提交 bf73d1d3 编写于 作者: S server

develop

上级 61a5a2dc
......@@ -3,7 +3,7 @@
namespace App\Web\Controller;
use Module\CmsWriter\Provider\CmsWriterHomePageProvider;
use Module\Cms\Provider\CmsHomePageProvider;
use Module\Vendor\Installer\Util\InstallerUtil;
use Module\Vendor\Provider\HomePage\HomePageProvider;
......@@ -12,6 +12,6 @@ class IndexController extends BaseController
public function index()
{
InstallerUtil::checkForInstallRedirect();
return HomePageProvider::call(__METHOD__, CmsWriterHomePageProvider::ACTION);
return HomePageProvider::call(__METHOD__, CmsHomePageProvider::ACTION);
}
}
......@@ -46,9 +46,6 @@ return [
'Cms' => [
'enable' => true,
],
'CmsWriter' => [
'enable' => true,
],
'SiteCounter' => [
'enable' => true,
],
......
<?php
namespace Module\CmsWriter\Admin\Controller;
use Illuminate\Routing\Controller;
use ModStart\Admin\Concern\HasAdminQuickCRUD;
use ModStart\Admin\Layout\AdminCRUDBuilder;
use ModStart\Form\Form;
use ModStart\Grid\GridFilter;
use ModStart\Support\Concern\HasFields;
use Module\CmsWriter\Util\ChannelUtil;
class ChannelController extends Controller
{
use HasAdminQuickCRUD;
protected function crud(AdminCRUDBuilder $builder)
{
$builder
->init('cms_channel')
->field(function ($builder) {
$builder->id('id', 'ID');
$builder->text('title', '名称')->required();
$builder->text('alias', '别名')->required()
->help('字母数字下划线,可以通过URL访问 channel/{alias}')
->ruleUnique('cms_channel')
->ruleRegex('/^[a-zA-Z0-9_]+$/');
$builder->image('cover', '封面');
$builder->textarea('description', '描述');
$builder->switch('pushEnable', '允许投稿')->width(100);
$builder->display('created_at', L('Created At'))->listable(false);
$builder->display('updated_at', L('Updated At'))->listable(false);
})
->gridFilter(function (GridFilter $filter) {
$filter->eq('id', L('ID'));
$filter->like('title', L('Title'));
})
->hookChanged(function (Form $form) {
ChannelUtil::clearCache();
})
->dialogSizeSmall()
->title('频道管理')
->asTree()
->treeMaxLevel(2);
}
}
<?php
namespace Module\CmsWriter\Admin\Controller;
use Illuminate\Routing\Controller;
use ModStart\Admin\Layout\AdminConfigBuilder;
use ModStart\Core\Type\TypeUtil;
use Module\CmsWriter\Type\PostEditorType;
class ConfigController extends Controller
{
public function setting(AdminConfigBuilder $builder)
{
$builder->pageTitle('文章投稿系统');
$builder->radio('CmsWriter_PostDefaultEditorType', '默认文章发布编辑器')
->optionType(PostEditorType::class)
->help('默认为' . TypeUtil::name(PostEditorType::class, PostEditorType::RICH_TEXT));
$builder->formClass('wide');
return $builder->perform();
}
}
<?php
namespace Module\CmsWriter\Admin\Controller;
use Illuminate\Routing\Controller;
use ModStart\Admin\Concern\HasAdminQuickCRUD;
use ModStart\Admin\Layout\AdminCRUDBuilder;
use ModStart\Field\AbstractField;
use ModStart\Field\AutoRenderedFieldValue;
use ModStart\Grid\GridFilter;
use ModStart\Repository\Filter\RepositoryFilter;
use ModStart\Support\Concern\HasFields;
use ModStart\Widget\TextLink;
use Module\Member\Util\MemberCmsUtil;
class PostController extends Controller
{
use HasAdminQuickCRUD;
protected function crud(AdminCRUDBuilder $builder)
{
$builder
->init('cms_post')
->field(function ($builder) {
$builder->id('id', 'ID');
$builder->display('memberUserId', '用户')->hookRendering(function (AbstractField $field, $item, $index) {
return MemberCmsUtil::showFromId($item->memberUserId);
});
$builder->display('title', '标题')->hookRendering(function (AbstractField $field, $item, $index) {
return AutoRenderedFieldValue::make(
TextLink::primary('<i class="iconfont icon-link"></i>', modstart_web_url('p/' . $item->alias), 'target="_blank"')
. ' ' . htmlspecialchars($item->title)
);
});
$builder->richHtml('contentHtml', '内容')->listable(false);
$builder->display('created_at', L('Created At'));
$builder->display('updated_at', L('Updated At'))->listable(false);
})
->repositoryFilter(function (RepositoryFilter $filter) {
$filter->where('memberUserId', '>', '0');
})
->gridFilter(function (GridFilter $filter) {
$filter->eq('id', L('ID'));
$filter->like('title', '标题');
})
->canEdit(false)->canAdd(false)
->title('用户文章');
}
}
<?php
namespace Module\CmsWriter\Admin\Controller;
use Illuminate\Routing\Controller;
use ModStart\Admin\Concern\HasAdminQuickCRUD;
use ModStart\Admin\Layout\AdminCRUDBuilder;
use ModStart\Core\Dao\ModelUtil;
use ModStart\Core\Util\HtmlUtil;
use ModStart\Core\Util\RandomUtil;
use ModStart\Field\AbstractField;
use ModStart\Field\AutoRenderedFieldValue;
use ModStart\Field\Tags;
use ModStart\Field\Type\FieldRenderMode;
use ModStart\Form\Form;
use ModStart\Form\Type\FormMode;
use ModStart\Grid\GridFilter;
use ModStart\Repository\Filter\RepositoryFilter;
use ModStart\Support\Concern\HasFields;
use ModStart\Widget\TextLink;
class PostSystemController extends Controller
{
use HasAdminQuickCRUD;
protected function crud(AdminCRUDBuilder $builder)
{
$builder
->init('cms_post')
->field(function ($builder) {
$builder->id('id', 'ID');
$builder->select('channelId', '频道')->optionModelTree('cms_channel');
$builder->text('title', '标题')->hookRendering(function (AbstractField $field, $item, $index) {
switch ($field->renderMode()) {
case FieldRenderMode::GRID:
return AutoRenderedFieldValue::make(
TextLink::primary('<i class="iconfont icon-link"></i>', modstart_web_url('p/' . $item->alias), 'target="_blank"')
. ' ' . htmlspecialchars($item->title)
);
}
});
$builder->richHtml('contentHtml', '内容');
$builder->switch('isRecommend', '推荐');
$builder->switch('isOriginal', '原创');
$builder->tags('tags', '标签')->serializeType(Tags::SERIALIZE_TYPE_COLON_SEPARATED);
$builder->display('created_at', L('Created At'));
$builder->display('updated_at', L('Updated At'))->listable(false);
})
->repositoryFilter(function (RepositoryFilter $filter) {
$filter->where(['memberUserId' => 0]);
})
->gridFilter(function (GridFilter $filter) {
$filter->eq('id', L('ID'));
$filter->like('title', '标题');
})
->hookSaved(function (Form $form) {
$item = $form->item();
switch ($form->mode()) {
case FormMode::ADD:
ModelUtil::update('cms_post', $item->id, [
'alias' => RandomUtil::lowerString(16),
'memberUserId' => 0,
'memberPostId' => 0,
'wordCount' => HtmlUtil::workCount($item->contentHtml),
'isDeleted' => false,
]);
break;
case FormMode::EDIT:
ModelUtil::update('cms_post', $item->id, [
'wordCount' => HtmlUtil::workCount($item->contentHtml),
]);
break;
}
})
->title('系统文章');
}
}
<?php
$router->match(['get', 'post'], 'cms/config/setting', 'ConfigController@setting');
$router->match(['get', 'post'], 'cms/post', 'PostController@index');
$router->match(['get', 'post'], 'cms/post/add', 'PostController@add');
$router->match(['get', 'post'], 'cms/post/edit', 'PostController@edit');
$router->match(['get', 'post'], 'cms/post/delete', 'PostController@delete');
$router->match(['get', 'post'], 'cms/post/show', 'PostController@show');
$router->match(['get', 'post'], 'cms/post_system', 'PostSystemController@index');
$router->match(['get', 'post'], 'cms/post_system/add', 'PostSystemController@add');
$router->match(['get', 'post'], 'cms/post_system/edit', 'PostSystemController@edit');
$router->match(['get', 'post'], 'cms/post_system/delete', 'PostSystemController@delete');
$router->match(['get', 'post'], 'cms/post_system/show', 'PostSystemController@show');
$router->match(['get', 'post'], 'cms/channel', 'ChannelController@index');
$router->match(['get', 'post'], 'cms/channel/add', 'ChannelController@add');
$router->match(['get', 'post'], 'cms/channel/edit', 'ChannelController@edit');
$router->match(['get', 'post'], 'cms/channel/delete', 'ChannelController@delete');
$router->match(['get', 'post'], 'cms/channel/show', 'ChannelController@show');
$router->match(['get', 'post'], 'cms/channel/sort', 'ChannelController@sort');
<?php
namespace Module\CmsWriter\Api\Controller;
use Illuminate\Routing\Controller;
use ModStart\Core\Exception\BizException;
use ModStart\Core\Input\InputPackage;
use ModStart\Core\Input\Response;
use ModStart\Core\Util\TreeUtil;
use Module\CmsWriter\Util\ChannelUtil;
use Module\CmsWriter\Util\PostUtil;
use Module\Member\Util\MemberUtil;
class ChannelController extends Controller
{
public function paginate()
{
$input = InputPackage::buildFromInput();
$searchInput = $input->getAsInput('search');
$channelAlias = $input->getTrimString('channelAlias');
$channel = null;
if ($channelAlias) {
$channel = ChannelUtil::getByAlias($channelAlias);
BizException::throwsIfEmpty('频道不存在', $channel);
}
$page = $input->getPage();
$pageSize = $input->getPageSize();
$option = [];
$option['order'] = ['id', 'desc'];
if ($channel) {
$nodes = ChannelUtil::all();
$channelIds = TreeUtil::nodesChildrenIds($nodes, $channel['id']);
$channelIds = array_merge([$channel['id']], $channelIds);
$option['order'] = ['id', 'desc'];
$option['whereIn'] = ['channelId', $channelIds];
}
$paginateData = PostUtil::paginatePosts($page, $pageSize, $option);
MemberUtil::mergeMemberUserBasics($paginateData['records']);
return Response::generateSuccessData([
'page' => $page,
'pageSize' => $pageSize,
'records' => $paginateData['records'],
'total' => $paginateData['total'],
'channel' => $channel,
]);
}
}
<?php
namespace Module\CmsWriter\Api\Controller;
use Illuminate\Routing\Controller;
use ModStart\Core\Input\Response;
use Module\CmsWriter\Util\ChannelUtil;
use Module\CmsWriter\Util\PostUtil;
class IndexController extends Controller
{
public function home()
{
$channelTree = ChannelUtil::tree();
$channelLatestPost = [];
foreach ($channelTree as $channel) {
$channelLatestPost[$channel['id']] = PostUtil::latestPostsByChannel($channel['id']);
}
$viewData = [];
$viewData['channelTree'] = $channelTree;
$viewData['channelLatestPost'] = $channelLatestPost;
$viewData['latestPosts'] = PostUtil::latestPosts(8);
return Response::generateSuccessData($viewData);
}
}
<?php
namespace Module\CmsWriter\Api\Controller;
use Illuminate\Routing\Controller;
use Illuminate\Support\Str;
use ModStart\Core\Input\InputPackage;
use ModStart\Core\Input\Response;
use ModStart\Core\Util\HtmlUtil;
use ModStart\Core\Util\TagUtil;
use Module\CmsWriter\Util\PostUtil;
use Module\Member\Auth\MemberUser;
use Module\Member\Support\MemberLoginCheck;
use Module\Member\Util\MemberUtil;
class PostController extends Controller implements MemberLoginCheck
{
public static $memberLoginCheckIgnores = ['get'];
public function get()
{
$input = InputPackage::buildFromInput();
$alias = $input->getTrimString('alias');
$post = PostUtil::getByAlias($alias);
if (empty($post)) {
return Response::generate(-1, '文章不存在');
}
if (!empty($post['memberUserId'])) {
$memberUser = MemberUtil::get($post['memberUserId']);
$post['_memberUser'] = array_merge(MemberUtil::convertOneToBasic($memberUser), [
'cmsWordCount' => $memberUser['cmsWordCount'],
]);
} else {
$post['_memberUser'] = null;
}
$post['_isLike'] = MemberUser::isLogin() && PostUtil::isLiked(MemberUser::id(), $post['id']);
$d = HtmlUtil::extractTextAndImages($post['contentHtml']);
$post['_summary'] = Str::limit($d['text'], 200);
$post['tags'] = TagUtil::string2Array($post['tags']);
PostUtil::update($post['id'], [
'viewCount' => intval($post['viewCount']) + 1
]);
return Response::generateSuccessData([
'post' => $post,
]);
}
}
<?php
namespace Module\CmsWriter\Api\Controller;
use Illuminate\Routing\Controller;
use ModStart\Core\Dao\ModelUtil;
use ModStart\Core\Exception\BizException;
use ModStart\Core\Input\InputPackage;
use ModStart\Core\Input\Response;
use ModStart\Core\Util\CRUDUtil;
use ModStart\Core\Util\HtmlUtil;
use ModStart\Core\Util\RandomUtil;
use ModStart\Core\Util\TagUtil;
use Module\CmsWriter\Type\PostEditorType;
use Module\CmsWriter\Util\PostUtil;
use Module\CmsWriter\Util\WriterUtil;
use Module\Member\Auth\MemberUser;
use Module\Member\Support\MemberLoginCheck;
use Module\Member\Util\MemberUtil;
use Module\Vendor\Html\HtmlConverter;
class WriterController extends Controller implements MemberLoginCheck
{
public function settingGet()
{
$memberUser = MemberUser::user();
$setting = [
'cmsEditorType' => $memberUser['cmsEditorType'],
];
if (empty($setting['cmsEditorType'])) {
$setting['cmsEditorType'] = modstart_config()->getInteger('CmsWriter_PostDefaultEditorType', PostEditorType::RICH_TEXT);
}
return Response::generateSuccessData($setting);
}
public function settingSave()
{
$input = InputPackage::buildFromInput();
$update = [];
$update['cmsEditorType'] = $input->getType('cmsEditorType', PostEditorType::class);
MemberUtil::update(MemberUser::id(), $update);
return Response::generateSuccess('保存成功');
}
public function categoryAll()
{
return Response::generateSuccessData(WriterUtil::categoryAll(MemberUser::id()));
}
public function postGet()
{
$id = InputPackage::buildFromInput()->getInteger('id');
$memberPost = ModelUtil::get('cms_member_post', [
'id' => $id, 'memberUserId' => MemberUser::id(),
]);
BizException::throwsIfEmpty('文章不存在', $memberPost);
$publishPostAlias = null;
if ($publishPost = ModelUtil::get('cms_post', ['memberPostId' => $memberPost['id'], 'isDeleted' => false])) {
$publishPostAlias = $publishPost['alias'];
}
return Response::generateSuccessData([
'memberPost' => [
'id' => $memberPost['id'],
'categoryId' => $memberPost['categoryId'],
'title' => $memberPost['title'],
'isPublished' => boolval($memberPost['isPublished']),
'isOriginal' => boolval($memberPost['isOriginal']),
'contentType' => intval($memberPost['contentType']),
'tags' => join(',', TagUtil::string2Array($memberPost['tags'])),
'content' => $memberPost['content'],
'_publishPostAlias' => $publishPostAlias
]
]);
}
public function postDelete()
{
$input = InputPackage::buildFromInput();
$id = $input->getInteger('id');
if (!$id) {
$id = CRUDUtil::id();
}
$memberPost = ModelUtil::get('cms_member_post', [
'id' => $id, 'memberUserId' => MemberUser::id()
]);
BizException::throwsIfEmpty('文章不存在', $memberPost);
ModelUtil::delete('cms_member_post', ['id' => $memberPost['id']]);
ModelUtil::delete('cms_member_post_history', ['memberPostId' => $memberPost['id']]);
PostUtil::deleteByMemberPostId($memberPost['id']);
return Response::generate(0, null);
}
public function postEdit()
{
$input = InputPackage::buildFromInput();
$id = $input->getInteger('id');
$memberPost = null;
if ($id) {
$memberPost = ModelUtil::get('cms_member_post', [
'id' => $id, 'memberUserId' => MemberUser::id()
]);
BizException::throwsIfEmpty('文章不存在', $memberPost);
}
$data = [];
$data['categoryId'] = $input->getInteger('categoryId');
$data['title'] = $input->getTrimString('title');
$data['contentType'] = $input->getType('contentType', PostEditorType::class, PostEditorType::RICH_TEXT);
$data['isOriginal'] = $input->getBoolean('isOriginal', false);
$data['tags'] = TagUtil::seperated2String($input->getTrimString('tags'));
switch ($data['contentType']) {
case PostEditorType::RICH_TEXT:
$data['content'] = $input->getRichContent('content');
$data['content'] = HtmlUtil::filter2($data['content']);
break;
case PostEditorType::MARKDOWN:
$data['content'] = $input->getTrimString('content');
break;
default:
return Response::generateError('错误的文章类型');
}
if (empty($data['title'])) {
return Response::generate(-1, '标题不能为空');
}
if (empty($data['content'])) {
return Response::generate(-1, '内容不能为空');
}
if ($memberPost) {
if ($memberPost['title'] != $data['title'] || $memberPost['content'] != $data['content']) {
ModelUtil::insert('cms_member_post_history', [
'memberPostId' => $memberPost['id'],
'title' => $memberPost['title'],
'content' => $memberPost['content'],
]);
$limit = 50;
$oldHistory = ModelUtil::model('cms_member_post_history')
->where(['memberPostId' => $memberPost['id'],])
->select('id')
->orderBy('id', 'desc')
->limit($limit)
->get()
->toArray();
$minId = $oldHistory[count($oldHistory) - 1]['id'];
ModelUtil::model('cms_member_post_history')
->where(['memberPostId' => $memberPost['id'],])
->where('id', '<', $minId)
->delete();
}
ModelUtil::update('cms_member_post', ['id' => $id], $data);
} else {
$data['memberUserId'] = MemberUser::id();
$data['isPublished'] = false;
$memberPost = ModelUtil::insert('cms_member_post', $data);
}
$memberPost = ModelUtil::get('cms_member_post', ['id' => $memberPost['id']]);
$publishPostAlias = null;
if ($publishPost = ModelUtil::get('cms_post', ['memberPostId' => $memberPost['id'], 'isDeleted' => false])) {
$publishPostAlias = $publishPost['alias'];
}
return Response::generate(0, null, [
'memberPost' => [
'id' => $memberPost['id'],
'categoryId' => $memberPost['categoryId'],
'title' => $memberPost['title'],
'isPublished' => boolval($memberPost['isPublished']),
'contentType' => intval($memberPost['contentType']),
'content' => $memberPost['content'],
'tags' => $memberPost['tags'],
'_publishPostAlias' => $publishPostAlias
]
]);
}
private function updateMemberUserPostStat()
{
$postCount = ModelUtil::count('cms_post', ['memberUserId' => MemberUser::id(), 'isDeleted' => false]);
$wordCount = ModelUtil::sum('cms_post', 'wordCount', ['memberUserId' => MemberUser::id(), 'isDeleted' => false]);
ModelUtil::update('member_user', ['id' => MemberUser::id()], [
'cmsPostCount' => $postCount,
'cmsWordCount' => $wordCount,
]);
}
public function postPublish()
{
$input = InputPackage::buildFromInput();
$id = $input->getInteger('id');
$memberPost = ModelUtil::get('cms_member_post', ['id' => $id, 'memberUserId' => MemberUser::id()]);
BizException::throwsIfEmpty('文章不存在', $memberPost);
$post = ModelUtil::get('cms_post', ['memberPostId' => $memberPost['id']]);
if (empty($post)) {
$post['id'] = 0;
$post['memberUserId'] = MemberUser::id();
$post['memberPostId'] = $memberPost['id'];
$post['alias'] = RandomUtil::lowerString(16);
}
$post['isDeleted'] = false;
$post['isOriginal'] = $memberPost['isOriginal'];
$post['tags'] = $memberPost['tags'];
$post['title'] = $memberPost['title'];
$post['contentHtml'] = HtmlConverter::convertToHtml(
$memberPost['contentType'],
$memberPost['content']
);
$post['wordCount'] = HtmlUtil::workCount($memberPost['content']);
if ($post['id']) {
ModelUtil::update('cms_post', ['id' => $post['id']], $post);
$post = ModelUtil::get('cms_post', $post['id']);
} else {
$post = ModelUtil::insert('cms_post', $post);
}
ModelUtil::update('cms_member_post', ['id' => $memberPost['id']], ['isPublished' => true]);
$this->updateMemberUserPostStat();
return Response::generate(0, '发布成功', [
'alias' => $post['alias'],
], CRUDUtil::jsGridRefresh());
}
public function postPublishCancel()
{
$input = InputPackage::buildFromInput();
$id = $input->getInteger('id');
$memberPost = ModelUtil::get('cms_member_post', ['id' => $id, 'memberUserId' => MemberUser::id()]);
BizException::throwsIfEmpty('文章不存在', $memberPost);
$post = ModelUtil::get('cms_post', ['memberPostId' => $memberPost['id']]);
if (empty($post)) {
return Response::generate(-1, '发布文章不存在');
}
ModelUtil::update('cms_post', ['id' => $post['id']], ['isDeleted' => true]);
ModelUtil::update('cms_member_post', ['id' => $memberPost['id']], ['isPublished' => false]);
ModelUtil::delete('cms_post_like', ['postId' => $post['id']]);
$this->updateMemberUserPostStat();
return Response::generate(0, '取消发布成功', [], CRUDUtil::jsGridRefresh());
}
public function postHistory()
{
$input = InputPackage::buildFromInput();
$id = $input->getInteger('id');
$memberPost = ModelUtil::get('cms_member_post', ['id' => $id, 'memberUserId' => MemberUser::id()]);
BizException::throwsIfEmpty('文章不存在', $memberPost);
$histories = [];
$records = ModelUtil::all('cms_member_post_history', ['memberPostId' => $memberPost['id']], ['id', 'title', 'created_at', 'content'], ['id', 'desc']);
foreach ($records as $record) {
$histories[] = [
'id' => $record['id'],
'title' => $record['title'],
'time' => $record['created_at'],
'content' => $record['content'],
];
}
return Response::generateSuccessData([
'histories' => $histories,
]);
}
public function postPaginate()
{
$input = InputPackage::buildFromInput();
$page = $input->getPage();
$pageSize = $input->getPageSize();
$option = [];
$option['where'] = [];
$option['where']['memberUserId'] = MemberUser::id();
$option['order'] = [];
$option['order'][] = ['updated_at', 'desc'];
$categoryId = $input->getInteger('categoryId');
if ($categoryId) {
$option['where']['categoryId'] = $categoryId;
}
$paginateData = ModelUtil::paginate('cms_member_post', $page, $pageSize, $option);
$records = [];
foreach ($paginateData['records'] as $record) {
$records[] = [
'id' => $record['id'],
'title' => $record['title'],
'time' => $record['updated_at'],
'summary' => HtmlUtil::text($record['content'], 100),
'isPublished' => ($record['isPublished'] ? true : false),
];
}
return Response::generate(0, null, [
'page' => $page,
'pageSize' => $pageSize,
'records' => $records,
]);
}
}
<?php
$router->group([
'middleware' => [
\Module\Member\Middleware\ApiAuthMiddleware::class,
],
], function () use ($router) {
$router->match(['get', 'post'], 'writer/setting/get', 'WriterController@settingGet');
$router->match(['get', 'post'], 'writer/setting/save', 'WriterController@settingSave');
$router->match(['get', 'post'], 'writer/category/all', 'WriterController@categoryAll');
$router->match(['get', 'post'], 'writer/post/paginate', 'WriterController@postPaginate');
$router->match(['get', 'post'], 'writer/post/get', 'WriterController@postGet');
$router->match(['get', 'post'], 'writer/post/edit', 'WriterController@postEdit');
$router->match(['get', 'post'], 'writer/post/delete', 'WriterController@postDelete');
$router->match(['get', 'post'], 'writer/post/publish', 'WriterController@postPublish');
$router->match(['get', 'post'], 'writer/post/publish_cancel', 'WriterController@postPublishCancel');
$router->match(['get', 'post'], 'post/get', 'PostController@get');
$router->match(['get', 'post'], 'post/like', 'PostController@like');
$router->match(['get', 'post'], 'post/unlike', 'PostController@unlike');
});
[data-post-like-item] [data-action],[data-topic-follow-item] [data-action]{display:none}[data-post-like-item][data-status=is_follow] [data-action=unfollow],[data-post-like-item][data-status=is_follow] [data-action=unlike],[data-post-like-item][data-status=is_like] [data-action=unfollow],[data-post-like-item][data-status=is_like] [data-action=unlike],[data-topic-follow-item][data-status=is_follow] [data-action=unfollow],[data-topic-follow-item][data-status=is_follow] [data-action=unlike],[data-topic-follow-item][data-status=is_like] [data-action=unfollow],[data-topic-follow-item][data-status=is_like] [data-action=unlike]{display:inline-block}[data-post-like-item][data-status=not_follow] [data-action=follow],[data-post-like-item][data-status=not_follow] [data-action=like],[data-post-like-item][data-status=not_like] [data-action=follow],[data-post-like-item][data-status=not_like] [data-action=like],[data-topic-follow-item][data-status=not_follow] [data-action=follow],[data-topic-follow-item][data-status=not_follow] [data-action=like],[data-topic-follow-item][data-status=not_like] [data-action=follow],[data-topic-follow-item][data-status=not_like] [data-action=like]{display:inline-block}
\ No newline at end of file
$(function(){$(document).on("click","[data-topic-follow-item] [data-action]",function(){const t=$(this),a=t.closest("[data-topic-follow-item]"),o=t.attr("data-action");var i=a.attr("data-alias");return window.api.base.postSuccess(window.__msRoot+"api/topic/"+o,{alias:i},function(t){switch(o){case"follow":a.attr("data-status","is_follow");break;case"unfollow":a.attr("data-status","not_follow")}}),!1}),$(document).on("click","[data-post-like-item] [data-action]",function(){const t=$(this),a=t.closest("[data-post-like-item]"),o=t.attr("data-action");var i=a.attr("data-alias");return window.api.base.postSuccess(window.__msRoot+"api/post/"+o,{alias:i},function(t){switch(o){case"like":a.attr("data-status","is_like");break;case"unlike":a.attr("data-status","not_like")}a.find(".cnt").html(t.data.count)}),!1})});
\ No newline at end of file
<?php
namespace Module\CmsWriter\Core;
use Illuminate\Events\Dispatcher;
use Illuminate\Support\ServiceProvider;
use ModStart\Admin\Config\AdminMenu;
use ModStart\Admin\Widget\DashboardItemA;
use ModStart\Core\Dao\ModelUtil;
use ModStart\Core\Util\TreeUtil;
use ModStart\Layout\Row;
use Module\CmsWriter\Provider\CmsWriterHomePageProvider;
use Module\Member\Config\MemberMenu;
use Module\Vendor\Admin\Config\AdminWidgetDashboard;
use Module\Vendor\Admin\Config\AdminWidgetLink;
use Module\Vendor\Provider\HomePage\HomePageProvider;
class ModuleServiceProvider extends ServiceProvider
{
public function boot(Dispatcher $events)
{
MemberMenu::register(function () {
return [
[
'icon' => 'list-alt',
'title' => '文章管理',
'sort' => 100,
'children' => [
[
'title' => '文章分类',
'url' => modstart_web_url('writer/category'),
],
[
'title' => '文章管理',
'url' => modstart_web_url('writer/post'),
],
[
'title' => '写作设置',
'url' => modstart_web_url('writer/setting'),
],
]
],
];
});
AdminWidgetLink::register(function () {
$menu = [];
$menu[] = ['首页', modstart_web_url('cms')];
$tree = TreeUtil::modelToTree('cms_channel', ['title' => 'title', 'alias' => 'alias']);
$categories = TreeUtil::treeToListWithIndent($tree, 'id', 'title', 0, ['alias']);
$menu = array_merge($menu, array_map(function ($record) {
return [
'频道:' . $record['title'],
modstart_web_url("channel/$record[alias]"),
];
}, $categories));
return [
AdminWidgetLink::build('文章投稿', $menu)
];
});
AdminMenu::register(function () {
return [
[
'title' => '文章内容',
'icon' => 'category',
'sort' => 150,
'children' => [
[
'title' => '频道管理',
'url' => '\Module\CmsWriter\Admin\Controller\ChannelController@index',
],
[
'title' => '系统文章',
'url' => '\Module\CmsWriter\Admin\Controller\PostSystemController@index',
],
[
'title' => '用户文章',
'url' => '\Module\CmsWriter\Admin\Controller\PostController@index',
],
]
],
[
'title' => '功能设置',
'icon' => 'tools',
'sort' => 300,
'children' => [
[
'title' => '文章投稿设置',
'url' => '\Module\CmsWriter\Admin\Controller\ConfigController@setting',
],
]
]
];
});
AdminWidgetDashboard::registerIcon(function (Row $row) {
$row->column(3, DashboardItemA::makeIconNumberTitle(
'iconfont icon-list-alt', ModelUtil::count('cms_channel'), '频道数',
modstart_admin_url('cms/channel')
));
$row->column(3, DashboardItemA::makeIconNumberTitle(
'iconfont icon-file',
ModelUtil::model('cms_post')->where('memberUserId', '>', 0)->count(),
'用户文章数',
modstart_admin_url('cms/post')
));
$row->column(3, DashboardItemA::makeIconNumberTitle(
'iconfont icon-file',
ModelUtil::model('cms_post')->where('memberUserId', 0)->count(),
'系统文章数',
modstart_admin_url('cms/post_system')
));
});
HomePageProvider::register(CmsWriterHomePageProvider::class);
}
public function register()
{
}
}
## 模块
「文章投稿系统」是一个通用多级分类文章管理系统。
## 功能特性
- 文章栏目管理
- 文章管理
- 付费阅读(部分)
- 文章评论
- 发表文章
- 用户投稿管理
通用内容管理系统
---
- 提供自适应的内容管理系统
通用内容管理系统
---
- 修复发布文章页面JS异常
- 修复文章登录状态页面异常
通用内容管理系统
---
- 新增:频道页面显示频道背景
<?php
namespace Module\CmsWriter\Event;
class PostLikedEvent
{
public $postId;
public $memberUserId;
public function __construct($postId, $memberUserId)
{
$this->postId = $postId;
$this->memberUserId = $memberUserId;
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class ChangeCmsMemberUserFields extends Migration
{
public function up()
{
Schema::table('member_user', function (Blueprint $table) {
$table->integer('cmsPostCount')->nullable()->comment('文章数');
$table->integer('cmsWordCount')->nullable()->comment('文字数');
$table->tinyInteger('cmsEditorType')->nullable()->comment('编辑器类型');
});
}
public function down()
{
}
}
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCmsChannel extends Migration
{
public function up()
{
Schema::create('cms_channel', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('pid')->nullable()->comment('用户');
$table->integer('sort')->nullable()->comment('用户');
$table->string('alias', 16)->nullable()->comment('Alias');
$table->string('cover', 200)->nullable()->comment('封面');
$table->string('title', 50)->nullable()->comment('标题');
$table->string('description', 400)->nullable()->comment('公告');
$table->tinyInteger('pushEnable')->nullable()->comment('允许投稿');
$table->tinyInteger('pushVerify')->nullable()->comment('投稿是否需要审核');
$table->integer('postCount')->nullable()->comment('文章数');
$table->unique(['alias']);
});
Schema::create('cms_channel_post', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('channelId')->nullable()->comment('专题');
$table->integer('postId')->nullable()->comment('文章');
$table->index(['channelId']);
$table->index(['postId']);
});
Schema::create('cms_channel_post_apply', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('channelId')->nullable()->comment('专题');
$table->integer('postId')->nullable()->comment('文章');
$table->index(['channelId']);
$table->index(['postId']);
});
}
public function down()
{
}
}
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCmsMemberComment extends Migration
{
public function up()
{
Schema::create('cms_member_comment', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->bigInteger('postId')->nullable()->comment('');
$table->integer('memberUserId')->nullable()->comment('');
$table->integer('rootCommentId')->nullable()->comment('所属评论');
$table->integer('likeCount')->nullable()->comment('喜欢数');
$table->string('content', 1000)->nullable()->comment('内容');
$table->index(['memberUserId']);
$table->index(['postId']);
});
Schema::create('cms_member_comment_like', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('commentId')->nullable()->comment('评论');
$table->integer('memberUserId')->nullable()->comment('用户');
$table->unique(['commentId', 'memberUserId']);
});
}
public function down()
{
}
}
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCmsMemberPost extends Migration
{
public function up()
{
Schema::create('cms_member_post_category', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('memberUserId')->nullable()->comment('用户ID');
$table->string('title', 100)->nullable()->comment('文章分类');
$table->index(['memberUserId']);
});
Schema::create('cms_member_post', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('memberUserId')->nullable()->comment('用户ID');
$table->integer('categoryId')->nullable()->comment('分类');
$table->string('title', 200)->nullable()->comment('标题');
$table->tinyInteger('isPublished')->nullable()->comment('已发布');
$table->tinyInteger('contentType')->nullable()->comment('类型');
$table->text('content')->nullable()->comment('内容');
$table->tinyInteger('isOriginal')->nullable()->comment('原创');
$table->string('tags', 200)->nullable()->comment('标签');
$table->index(['memberUserId']);
$table->index(['categoryId']);
});
Schema::create('cms_member_post_history', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('memberPostId')->nullable()->comment('文章');
$table->string('title', 200)->nullable()->comment('标题');
$table->text('content')->nullable()->comment('内容');
});
}
public function down()
{
}
}
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCmsPost extends Migration
{
public function up()
{
Schema::create('cms_post', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('alias', 16)->nullable()->comment('Alias');
$table->integer('channelId')->nullable()->comment('用户');
$table->integer('memberUserId')->nullable()->comment('用户');
$table->integer('memberPostId')->nullable()->comment('用户文章');
$table->integer('wordCount')->nullable()->comment('文字数');
$table->integer('viewCount')->nullable()->comment('阅读数');
$table->integer('commentCount')->nullable()->comment('评论数');
$table->integer('likeCount')->nullable()->comment('喜欢数');
$table->string('title', 200)->nullable()->comment('标题');
$table->text('contentHtml')->nullable()->comment('内容');
$table->tinyInteger('isRecommend')->nullable()->comment('推荐');
$table->tinyInteger('isDeleted')->nullable()->comment('已删除');
$table->tinyInteger('isOriginal')->nullable()->comment('原创');
$table->string('tags', 200)->nullable()->comment('标签');
$table->unique(['alias']);
$table->index(['channelId']);
$table->index(['memberUserId']);
$table->index(['memberPostId']);
});
Schema::create('cms_post_like', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('postId')->nullable()->comment('文章');
$table->integer('memberUserId')->nullable()->comment('用户');
$table->unique(['postId', 'memberUserId']);
$table->index(['memberUserId']);
});
}
public function down()
{
}
}
<?php
namespace Module\CmsWriter\Provider;
use Module\Vendor\Provider\HomePage\AbstractHomePageProvider;
class CmsWriterHomePageProvider extends AbstractHomePageProvider
{
const ACTION = '\\Module\\CmsWriter\\Web\\Controller\\IndexController@index';
public function title()
{
return '文章投稿系统';
}
public function action()
{
return self::ACTION;
}
}
<?php
namespace Module\CmsWriter\Type;
use ModStart\Core\Type\BaseType;
use Module\Vendor\Html\HtmlType;
class PostEditorType implements BaseType
{
const RICH_TEXT = HtmlType::RICH_TEXT;
const MARKDOWN = HtmlType::MARKDOWN;
public static function getList()
{
return [
self::RICH_TEXT => '富文本',
self::MARKDOWN => 'Markdown',
];
}
}
<?php
namespace Module\CmsWriter\Type;
use ModStart\Core\Type\BaseType;
class PostStatus implements BaseType
{
const WAIT_VERIFY = 1;
const VERIFY_PASS = 2;
const VERIFY_REJECT = 3;
public static function getList()
{
return [
self::WAIT_VERIFY => '等待审核',
self::VERIFY_PASS => '审核成功',
self::VERIFY_REJECT => '审核拒绝',
];
}
}
<?php
namespace Module\CmsWriter\Util;
use Illuminate\Support\Facades\Cache;
use ModStart\Core\Dao\ModelUtil;
use ModStart\Core\Util\TreeUtil;
class ChannelUtil
{
public static function clearCache()
{
Cache::forget('CmsChannels');
Cache::forget('CmsChannelTree');
}
public static function tree()
{
return Cache::remember('CmsChannelTree', 3600, function () {
return TreeUtil::modelToTree('cms_channel', [
'alias' => 'alias',
'title' => 'title',
'cover' => 'cover',
'description' => 'description',
]);
});
}
public static function getByAlias($alias)
{
foreach (self::all() as $item) {
if ($alias == $item['alias']) {
return $item;
}
}
return null;
}
public static function mapById()
{
return array_build(self::all(), function ($k, $v) {
return [$v['id'], $v];
});
}
public static function all()
{
return Cache::remember('CmsChannels', 3600, function () {
return ModelUtil::all('cms_channel');
});
}
}
<?php
namespace Module\CmsWriter\Util;
use Illuminate\Support\Str;
use ModStart\Core\Dao\ModelUtil;
use ModStart\Core\Util\HtmlUtil;
use ModStart\Core\Util\TreeUtil;
class PostUtil
{
public static function latestPostsByChannel($channelId, $limit = 3)
{
$nodes = ChannelUtil::all();
$channelIds = TreeUtil::nodesChildrenIds($nodes, $channelId);
$channelIds = array_merge([$channelId], $channelIds);
$option['order'] = ['id', 'desc'];
$option['whereIn'] = ['channelId', $channelIds];
$paginateData = self::paginatePosts(1, $limit, $option);
return $paginateData['records'];
}
public static function latestPosts($limit)
{
$option['order'] = ['id', 'desc'];
$paginateData = self::paginatePosts(1, $limit, $option);
return $paginateData['records'];
}
public static function paginatePosts($page, $pageSize, $option = [])
{
$option['where']['isDeleted'] = false;
$paginateData = ModelUtil::paginate('cms_post', $page, $pageSize, $option);
$channelMap = ChannelUtil::mapById();
foreach ($paginateData['records'] as &$record) {
$d = HtmlUtil::extractTextAndImages($record['contentHtml']);
$record['_summary'] = Str::limit($d['text'], 200);
$record['_cover'] = (empty($d['images'][0]) ? null : $d['images'][0]);
$record['_channel'] = isset($channelMap[$record['channelId']]) ? $channelMap[$record['channelId']] : null;
}
return $paginateData;
}
public static function getByAlias($alias)
{
return ModelUtil::get('cms_post', ['alias' => $alias, 'isDeleted' => false,]);
}
public static function get($id)
{
return ModelUtil::get('cms_post', ['id' => $id, 'isDeleted' => false,]);
}
public static function update($postId, $data)
{
return ModelUtil::update('cms_post', ['id' => $postId], $data);
}
public static function paginateMemberUserPosts($memberUserId, $page, $pageSize, $option = [])
{
$option['where']['memberUserId'] = $memberUserId;
$option['where']['isDeleted'] = false;
$paginateData = ModelUtil::paginate('cms_post', $page, $pageSize, $option);
foreach ($paginateData['records'] as &$record) {
$d = HtmlUtil::extractTextAndImages($record['contentHtml']);
$record['_summary'] = Str::limit($d['text'], 200);
$record['_cover'] = (empty($d['images'][0]) ? null : $d['images'][0]);
}
return $paginateData;
}
public static function isLiked($memberUserId, $postId)
{
$data = [
'postId' => $postId,
'memberUserId' => $memberUserId,
];
if (ModelUtil::exists('cms_post_like', $data)) {
return true;
}
return false;
}
public static function updatePostCommentStat($postId)
{
$commentCount = ModelUtil::count('cms_post_comment', ['postId' => $postId]);
ModelUtil::update('cms_post', ['id' => $postId], ['commentCount' => $commentCount]);
}
public static function delete($id)
{
ModelUtil::delete('cms_post', ['id' => $id]);
ModelUtil::delete('cms_post_like', ['postId' => $id]);
}
public static function deleteByMemberPostId($memberPostId)
{
$m = ModelUtil::get('cms_post', ['memberPostId' => $memberPostId]);
if (!empty($m)) {
self::delete($m['id']);
}
}
}
<?php
namespace Module\CmsWriter\Util;
use ModStart\Core\Dao\ModelUtil;
class WriterUtil
{
public static function categoryAll($memberUserId)
{
return ModelUtil::all('cms_member_post_category',
['memberUserId' => $memberUserId],
['id', 'title'],
['id', 'desc']
);
}
}
<p>
<a href="{{$__msRoot}}note_member/{{$comment['_memberUser']['id']}}" target="_blank">{{$comment['_memberUser']['username']}}</a>
评论了你的文章
<a href="{{$__msRoot}}n/{{$note['alias']}}" target="_blank">{{$note['title']}}</a>
</p>
<div class="ub-html">
{!! $comment['content'] !!}
</div>
<p>
<a href="{{$__msRoot}}note_member/{{$reply['_memberUser']['id']}}" target="_blank">{{$reply['_memberUser']['username']}}</a>
在文章
<a href="{{$__msRoot}}n/{{$note['alias']}}" target="_blank">{{$note['title']}}</a>
回复了你的评论
</p>
<div class="ub-html">
{!! $reply['content'] !!}
</div>
<p>
<a href="{{$__msRoot}}note_member/{{$reward['_rewardMemberUser']['id']}}" target="_blank">{{$reward['_rewardMemberUser']['username']}}</a>
打赏了你的文章
<a href="{{$__msRoot}}n/{{$note['alias']}}" target="_blank">{{$note['title']}}</a>
金额 ¥{{$reward['money']}}
</p>
<p>
<a href="{{$__msRoot}}note_member/{{$memberUser['id']}}" target="_blank">{{$memberUser['username']}}</a>
喜欢了你的文章
<a href="{{$__msRoot}}n/{{$note['alias']}}" target="_blank">{{$note['title']}}</a>
</p>
<p>
<a href="{{$__msRoot}}note_member/{{$note['_memberUser']['id']}}" target="_blank">{{$note['_memberUser']['username']}}</a>
在专题
<a href="{{$__msRoot}}t/{{$topic['alias']}}" target="_blank">{{$topic['title']}}</a>
投稿了新的文章
<a href="{{$__msRoot}}n/{{$note['alias']}}" target="_blank">{{$note['title']}}</a>
<a href="{{$__msRoot}}t/{{$topic['alias']}}" target="_blank">点击进入审核</a>
</p>
<p>
<a href="{{$__msRoot}}note_member/{{$note['_memberUser']['id']}}" target="_blank">{{$note['_memberUser']['username']}}</a>
在专题
<a href="{{$__msRoot}}t/{{$topic['alias']}}" target="_blank">{{$topic['title']}}</a>
投稿了新的文章
<a href="{{$__msRoot}}n/{{$note['alias']}}" target="_blank">{{$note['title']}}</a>
并自动审核通过
</p>
<p>
您在在专题
<a href="{{$__msRoot}}t/{{$topic['alias']}}" target="_blank">{{$topic['title']}}</a>
投稿了新的文章
<a href="{{$__msRoot}}n/{{$note['alias']}}" target="_blank">{{$note['title']}}</a>
已经审核通过
</p>
<p>
您在在专题
<a href="{{$__msRoot}}t/{{$topic['alias']}}" target="_blank">{{$topic['title']}}</a>
投稿了新的文章
<a href="{{$__msRoot}}n/{{$note['alias']}}" target="_blank">{{$note['title']}}</a>
审核未通过,拒绝理由:{{$reason}}
</p>
@extends($_viewFrame)
@section('pageTitle'){{modstart_config('siteName').' - '.modstart_config('siteSlogan')}}@endsection
{!! \ModStart\ModStart::js('asset/common/timeago.js') !!}
@section('bodyContent')
<div class="ub-cover" style="background-color:#EEE;background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($channel['cover'])}})">
<div class="ub-nav-header">
{{$channel['title']}}
</div>
<div class="ub-nav-header-sub">
{{$channel['description']}}
</div>
</div>
<div class="ub-container margin-top">
<div class="row">
<div class="col-md-12">
<div class="ub-panel margin-top">
<div class="head">
<div class="title">文章列表</div>
</div>
<div class="body ub-list-items">
@foreach($records as $record)
<div class="item-k">
<a class="image" href="{{modstart_web_url('p/'.$record['alias'])}}">
<div class="cover ub-cover-4-3 tw-bg-gray-200" style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($record['_cover'])}})"></div>
</a>
<a class="title" href="{{modstart_web_url('p/'.$record['alias'])}}">{{$record['title']}}</a>
<div class="summary">
{{$record['_summary']}}
</div>
<div class="info">
<div class="left">
频道:
@if($record['_channel'])
<a href="{{modstart_web_url('channel/'.$record['_channel']['alias'])}}">{{$record['_channel']['title'] or ''}}</a>
@else
-
@endif
</div>
<div class="right">
<i class="iconfont icon-time"></i>
<time datetime="{{$record['created_at']}}"></time>
&nbsp;
<i class="iconfont icon-eye"></i>
{{$record['viewCount'] or 0}}
</div>
</div>
</div>
@endforeach
<div class="ub-page">
{!! $pageHtml !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends($_viewFrame)
@section('pageTitle'){{modstart_config('siteName').' - '.modstart_config('siteSlogan')}}@endsection
{!! \ModStart\ModStart::js('asset/common/timeago.js') !!}
@section('bodyContent')
<div class="ub-container margin-top">
<div class="row">
<div class="col-md-8">
<div class="tw-bg-white tw-rounded-lg">
<div id="banner">
@include('module::Banner.View.pc.public.banner',['position'=>'home','bannerRatio'=>'5-2'])
</div>
</div>
@foreach($channelTree as $channelGroup)
@if(!empty($channelLatestPost[$channelGroup['id']]))
<div class="ub-panel margin-top">
<div class="head">
<div class="more">
<a href="{{modstart_web_url('channel/'.$channelGroup['alias'])}}">更多</a>
</div>
<div class="title">{{$channelGroup['title']}}</div>
</div>
<div class="body ub-list-items">
@foreach($channelLatestPost[$channelGroup['id']] as $record)
<div class="item-k">
<a class="image" href="{{modstart_web_url('p/'.$record['alias'])}}">
<div class="cover ub-cover-4-3 tw-bg-gray-200" style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($record['_cover'])}})"></div>
</a>
<a class="title" href="{{modstart_web_url('p/'.$record['alias'])}}">{{$record['title']}}</a>
<div class="summary">
{{$record['_summary']}}
</div>
<div class="info">
<div class="left">
频道:
@if($record['_channel'])
<a href="{{modstart_web_url('channel/'.$record['_channel']['alias'])}}">{{$record['_channel']['title'] or ''}}</a>
@else
-
@endif
</div>
<div class="right">
<i class="iconfont icon-time"></i>
<time datetime="{{$record['created_at']}}"></time>
&nbsp;
<i class="iconfont icon-eye"></i>
{{$record['viewCount'] or 0}}
</div>
</div>
</div>
@endforeach
</div>
</div>
@endif
@endforeach
</div>
<div class="col-md-4">
<div class="ub-panel" id="postLatest">
<div class="head">
<div class="title">最近更新</div>
</div>
<div class="body ub-list-items" style="overflow:auto;">
@foreach($latestPosts as $record)
<a class="item-c" href="{{modstart_web_url('p/'.$record['alias'])}}">{{$record['title']}}</a>
@endforeach
</div>
<script>
$(function () {
$('#postLatest .body').css('height',($('#banner').height()-30)+'px');
});
</script>
</div>
{{-- <div>--}}
{{-- <img style="width:100%;" src="/placeholder/300x200" alt="">--}}
{{-- </div>--}}
<div class="ub-panel margin-top">
<div class="head">
<div class="title">频道</div>
</div>
<div class="body">
<div class="body">
<div class="ub-nav-category">
@foreach($channelTree as $channelGroup)
<a class="group-title" href="{{modstart_web_url('channel/'.$channelGroup['alias'])}}">{{$channelGroup['title']}}</a>
<div class="group-list">
@if(!empty($channelGroup['_child']))
@foreach($channelGroup['_child'] as $channel)
<a class="item" href="{{modstart_web_url('channel/'.$channel['alias'])}}">{{$channel['title']}}</a>
@endforeach
@endif
</div>
@endforeach
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="ub-container">
@include('module::Partner.View.pc.public.partner',['position'=>'home'])
</div>
@endsection
@extends($_viewFrame)
@section('pageTitleMain'){{$post['title']}}@endsection
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/cms.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/cms.js') !!}
@section('bodyContent')
<div class="ub-container" style="max-width:35rem;background:#FFF;">
<div class="ub-article margin-top white tw-rounded">
{{-- @if($post['status']!==\Module\CmsWriter\Type\NoteStatus::VERIFY_PASS)--}}
{{-- <div class="ub-alert ub-alert-danger ub-text-center">当前文章正在审核</div>--}}
{{-- @endif--}}
<h1>{{$post['title']}}</h1>
<div class="attr">
<div>
@if($post['isOriginal'])
<span class="ub-tag primary">原创</span>
@endif
@if(!empty($post['tags']))
@foreach($post['tags'] as $tag)
<span class="ub-tag">{{$tag}}</span>
@endforeach
@endif
更新{{$post['created_at']}}
</div>
</div>
<div class="content ub-html">
{!! $post['contentHtml'] !!}
</div>
</div>
@if(0)
<div class="ub-text-right tw-py-4">
<a class="tw-text-gray-400" href="javascript:;"
data-dialog-request="{{\Module\ContentReport\Util\ContentReportUtil::submitPageUrl('post',$post['id'],$post['title'])}}">
举报
</a>
<span class="tw-text-gray-400 tw-ml-2">
&copy; 著作权归作者所有
</span>
</div>
@endif
<div class="margin-top ub-padding">
<div class="tw-text-center">
@include('module::Vendor.View.public.shareButtons')
</div>
@if(0)
<div>
<div class="row">
<div class="col-md-6">
@if(0)
<div class="tw-inline-block" data-post-like-item data-alias="{{$post['alias']}}" data-status="{{$post['_isLike']?'is_like':'not_like'}}">
<a class="btn btn-primary btn-round" data-action="like" href="javascript:;">
<i class="iconfont icon-heart-o"></i>
喜欢
|
<span class="cnt">{{$post['likeCount'] or 0}}</span>
</a>
<a class="btn btn-round" data-action="unlike" href="javascript:;">
<i class="iconfont icon-heart-o"></i>
已喜欢
|
<span class="cnt">{{$post['likeCount'] or 0}}</span>
</a>
</div>
@endif
</div>
<div class="col-md-6 ub-text-right">
</div>
</div>
</div>
@endif
@if(!empty($post['_memberUser']))
<div class="margin-top-lg tw-bg-gray-100 tw-p-4 tw-rounded tw-mb-2">
<div class="tw-flex tw-justify-between tw-items-center">
<div class="tw-flex">
<div class="tw-mr-4">
<div class="ub-cover-1-1 tw-shadow tw-w-10 tw-h-10 tw-rounded-full"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($post['_memberUser']['avatar'])}});">
</div>
</div>
<div>
<div class="tw-font-bold tw-text-gray-700">{{$post['_memberUser']['username'] or '[无用户]'}}</div>
<div class="tw-text-gray-400 tw-text-sm">
写了 {{$post['_memberUser']['cmsWordCount'] or 0}}
</div>
</div>
</div>
</div>
<div class="tw-border-0 tw-border-solid tw-border-t tw-border-gray-200 tw-mt-2 tw-pt-2 tw-text-gray-500">
{{$post['_memberUser']['signature'] or 'Ta没有介绍内容'}}
</div>
</div>
@endif
</div>
</div>
@if(0)
<div class="ub-container margin-top" style="max-width:35rem;">
<div>
@include('module::MemberComment.View.pc.public.comment',['biz'=>'post','bizId'=>$post['id']])
</div>
</div>
@endif
@endsection
@extends($_viewFrame)
@section('pageTitleMain','关注的专题文章')
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-3">
<div class="margin-top">
<div class="ub-menu simple">
<a class="title {{modstart_baseurl_active(modstart_web_url('follow/topics'))}}" href="{{modstart_web_url('follow/topics')}}">
<i class="iconfont icon-category"></i>
关注的专题
</a>
<a class="title {{modstart_baseurl_active(modstart_web_url('follow/users'))}}" href="{{modstart_web_url('follow/users')}}">
<i class="iconfont icon-user"></i>
关注的用户
</a>
</div>
</div>
<div class="ub-panel margin-top">
<div class="head">
<div class="title">推荐专题</div>
</div>
<div class="body tw-bg-white">
@include('module::CmsWriter.View.pc.part.topics',['topics'=>$recommendTopics])
</div>
</div>
</div>
<div class="col-md-9">
<div class="tw-bg-white tw-rounded">
<div class="ub-nav-tab margin-top">
<a href="javascript:;" class="active">
<i class="iconfont icon-list-alt"></i>
关注的专题文章
</a>
</div>
<div class="margin-top">
@include('module::CmsWriter.View.pc.part.notes',['notes'=>$notes])
<div class="ub-page">
{!! $pageHtml !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends($_viewFrame)
@section('pageTitleMain','关注的用户文章')
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-3">
<div class="margin-top">
<div class="ub-menu simple">
<a class="title {{modstart_baseurl_active(modstart_web_url('follow/topics'))}}" href="{{modstart_web_url('follow/topics')}}">
<i class="iconfont icon-category"></i>
关注的专题
</a>
<a class="title {{modstart_baseurl_active(modstart_web_url('follow/users'))}}" href="{{modstart_web_url('follow/users')}}">
<i class="iconfont icon-user"></i>
关注的用户
</a>
</div>
</div>
<div class="ub-panel margin-top">
<div class="head">
<div class="title">推荐用户</div>
</div>
<div class="body tw-bg-white">
@include('module::CmsWriter.View.pc.part.users',['users'=>$recommendUsers])
</div>
</div>
</div>
<div class="col-md-9">
<div class="tw-bg-white tw-rounded">
<div class="ub-nav-tab margin-top">
<a href="javascript:;" class="active">
<i class="iconfont icon-list-alt"></i>
关注的用户文章
</a>
</div>
<div class="margin-top">
@include('module::CmsWriter.View.pc.part.notes',['notes'=>$notes])
<div class="ub-page">
{!! $pageHtml !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends($_viewFrameDialog)
@section('pageTitle')收录到专题@endsection
@section('bodyAppend')
<script src="@asset('asset/vendor/vue.js')"></script>
<script src="@asset('asset/vendor/element-ui/index.js')"></script>
<script>
window.__data = {
noteAlias: {!! json_encode(\Illuminate\Support\Facades\Input::get('noteAlias')) !!}
};
</script>
<script src="@asset('vendor/CmsWriter/entry/noteAddToTopic.js')"></script>
@endsection
@section('bodyContent')
<div id="app"></div>
@endsection
@extends($_viewFrame)
@section('pageTitleMain')文章@endsection
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-9">
<div class="tw-bg-white tw-rounded">
<div class="ub-nav-tab margin-top">
<a href="{{modstart_web_url('note')}}" class="{{modstart_baseurl_active(modstart_web_url('note'))}}">
<i class="iconfont icon-list-alt"></i>
推荐文章
</a>
<a href="{{modstart_web_url('note/comments')}}" class="{{modstart_baseurl_active(modstart_web_url('note/comments'))}}">
<i class="iconfont icon-pinglun"></i>
热论文章
</a>
<a href="{{modstart_web_url('note/views')}}" class="{{modstart_baseurl_active(modstart_web_url('note/views'))}}">
<i class="iconfont icon-star"></i>
最热文章
</a>
<a href="{{modstart_web_url('note/latest')}}" class="{{modstart_baseurl_active(modstart_web_url('note/latest'))}}">
<i class="iconfont icon-details"></i>
最新文章
</a>
</div>
<div class="margin-top">
@include('module::CmsWriter.View.pc.part.notes',['notes'=>$notes])
</div>
<div class="ub-page">
{!! $pageHtml !!}
</div>
</div>
</div>
<div class="col-md-3">
<div class="margin-top">
<a class="btn btn-lg btn-primary btn-block" href="{{modstart_web_url('writer')}}">
<i class="iconfont icon-edit"></i>
开始创作
</a>
</div>
<div class="ub-panel margin-top">
<div class="head">
<div class="title">推荐专题</div>
</div>
<div class="body tw-bg-white">
@include('module::CmsWriter.View.pc.part.topics',['topics'=>$recommendTopics])
</div>
</div>
<div class="ub-panel margin-top" data-user-box>
<div class="head">
<div class="ub-nav-tab">
<a href="javascript:;" class="active" style="padding:0;">
推荐用户
</a>
<a href="javascript:;" style="padding:0;">
最新用户
</a>
</div>
</div>
<div class="body tw-bg-white">
<div data-user-item>
@include('module::CmsWriter.View.pc.part.users',['users'=>$recommendUsers])
</div>
<div data-user-item class="tw-hidden">
@include('module::CmsWriter.View.pc.part.users',['users'=>$latestUsers])
</div>
</div>
<script>
$(function () {
var $box = $('[data-user-box]');
var $tab = $box.find('.ub-nav-tab a');
$tab.on('click', function () {
var index = $(this).index();
$box.find('[data-user-item]').addClass('tw-hidden').eq(index).removeClass('tw-hidden');
$tab.removeClass('active').eq(index).addClass('active');
return false;
});
});
</script>
</div>
</div>
</div>
</div>
@endsection
@extends($_viewFrame)
@section('pageTitleMain'){{$note['title']}}@endsection
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
@section('bodyContent')
<div class="ub-container" style="max-width:35rem;background:#FFF;">
<div class="ub-article margin-top white tw-rounded">
@if($note['status']!==\Module\CmsWriter\Type\NoteStatus::VERIFY_PASS)
<div class="ub-alert ub-alert-danger ub-text-center">当前文章正在审核</div>
@endif
<h1>{{$note['title']}}</h1>
<div class="attr">
<div>
@if($note['isOriginal'])
<span class="ub-tag primary">原创</span>
@endif
@if(!empty($note['tags']))
@foreach($note['tags'] as $tag)
<span class="ub-tag">{{$tag}}</span>
@endforeach
@endif
更新{{$note['created_at']}}
</div>
</div>
<div class="content ub-html">
{!! $note['contentHtml'] !!}
</div>
</div>
<div class="ub-text-right tw-py-4">
<a class="tw-text-gray-400" href="javascript:;"
data-dialog-request="{{\Module\ContentReport\Util\ContentReportUtil::submitPageUrl('note',$note['id'],$note['title'])}}">
举报
</a>
<span class="tw-text-gray-400 tw-ml-2">
&copy; 著作权归作者所有
</span>
</div>
<div class="margin-top ub-padding">
<div>
<div class="row">
<div class="col-md-6">
<div class="tw-inline-block" data-note-like-item data-alias="{{$note['alias']}}" data-status="{{$note['_isLike']?'is_like':'not_like'}}">
<a class="btn btn-primary btn-round" data-action="like" href="javascript:;">
<i class="iconfont icon-heart-o"></i>
喜欢
|
<span class="cnt">{{$note['likeCount']}}</span>
</a>
<a class="btn btn-round" data-action="unlike" href="javascript:;">
<i class="iconfont icon-heart-o"></i>
已喜欢
|
<span class="cnt">{{$note['likeCount']}}</span>
</a>
</div>
<a class="btn btn-round" href="javascript:;" data-dialog-request="{{modstart_web_url('n/'.$note['alias'].'/add_to_topic')}}">
<i class="iconfont icon-plus"></i>
收录到我的专题
|
<span>{{$note['viewCount']}}</span>
</a>
</div>
<div class="col-md-6 ub-text-right">
@include('module::Vendor.View.public.shareButtons')
</div>
</div>
</div>
@include('module::MemberReward.View.pc.public.reward',['memberUserId'=>$note['memberUserId'],'biz'=>'note','bizId'=>$note['id']])
<div class="margin-top-lg tw-bg-gray-100 tw-p-4 tw-rounded tw-mb-2">
<div class="tw-flex tw-justify-between tw-items-center">
<div class="tw-flex">
<div class="tw-mr-4">
<div class="ub-cover-1-1 tw-shadow tw-w-10 tw-h-10 tw-rounded-full"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($note['_memberUser']['avatar'])}});">
</div>
</div>
<div>
<div class="tw-font-bold tw-text-gray-700">{{$note['_memberUser']['username']}}</div>
<div class="tw-text-gray-400 tw-text-sm">
写了 {{$note['_memberUser']['wordCount']}} {{$note['_memberUser']['followerCount']}} 人关注
</div>
</div>
</div>
<div>
@if($note['_memberUser']['id']!=\Module\Member\Auth\MemberUser::id())
<div data-member-follow-item data-status="{{$note['_memberUser']['_isFollow']?'is_follow':'not_follow'}}" data-id="{{$note['_memberUser']['id']}}">
<a href="javascript:;" data-action="follow" class="btn btn-primary btn-round">
<i class="iconfont icon-plus"></i>
关注
</a>
<a href="javascript:;" data-action="unfollow" class="btn btn-round">
<i class="iconfont icon-check"></i>
已关注
</a>
</div>
@endif
</div>
</div>
<div class="tw-border-0 tw-border-solid tw-border-t tw-border-gray-200 tw-mt-2 tw-pt-2 tw-text-gray-500">
{{$note['_memberUser']['signature']}}
</div>
</div>
</div>
</div>
@if(modstart_config('MemberComment_Enable',false))
<div class="ub-container margin-top" style="max-width:35rem;">
<div>
@include('module::MemberComment.View.pc.public.comment',['biz'=>'note','bizId'=>$note['id']])
</div>
</div>
@endif
@endsection
@extends('module::CmsWriter.View.pc.noteMember.frame')
@section('pageTitleMain')关注的专题 -{{$user['username']}}的个人中心@endsection
@section('noteMemberContent')
<div class="ub-nav-tab margin-top">
<a href="{{modstart_web_url('note_member/'.$user['id'].'/like_notes')}}">
<i class="iconfont icon-heart-o"></i>
喜欢的文章
</a>
<a href="{{modstart_web_url('note_member/'.$user['id'].'/followed_topics')}}" class="active">
<i class="iconfont icon-category"></i>
关注的专题
</a>
</div>
<div class="margin-top">
@include('module::CmsWriter.View.pc.part.topicsPage',['topics'=>$records])
</div>
<div class="ub-page">
{!! $pageHtml !!}
</div>
@endsection
@extends($_viewFrame)
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-9">
<div class="margin-top tw-bg-white tw-p-4 tw-rounded tw-mb-2">
<div class="tw-flex tw-justify-between tw-items-center">
<div class="tw-flex">
<div class="tw-mr-4">
<div class="ub-cover-1-1 tw-shadow tw-w-20 tw-h-20 tw-rounded-full"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($user['avatar'])}});"></div>
</div>
<div class="tw-py-3">
<div>
<span class="tw-font-bold tw-text-xl tw-text-gray-700">{{$user['username']}}</span>
@if($user['gender']==\Module\Member\Type\Gender::MALE)
<i class="iconfont icon-male tw-text-blue-500 tw-text-sm"></i>
@endif
@if($user['gender']==\Module\Member\Type\Gender::FEMALE)
<i class="iconfont icon-female tw-text-pink-500 tw-text-sm"></i>
@endif
</div>
<div class="tw-mt-2">
<div class="tw-flex">
<a class="tw-block" href="{{modstart_web_url('member_follow/'.$user['id'].'/following')}}">
<div class="tw-text-lg tw-text-gray-700">{{intval($user['followCount'])}}</div>
<div class="tw-text-gray-400 tw-text-sm">关注</div>
</a>
<a class="tw-block tw-pl-4" href="{{modstart_web_url('member_follow/'.$user['id'].'/followers')}}">
<div class="tw-text-lg tw-text-gray-700">{{intval($user['followerCount'])}}</div>
<div class="tw-text-gray-400 tw-text-sm">粉丝</div>
</a>
<div class="tw-block tw-pl-4">
<div class="tw-text-lg tw-text-gray-700">{{intval($user['wordCount'])}}</div>
<div class="tw-text-gray-400 tw-text-sm">字数</div>
</div>
<div class="tw-block tw-pl-4">
<div class="tw-text-lg tw-text-gray-700">{{intval($user['noteCount'])}}</div>
<div class="tw-text-gray-400 tw-text-sm">文章</div>
</div>
</div>
</div>
</div>
</div>
<div>
@if($user['id']!=\Module\Member\Auth\MemberUser::id())
<a href="{{modstart_web_url('member_chat#chat_create/'.$user['id'])}}" class="btn btn-lg btn-primary-line btn-round">
<i class="iconfont icon-pinglun"></i>
发私信
</a>
<div class="tw-inline-block" data-member-follow-item data-status="{{$user['_isFollow']?'is_follow':'not_follow'}}" data-id="{{$user['id']}}">
<a href="javascript:;" data-action="follow" class="btn btn-lg btn-primary-line btn-round">
<i class="iconfont icon-plus"></i>
关注
</a>
<a href="javascript:;" data-action="unfollow" class="btn btn-lg btn-round">
<i class="iconfont icon-check"></i>
已关注
</a>
</div>
@endif
</div>
</div>
</div>
<div class="tw-bg-white tw-rounded">
@section('noteMemberContent')@show
</div>
</div>
<div class="col-md-3">
<div class="ub-panel margin-top">
<div class="head">
<div class="title">个人介绍</div>
</div>
<div class="body">
<div class="ub-html">
{!! \ModStart\Core\Util\HtmlUtil::text2html($user['signature']) !!}
</div>
</div>
</div>
<div class="ub-panel">
<div class="head"></div>
<div class="body">
<a href="{{modstart_web_url('note_member/'.$user['id'].'/like_notes')}}"
class="btn btn-block {{modstart_baseurl_active(modstart_web_url('note_member/'.$user['id'].'/like_notes'),'ub-text-primary')}}">
<i class="iconfont icon-heart-o"></i>
喜欢的文章
</a>
<a href="{{modstart_web_url('note_member/'.$user['id'].'/followed_topics')}}"
class="btn btn-block margin-top {{modstart_baseurl_active(modstart_web_url('note_member/'.$user['id'].'/followed_topics'),'ub-text-primary')}}">
<i class="iconfont icon-category"></i>
关注的专题
</a>
</div>
</div>
<div class="ub-panel">
<div class="head">
<div class="title">TA创建的专题</div>
</div>
<div class="body">
@include('module::CmsWriter.View.pc.part.topics',['topics'=>$topics])
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('module::CmsWriter.View.pc.noteMember.frame')
@section('pageTitleMain'){{$user['username']}}的个人中心@endsection
@section('noteMemberContent')
<div class="ub-nav-tab margin-top">
<a href="{{modstart_web_url('note_member/'.$user['id'])}}" class="active">
<i class="iconfont icon-list-alt"></i>
文章列表
</a>
</div>
<div class="margin-top">
@include('module::CmsWriter.View.pc.part.notes',['notes'=>$notes])
</div>
<div class="ub-page">
{!! $pageHtml !!}
</div>
@endsection
@extends('module::CmsWriter.View.pc.noteMember.frame')
@section('pageTitleMain')喜欢的文章 -{{$user['username']}}的个人中心@endsection
@section('noteMemberContent')
<div class="ub-nav-tab margin-top">
<a href="{{modstart_web_url('note_member/'.$user['id'].'/like_notes')}}" class="active">
<i class="iconfont icon-heart-o"></i>
喜欢的文章
</a>
<a href="{{modstart_web_url('note_member/'.$user['id'].'/followed_topics')}}">
<i class="iconfont icon-category"></i>
关注的专题
</a>
</div>
<div class="margin-top">
@include('module::CmsWriter.View.pc.part.notes',['notes'=>$notes])
</div>
<div class="ub-page">
{!! $pageHtml !!}
</div>
@endsection
@if(empty($notes))
<div class="ub-empty">
<div class="icon">
<div class="iconfont icon-empty-box"></div>
</div>
<div class="text">暂无记录</div>
</div>
@else
{!! \ModStart\ModStart::js('asset/common/timeago.js') !!}
@foreach($notes as $note)
<div class="tw-m-2">
<div class="tw-bg-white tw-p-4 tw-border-0 tw-border-b tw-border-solid tw-border-gray-200">
<a href="{{modstart_web_url('n/'.$note['alias'])}}" class="tw-block tw-truncate tw-text-black tw-text-lg">
{{$note['title']}}
</a>
<div class="tw-flex tw-mt-4">
<a href="{{modstart_web_url('note_member/'.$note['memberUserId'])}}" class="tw-block tw-w-4 tw-h-4 tw-bg-cover tw-bg-center tw-rounded-full tw-shadow-inner"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($note['_memberUser']['avatar'])}})">
</a>
<a href="{{modstart_web_url('note_member/'.$note['memberUserId'])}}" class="tw-flex tw-text-gray-600 tw-font-medium tw-ml-2">{{$note['_memberUser']['username']}}</a>
<div class="tw-flex tw-ml-2 tw-items-center tw-text-xs tw-text-gray-400">
<time datetime="{{$note['created_at']}}"></time>
<span class="tw-px-1"></span>
<span>{{$note['_memberUser']['signature']}}</span>
</div>
</div>
<div class="tw-flex">
<div class="tw-mt-4 tw-flex-grow">
<div>
<p class="tw-text-gray-600 tw-text-sm">{!! $note['_summary'] !!}</p>
</div>
<div class="tw-mt-6 tw-flex tw-flex-wrap">
<a href="javascript:;" class="tw-flex tw-items-center tw-text-gray-500 hover:tw-opacity-75 tw-mr-4">
<i class="iconfont icon-thumb-up tw-mr-1"></i>
<span>{{intval($note['viewCount'])}}</span>
</a>
<a href="javascript:;" class="tw-flex tw-items-center tw-text-gray-500 hover:tw-opacity-75 tw-mr-4">
<i class="iconfont icon-pinglun tw-mr-1"></i>
<span>{{intval($note['commentCount'])}}</span>
</a>
<a href="javascript:;" class="tw-flex tw-items-center tw-text-gray-500 hover:tw-opacity-75 tw-mr-4">
<i class="iconfont icon-heart-o tw-mr-1"></i>
<span>{{intval($note['likeCount'])}}</span>
</a>
</div>
</div>
@if(!empty($note['_cover']))
<div class="tw-mt-4 tw-ml-4 tw-flex-shrink-0" style="width:20%;">
<div class="ub-cover-3-2 tw-w-full tw-rounded" style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($note['_cover'])}})"></div>
</div>
@endif
</div>
</div>
</div>
@endforeach
@endif
@if(empty($topics))
<div class="ub-empty">
<div class="icon">
<div class="iconfont icon-empty-box"></div>
</div>
<div class="text">暂无记录</div>
</div>
@else
@foreach($topics as $topic)
<div class="tw-rounded-lg tw-mb-2 tw-flex tw-justify-between tw-items-center tw-bg-white" data-repeat="3">
<div class="tw-flex">
<div class="tw-mr-4">
<a href="{{modstart_web_url('t/'.$topic['alias'])}}" class="ub-cover-1-1 tw-shadow tw-w-10 tw-h-10 tw-rounded"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($topic['cover'])}});">
</a>
</div>
<div>
<a href="{{modstart_web_url('t/'.$topic['alias'])}}" class="tw-font-bold tw-text-gray-700">{{$topic['title']}}</a>
<div class="tw-text-gray-400 tw-text-sm">{{$topic['description']}}</div>
</div>
</div>
@if(isset($topic['_isFollow']))
<div data-topic-follow-item data-status="{{$topic['_isFollow']?'is_follow':'not_follow'}}" data-alias="{{$topic['alias']}}">
<a href="javascript:;" data-action="follow" class="btn btn-primary btn-round">
<i class="iconfont icon-plus"></i>
关注
</a>
<a href="javascript:;" data-action="unfollow" class="btn btn-round">
<i class="iconfont icon-check"></i>
已关注
</a>
</div>
@endif
</div>
@endforeach
@endif
@if(empty($topics))
<div class="ub-empty">
<div class="icon">
<div class="iconfont icon-empty-box"></div>
</div>
<div class="text">暂无记录</div>
</div>
@else
@foreach($topics as $topic)
<div class="tw-p-4 tw-rounded-lg tw-mb-2 tw-flex tw-justify-between tw-items-center tw-bg-white" data-repeat="3">
<div class="tw-flex">
<div class="tw-mr-4">
<a href="{{modstart_web_url('t/'.$topic['alias'])}}" class="ub-cover-1-1 tw-shadow tw-w-10 tw-h-10 tw-rounded"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($topic['cover'])}});">
</a>
</div>
<div>
<a href="{{modstart_web_url('t/'.$topic['alias'])}}" class="tw-font-bold tw-text-gray-700">{{$topic['title']}}</a>
<div class="tw-text-gray-400 tw-text-sm">{{$topic['description']}}</div>
</div>
</div>
@if(isset($topic['_isFollow']))
<div data-topic-follow-item data-status="{{$topic['_isFollow']?'is_follow':'not_follow'}}" data-alias="{{$topic['alias']}}">
<a href="javascript:;" data-action="follow" class="btn btn-primary btn-round">
<i class="iconfont icon-plus"></i>
关注
</a>
<a href="javascript:;" data-action="unfollow" class="btn btn-round">
<i class="iconfont icon-check"></i>
已关注
</a>
</div>
@endif
</div>
@endforeach
@endif
@if(empty($users))
<div class="ub-empty">
暂无记录
</div>
@else
@foreach($users as $user)
<div class="tw-py-1 tw-flex tw-justify-between tw-items-center">
<div class="tw-flex">
<div class="tw-mr-4">
<a href="{{modstart_web_url('note_member/'.$user['id'])}}" class="ub-cover-1-1 tw-shadow tw-w-10 tw-h-10 tw-rounded-full"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($user['avatar'])}});">
</a>
</div>
<div>
<a href="{{modstart_web_url('note_member/'.$user['id'])}}" class="tw-font-bold tw-text-gray-700">{{$user['username']}}</a>
<div class="tw-text-gray-400 tw-text-sm">{{$user['signature']}}</div>
</div>
</div>
@if($user['id']!=\Module\Member\Auth\MemberUser::id())
<div data-member-follow-item data-status="{{$user['_isFollow']?'is_follow':'not_follow'}}" data-id="{{$user['id']}}">
<a href="javascript:;" data-action="follow" class="btn btn-primary-line btn-round">
<i class="iconfont icon-plus"></i>
关注
</a>
<a href="javascript:;" data-action="unfollow" class="btn btn-round">
<i class="iconfont icon-check"></i>
已关注
</a>
</div>
@endif
</div>
@endforeach
@endif
@if(empty($users))
<div class="ub-empty">
暂无记录
</div>
@else
@foreach($users as $user)
<div class="tw-p-4 tw-flex tw-justify-between tw-items-center">
<div class="tw-flex">
<div class="tw-mr-4">
<a href="{{modstart_web_url('note_member/'.$user['id'])}}" class="ub-cover-1-1 tw-shadow tw-w-10 tw-h-10 tw-rounded-full"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($user['avatar'])}});">
</a>
</div>
<div>
<a href="{{modstart_web_url('note_member/'.$user['id'])}}" class="tw-font-bold tw-text-gray-700">{{$user['username']}}</a>
<div class="tw-text-gray-400 tw-text-sm">{{$user['signature']}}</div>
</div>
</div>
@if($user['id']!=\Module\Member\Auth\MemberUser::id())
<div data-member-follow-item data-status="{{$user['_isFollow']?'is_follow':'not_follow'}}" data-id="{{$user['id']}}">
<a href="javascript:;" data-action="follow" class="btn btn-primary-line btn-round">
<i class="iconfont icon-plus"></i>
关注
</a>
<a href="javascript:;" data-action="unfollow" class="btn btn-round">
<i class="iconfont icon-check"></i>
已关注
</a>
</div>
@endif
</div>
@endforeach
@endif
@extends($_viewFrame)
@section('pageTitleMain')搜索{{$keywords}}结果@endsection
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
{!! \ModStart\ModStart::js('asset/vendor/jqueryMark.js') !!}
@section('bodyAppend')
@parent
<style type="text/css">
mark {
color: red;
background: none;
}
</style>
<script>
$(function () {
$("[data-search-result] a").mark({!! json_encode($keywords) !!}.split('').join(' '),{separateWordSearch:true});
});
</script>
@endsection
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-3">
@include('module::CmsWriter.View.pc.search.tab')
</div>
<div class="col-md-9">
<div class="ub-padding tw-bg-white margin-top">
<div class="ub-search-block-a">
<input class="input" type="text" placeholder="搜索 文章/专题/用户"
value="{{$keywords}}"
id="keyword" onkeypress="if(event.keyCode===13){window.location.href='{{modstart_web_url('search/notes')}}?keywords='+window.api.util.urlencode($(this).val());}" />
<a class="search-btn" href="javascript:;"
onclick="window.location.href='{{modstart_web_url('search/notes')}}?keywords='+window.api.util.urlencode($(this).prev().val());">
<span class="iconfont icon-search"></span>
搜索
</a>
</div>
</div>
<div class="ub-search-result">
搜索 <span class="keyword">{{$keywords}}</span> 共找到 <span class="count">{{$total}}</span> 条记录
</div>
<div class="tw-bg-white tw-rounded">
<div class="ub-nav-tab margin-top">
<a href="javascript:;" class="active">
<i class="iconfont icon-list-alt"></i>
搜索结果
</a>
</div>
<div class="margin-top" data-search-result>
@include('module::CmsWriter.View.pc.part.notes',['notes'=>$notes])
<div class="ub-page">
{!! $pageHtml !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
<div class="margin-top">
<div class="ub-menu simple">
<a class="title {{modstart_baseurl_active(modstart_web_url('search/notes'))}}" href="{{modstart_web_url('search/notes',['keywords'=>$keywords])}}">
<i class="iconfont icon-list"></i>
搜索文章
</a>
<a class="title {{modstart_baseurl_active(modstart_web_url('search/topics'))}}" href="{{modstart_web_url('search/topics',['keywords'=>$keywords])}}">
<i class="iconfont icon-category"></i>
搜索专题
</a>
<a class="title {{modstart_baseurl_active(modstart_web_url('search/users'))}}" href="{{modstart_web_url('search/users',['keywords'=>$keywords])}}">
<i class="iconfont icon-user"></i>
关注的用户
</a>
</div>
</div>
@extends($_viewFrame)
@section('pageTitleMain')搜索{{$keywords}}结果@endsection
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
{!! \ModStart\ModStart::js('asset/vendor/jqueryMark.js') !!}
@section('bodyAppend')
@parent
<style type="text/css">
mark {
color: red;
background: none;
}
</style>
<script>
$(function () {
$("[data-search-result] a").mark({!! json_encode($keywords) !!}.split('').join(' '),{separateWordSearch:true});
});
</script>
@endsection
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-3">
@include('module::CmsWriter.View.pc.search.tab')
</div>
<div class="col-md-9">
<div class="ub-padding tw-bg-white margin-top">
<div class="ub-search-block-a">
<input class="input" type="text" placeholder="搜索 文章/专题/用户"
value="{{$keywords}}"
id="keyword" onkeypress="if(event.keyCode===13){window.location.href='{{modstart_web_url('search/notes')}}?keywords='+window.api.util.urlencode($(this).val());}" />
<a class="search-btn" href="javascript:;"
onclick="window.location.href='{{modstart_web_url('search/notes')}}?keywords='+window.api.util.urlencode($(this).prev().val());">
<span class="iconfont icon-search"></span>
搜索
</a>
</div>
</div>
<div class="ub-search-result">
搜索 <span class="keyword">{{$keywords}}</span> 共找到 <span class="count">{{$total}}</span> 条记录
</div>
<div class="tw-bg-white tw-rounded">
<div class="ub-nav-tab margin-top">
<a href="javascript:;" class="active">
<i class="iconfont icon-list-alt"></i>
搜索结果
</a>
</div>
<div class="margin-top" data-search-result>
@include('module::CmsWriter.View.pc.part.topicsPage',['topics'=>$topics])
<div class="ub-page">
{!! $pageHtml !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends($_viewFrame)
@section('pageTitleMain')搜索{{$keywords}}结果@endsection
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
{!! \ModStart\ModStart::js('asset/vendor/jqueryMark.js') !!}
@section('bodyAppend')
@parent
<style type="text/css">
mark {
color: red;
background: none;
}
</style>
<script>
$(function () {
$("[data-search-result] a").mark({!! json_encode($keywords) !!}.split('').join(' '),{separateWordSearch:true});
});
</script>
@endsection
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-3">
@include('module::CmsWriter.View.pc.search.tab')
</div>
<div class="col-md-9">
<div class="ub-padding tw-bg-white margin-top">
<div class="ub-search-block-a">
<input class="input" type="text" placeholder="搜索 文章/专题/用户"
value="{{$keywords}}"
id="keyword" onkeypress="if(event.keyCode===13){window.location.href='{{modstart_web_url('search/notes')}}?keywords='+window.api.util.urlencode($(this).val());}" />
<a class="search-btn" href="javascript:;"
onclick="window.location.href='{{modstart_web_url('search/notes')}}?keywords='+window.api.util.urlencode($(this).prev().val());">
<span class="iconfont icon-search"></span>
搜索
</a>
</div>
</div>
<div class="ub-search-result">
搜索 <span class="keyword">{{$keywords}}</span> 共找到 <span class="count">{{$total}}</span> 条记录
</div>
<div class="tw-bg-white tw-rounded">
<div class="ub-nav-tab margin-top">
<a href="javascript:;" class="active">
<i class="iconfont icon-list-alt"></i>
搜索结果
</a>
</div>
<div class="margin-top" data-search-result>
@include('module::CmsWriter.View.pc.part.usersPage',['users'=>$users])
<div class="ub-page">
{!! $pageHtml !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends($_viewFrame)
@section('pageTitleMain'){{\ModStart\Core\Util\CRUDUtil::id()?'编辑专题':'创建专题'}}@endsection
@section('bodyAppend')
<script src="@asset('asset/vendor/vue.js')"></script>
<script src="@asset('asset/vendor/element-ui/index.js')"></script>
<script>
window.__selectorDialogServer = "{{modstart_web_url('member_data/file_manager')}}";
window.__data = {
id:{{\ModStart\Core\Util\CRUDUtil::id()}}
};
</script>
<script src="@asset('vendor/CmsWriter/entry/topicEdit.js')"></script>
@endsection
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-9">
<div id="app"></div>
</div>
<div class="col-md-3">
<div class="ub-panel margin-top">
<div class="head">
<div class="title">专题说明</div>
</div>
<div class="body">
<div class="ub-html">
{!! modstart_config('moduleCmsTopicEditTip') !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends($_viewFrameDialog)
@section('pageTitle')添加文章@endsection
@section('bodyAppend')
<script src="@asset('asset/vendor/vue.js')"></script>
<script src="@asset('asset/vendor/element-ui/index.js')"></script>
<script>
window.__data = {
topicAlias: {!! json_encode(\Illuminate\Support\Facades\Input::get('topicAlias')) !!}
};
</script>
<script src="@asset('vendor/CmsWriter/entry/topicNoteAdd.js')"></script>
@endsection
@section('bodyContent')
<div id="app"></div>
@endsection
@extends($_viewFrameDialog)
@section('pageTitle')专题投稿@endsection
@section('bodyAppend')
<script src="@asset('asset/vendor/vue.js')"></script>
<script src="@asset('asset/vendor/element-ui/index.js')"></script>
<script>
window.__data = {
topicAlias: {!! json_encode(\Illuminate\Support\Facades\Input::get('topicAlias')) !!}
};
</script>
<script src="@asset('vendor/CmsWriter/entry/topicNoteApply.js')"></script>
@endsection
@section('bodyContent')
<div id="app"></div>
@endsection
@extends($_viewFrameDialog)
@section('pageTitle')投稿审核@endsection
@section('bodyAppend')
<script src="@asset('asset/vendor/vue.js')"></script>
<script src="@asset('asset/vendor/element-ui/index.js')"></script>
<script>
window.__data = {
topicAlias: {!! json_encode(\Illuminate\Support\Facades\Input::get('topicAlias')) !!}
};
</script>
<script src="@asset('vendor/CmsWriter/entry/topicNoteApplyVerify.js')"></script>
@endsection
@section('bodyContent')
<div id="app"></div>
@endsection
@extends($_viewFrame)
@section('pageTitleMain'){{$topic['title']}}@endsection
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-9">
<div class="margin-top tw-bg-white tw-p-4 tw-rounded tw-mb-2" >
<div class="tw-flex tw-justify-between tw-items-center">
<div class="tw-flex">
<div class="tw-mr-4">
<div class="ub-cover-1-1 tw-shadow tw-w-20 tw-h-20 tw-rounded"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($topic['cover'])}});">
</div>
</div>
<div class="tw-py-3">
<div class="tw-font-bold tw-text-xl tw-text-gray-700">{{$topic['title']}}</div>
<div class="tw-text-gray-400 tw-text-sm tw-mt-2">
收录了{{intval($topic['noteCount'])}}篇文章 · {{intval($topic['followerCount'])}}人关注
</div>
</div>
</div>
<div data-topic-follow-item data-status="{{$topic['_isFollow']?'is_follow':'not_follow'}}" data-alias="{{$topic['alias']}}">
@if($topic['pushEnable'])
@if(\Module\Member\Auth\MemberUser::id()==$topic['memberUserId'])
<a href="javascript:;" data-dialog-request="{{modstart_web_url('topic/note_add',['topicAlias'=>$topic['alias']])}}" class="btn btn-lg btn-primary-line btn-round">
<i class="iconfont icon-plus"></i>
添加文章
</a>
@else
@if(\Module\Member\Auth\MemberUser::isLogin())
<a href="javascript:;" data-dialog-request="{{modstart_web_url('topic/note_apply',['topicAlias'=>$topic['alias']])}}" class="btn btn-lg btn-primary-line btn-round">
<i class="iconfont icon-fly"></i>
投稿
</a>
@else
<a href="{{modstart_web_url('login',['redirect'=>modstart_web_url('t/'.$topic['alias'])])}}" class="btn btn-lg btn-primary-line btn-round">
<i class="iconfont icon-fly"></i>
投稿
</a>
@endif
@endif
@endif
<a href="javascript:;" data-action="follow" class="btn btn-lg btn-primary btn-round">
<i class="iconfont icon-plus"></i>
关注
</a>
<a href="javascript:;" data-action="unfollow" class="btn btn-lg btn-round">
<i class="iconfont icon-check"></i>
已关注
</a>
</div>
</div>
</div>
<div class="tw-bg-white tw-rounded">
<div class="ub-nav-tab margin-top">
<a href="{{modstart_web_url('note')}}" class="active">
<i class="iconfont icon-list-alt"></i>
文章列表
</a>
</div>
<div class="margin-top">
@include('module::CmsWriter.View.pc.part.notes',['notes'=>$notes])
</div>
</div>
<div class="ub-page">
{!! $pageHtml !!}
</div>
</div>
<div class="col-md-3">
<div class="ub-panel margin-top">
<div class="head">
<div class="title">{{$topic['title']}}</div>
</div>
<div class="body">
<div class="ub-html">
{!! \ModStart\Core\Util\HtmlUtil::text2html($topic['description']) !!}
</div>
</div>
</div>
@if($topic['memberUserId']===\Module\Member\Auth\MemberUser::id())
<div class="ub-panel">
<div class="head">
<div class="title">管理</div>
</div>
<div class="body">
<div>
<a class="btn btn-block" data-dialog-request="{{modstart_web_url('topic/note_apply_verify',['topicAlias'=>$topic['alias']])}}" href="javascript:;">审核投稿</a>
</div>
<div class="margin-top">
<a class="btn btn-block" href="{{modstart_web_url('topic/edit',['_id'=>$topic['id']])}}">编辑</a>
</div>
</div>
</div>
@endif
<div class="ub-panel">
<div class="head">
<div class="title">分享</div>
</div>
<div class="body">
<div>
@include('module::Vendor.View.public.shareButtons')
</div>
</div>
</div>
<div class="ub-panel">
<div class="head">
<div class="title">管理员</div>
</div>
<div class="body">
<div class="tw-py-1 tw-flex tw-justify-between tw-items-center">
<div class="tw-flex">
<div class="tw-mr-4">
<a href="{{modstart_web_url('note_member/'.$topicOwner['id'])}}" class="ub-cover-1-1 tw-shadow tw-w-10 tw-h-10 tw-rounded-full"
style="background-image:url({{\ModStart\Core\Assets\AssetsUtil::fix($topicOwner['avatar'])}});">
</a>
</div>
<div>
<a href="{{modstart_web_url('note_member/'.$topicOwner['id'])}}" class="tw-font-bold tw-text-gray-700">{{$topicOwner['username']}}</a>
<div class="tw-text-gray-400 tw-text-sm">{{$topicOwner['signature']}}</div>
</div>
</div>
@if($topicOwner['id']!=\Module\Member\Auth\MemberUser::id())
<div data-member-follow-item data-status="{{$topicOwner['_isFollow']?'is_follow':'not_follow'}}" data-id="{{$topicOwner['id']}}">
<a href="javascript:;" data-action="follow" class="btn btn-primary-line btn-round">
<i class="iconfont icon-plus"></i>
关注
</a>
<a href="javascript:;" data-action="unfollow" class="btn btn-round">
<i class="iconfont icon-check"></i>
已关注
</a>
</div>
@endif
</div>
</div>
</div>
<div class="ub-panel">
<div class="head">
<div class="title">关注的人</div>
</div>
<div class="body">
@include('module::CmsWriter.View.pc.part.users',['users'=>$followers])
</div>
</div>
</div>
</div>
</div>
@endsection
@extends($_viewFrame)
@section('pageTitleMain','文章')
{!! \ModStart\ModStart::styleFile('public/vendor/CmsWriter/asset/notesns.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/CmsWriter/asset/notesns.js') !!}
{!! \ModStart\ModStart::styleFile('public/vendor/MemberFollow/asset/memberFollow.css') !!}
{!! \ModStart\ModStart::scriptFile('public/vendor/MemberFollow/asset/memberFollow.js') !!}
@section('bodyContent')
<div class="ub-container">
<div class="row">
<div class="col-md-3">
<div class="margin-top">
<div class="ub-menu simple">
<a class="title {{modstart_baseurl_active(modstart_web_url('topics'))}}" href="{{modstart_web_url('topics')}}">
<i class="iconfont icon-category"></i>
推荐专题
</a>
<a class="title {{modstart_baseurl_active(modstart_web_url('topics/latest'))}}" href="{{modstart_web_url('topics/latest')}}">
<i class="iconfont icon-category"></i>
最新专题
</a>
</div>
</div>
<div class="margin-top ub-padding">
<a class="btn btn-lg btn-primary-line btn-round btn-block" href="{{modstart_web_url('topic/edit')}}">
<i class="iconfont icon-edit"></i>
创建我的专题
</a>
</div>
<div class="ub-panel margin-top">
<div class="head">
<div class="title">推荐用户</div>
</div>
<div class="body tw-bg-white">
@include('module::CmsWriter.View.pc.part.users',['users'=>$recommendUsers])
</div>
</div>
</div>
<div class="col-md-9">
<div class="ub-panel margin-top" style="background:transparent;">
<div class="head">
<div class="title">最新专题</div>
</div>
<div class="body">
@include('module::CmsWriter.View.pc.part.topicsPage',['topics'=>$topics])
<div class="ub-page">
{!! $pageHtml !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends($_viewMemberFrame)
@section('pageTitleMain')编辑文章@endsection
@section('memberBodyContent')
<div id="app"></div>
@endsection
@section('bodyAppend')
<script src="@asset('asset/common/editor.js')"></script>
<script src="@asset('asset/common/editorMarkdown.js')"></script>
<script src="@asset('asset/vendor/vue.js')"></script>
<script src="@asset('asset/vendor/element-ui/index.js')"></script>
<script>
window.__selectorDialogServer = "{{modstart_web_url('member_data/file_manager')}}";
window.__data = {
id:{{\ModStart\Core\Util\CRUDUtil::id()}}
};
</script>
<script src="@asset('vendor/CmsWriter/entry/writerPostEdit.js')"></script>
@endsection
<?php
namespace Module\CmsWriter\Web\Controller;
use ModStart\Core\Input\InputPackage;
use ModStart\Core\Input\Request;
use ModStart\Core\Input\Response;
use ModStart\Core\Util\PageHtmlUtil;
use ModStart\Module\ModuleBaseController;
class ChannelController extends ModuleBaseController
{
private $api;
public function __construct(\Module\CmsWriter\Api\Controller\ChannelController $api)
{
$this->api = $api;
}
public function index($alias)
{
InputPackage::mergeToInput('channelAlias', $alias);
$viewData = Response::tryGetData($this->api->paginate());
$viewData['pageHtml'] = PageHtmlUtil::render($viewData['total'], $viewData['pageSize'], $viewData['page'], '?' . Request::mergeQueries(['page' => ['{page}']]));
return $this->view('cms.channel.index', $viewData);
}
}
<?php
namespace Module\CmsWriter\Web\Controller;
use ModStart\Core\Input\Response;
use ModStart\Module\ModuleBaseController;
class IndexController extends ModuleBaseController
{
private $api;
public function __construct(\Module\CmsWriter\Api\Controller\IndexController $api)
{
$this->api = $api;
}
public function index()
{
$viewData = Response::tryGetData($this->api->home());
return $this->view('cms.index', $viewData);
}
}
<?php
namespace Module\CmsWriter\Web\Controller;
use ModStart\Core\Input\InputPackage;
use ModStart\Core\Input\Response;
use ModStart\Module\ModuleBaseController;
use Module\Member\Support\MemberLoginCheck;
class PostController extends ModuleBaseController implements MemberLoginCheck
{
public static $memberLoginCheckIgnores = ['index', 'show'];
private $api;
public function __construct(\Module\CmsWriter\Api\Controller\PostController $api)
{
$this->api = $api;
}
public function show($alias)
{
InputPackage::mergeToInput('alias', $alias);
$ret = Response::tryGetData($this->api->get());
return $this->view('cms.post.show', [
'post' => $ret['post'],
]);
}
}
<?php
namespace Module\CmsWriter\Web\Controller;
use ModStart\Core\Input\InputPackage;
use ModStart\Core\Input\Request;
use ModStart\Core\Input\Response;
use ModStart\Core\Util\PageHtmlUtil;
use ModStart\Module\ModuleBaseController;
use Module\Member\Support\MemberLoginCheck;
class SearchController extends ModuleBaseController implements MemberLoginCheck
{
private $api;
public function __construct(\Module\CmsWriter\Api\Controller\SearchController $api)
{
$this->api = $api;
}
public function index()
{
return Response::redirect(modstart_web_url('search/notes', ['keywords' => InputPackage::buildFromInput()->getTrimString('keywords')]));
}
public function notes()
{
$input = InputPackage::buildFromInput();
$viewData = [];
$ret = Response::tryGetData($this->api->notes());
$viewData['pageHtml'] = PageHtmlUtil::render($ret['total'], $ret['pageSize'], $ret['page'], '?' . Request::mergeQueries(['page' => ['{page}']]));
$viewData['notes'] = $ret['records'];
$viewData['keywords'] = $input->getTrimString('keywords');
$viewData['total'] = $ret['total'];
return $this->view('search.notes', $viewData);
}
public function topics()
{
$input = InputPackage::buildFromInput();
$viewData = [];
$ret = Response::tryGetData($this->api->topics());
$viewData['pageHtml'] = PageHtmlUtil::render($ret['total'], $ret['pageSize'], $ret['page'], '?' . Request::mergeQueries(['page' => ['{page}']]));
$viewData['topics'] = $ret['records'];
$viewData['keywords'] = $input->getTrimString('keywords');
$viewData['total'] = $ret['total'];
return $this->view('search.topics', $viewData);
}
public function users()
{
$input = InputPackage::buildFromInput();
$viewData = [];
$ret = Response::tryGetData($this->api->users());
$viewData['pageHtml'] = PageHtmlUtil::render($ret['total'], $ret['pageSize'], $ret['page'], '?' . Request::mergeQueries(['page' => ['{page}']]));
$viewData['users'] = $ret['records'];
$viewData['keywords'] = $input->getTrimString('keywords');
$viewData['total'] = $ret['total'];
return $this->view('search.users', $viewData);
}
}
<?php
namespace Module\CmsWriter\Web\Controller;
use ModStart\App\Web\Layout\WebConfigBuilder;
use ModStart\App\Web\Layout\WebPage;
use ModStart\Core\Dao\ModelUtil;
use ModStart\Core\Exception\BizException;
use ModStart\Core\Input\Request;
use ModStart\Core\Input\Response;
use ModStart\Core\Util\CRUDUtil;
use ModStart\Field\Tags;
use ModStart\Form\Form;
use ModStart\Grid\Displayer\ItemOperate;
use ModStart\Grid\Grid;
use ModStart\Grid\GridFilter;
use ModStart\Repository\Filter\RepositoryFilter;
use ModStart\Widget\Box;
use ModStart\Widget\TextAjaxRequest;
use ModStart\Widget\TextLink;
use Module\CmsWriter\Type\PostEditorType;
use Module\Member\Auth\MemberUser;
use Module\Member\Support\MemberLoginCheck;
use Module\Member\Web\Controller\MemberFrameController;
class WriterController extends MemberFrameController implements MemberLoginCheck
{
private $api;
public function __construct()
{
parent::__construct();
$this->api = app(\Module\CmsWriter\Api\Controller\WriterController::class);
}
public function index()
{
return Response::redirect('writer/post');
}
public function setting(WebConfigBuilder $builder)
{
$builder->radio('cmsEditorType', '编辑器类型')->optionType(PostEditorType::class);
$builder->view($this->viewMemberFrame)->pageTitle('写作设置');
return $builder->perform(Response::tryGetData($this->api->settingGet()), function () {
return $this->api->settingSave();
});
}
public function category(WebPage $page)
{
$grid = Grid::make('cms_member_post_category');
$grid->text('title', '标题')->required();
$grid->repositoryFilter(function (RepositoryFilter $filter) {
$filter->where('memberUserId', MemberUser::id());;
});
$grid->gridFilter(function (GridFilter $filter) {
$filter->eq('title', '标题');
});
$grid->title('分类');
$grid->urlAdd(action('\\' . __CLASS__ . '@categoryEdit'));
$grid->urlEdit(action('\\' . __CLASS__ . '@categoryEdit'));
$grid->urlDelete(action('\\' . __CLASS__ . '@categoryDelete'));
if (Request::isPost()) {
return $grid->request();
}
$grid->dialogSizeSmall();
return $page->view($this->viewMemberFrame)->pageTitle('分类管理')->body(new Box($grid, '分类管理'));
}
public function categoryEdit(WebConfigBuilder $builder)
{
$id = CRUDUtil::id();
$record = null;
if ($id) {
$record = ModelUtil::get('cms_member_post_category', [
'id' => $id, 'memberUserId' => MemberUser::id(),
]);
BizException::throwsIfEmpty('记录不存在', $record);
}
$builder->text('title', '标题')->required();
$builder->useDialog();
$builder->page()->pageTitle($id ? '编辑分类' : '增加分类');
return $builder->perform($record, function (Form $form) use ($id) {
$data = $form->dataForming();
if ($id) {
ModelUtil::update('cms_member_post_category', $id, $data);
} else {
$data['memberUserId'] = MemberUser::id();
ModelUtil::insert('cms_member_post_category', $data);
}
return Response::generateSuccess('保存成功');
});
}
public function categoryDelete()
{
$id = CRUDUtil::id();
$record = ModelUtil::get('cms_member_post_category', [
'id' => $id, 'memberUserId' => MemberUser::id(),
]);
BizException::throwsIfEmpty('记录不存在', $record);
if (ModelUtil::exists('cms_member_post', ['categoryId' => $id])) {
return Response::generateError('当前分类有文章,不能删除');
}
ModelUtil::delete('cms_member_post_category', $id);
return Response::generateSuccess();
}
public function post(WebPage $page)
{
$grid = Grid::make('cms_member_post');
$grid->select('categoryId', '分类')
->optionModel('cms_member_post_category', 'id', 'title', ['memberUserId' => MemberUser::id()])
->width(100);
$grid->text('title', '标题')->width(200);
$grid->switch('isPublished', '已发布')->optionsYesNo();
$grid->switch('isOriginal', '原创')->optionsYesNo();
$grid->tags('tags', '标签')->serializeType(Tags::SERIALIZE_TYPE_COLON_SEPARATED);
$grid->datetime('created_at', '创建');
$grid->datetime('updated_at', '更新');
$grid->repositoryFilter(function (RepositoryFilter $filter) {
$filter->where('memberUserId', MemberUser::id());
});
$grid->gridFilter(function (GridFilter $filter) {
$filter->eq('categoryId', '分类')->selectModel('cms_member_post_category', 'id', 'title', ['memberUserId' => MemberUser::id()]);
$filter->eq('title', '标题');
$filter->eq('isPublished', '已发布')->switchRadioYesNo();
});
$grid->urlAdd(action('\\' . __CLASS__ . '@postEdit'))->addBlankPage(true);
$grid->urlEdit(action('\\' . __CLASS__ . '@postEdit'))->editBlankPage(true);
$grid->urlDelete(modstart_api_url('writer/post/delete'));
$grid->title('文章');
$grid->hookItemOperateRendering(function (ItemOperate $itemOperate) {
$item = $itemOperate->item();
if ($item->isPublished) {
$post = ModelUtil::get('cms_post', ['memberPostId' => $item->id]);
if (!empty($post)) {
$itemOperate->prepend(TextLink::primary('查看发布', modstart_web_url('p/' . $post['alias']), 'target="_blank"'));
$itemOperate->prepend(TextAjaxRequest::primary('更新发布', modstart_api_url('writer/post/publish?id=' . $item->id), '确定更新发布?'));
}
$itemOperate->prepend(TextAjaxRequest::danger('取消发布', modstart_api_url('writer/post/publish_cancel?id=' . $item->id), '确定取消发布?'));
} else {
$itemOperate->prepend(TextAjaxRequest::primary('立即发布', modstart_api_url('writer/post/publish?id=' . $item->id), '确定发布?'));
}
$itemOperate->getField()->width(300);
});
if (Request::isPost()) {
return $grid->request();
}
return $page->view($this->viewMemberFrame)->pageTitle('文章管理')->body(new Box($grid, '文章管理'));
}
public function postEdit()
{
return $this->view('writer.edit');
}
}
<?php
$router->group([
'middleware' => [
\Module\Member\Middleware\WebAuthMiddleware::class,
],
], function () use ($router) {
$router->match(['get', 'post'], 'cms_writer', 'IndexController@index');
$router->match(['get', 'post'], 'writer', 'WriterController@index');
$router->match(['get', 'post'], 'writer/setting', 'WriterController@setting');
$router->match(['get', 'post'], 'writer/category', 'WriterController@category');
$router->match(['get', 'post'], 'writer/category_edit', 'WriterController@categoryEdit');
$router->match(['get', 'post'], 'writer/category_delete', 'WriterController@categoryDelete');
$router->match(['get', 'post'], 'writer/post', 'WriterController@post');
$router->match(['get', 'post'], 'writer/post_edit', 'WriterController@postEdit');
$router->match(['get', 'post'], 'channel/{alias_url}', 'ChannelController@index');
$router->match(['get', 'post'], 'p/{alias}', 'PostController@show');
});
{
"name": "CmsWriter",
"title": "文章投稿系统",
"require": [
"Vendor:>=1.7.0"
],
"version": "1.0.0",
"modstartVersion": ">=1.6.0",
"author": "ModStart",
"description": "多用户支持的文章投稿平台",
"providers": [
],
"config": {
}
}
const gulp = require('gulp');
const gulpfile = require('./../../../../vendor/modstart/modstart/resources/asset/src/mod/gulpfile.js');
gulpfile(gulp, __dirname)
{
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"babel-loader": "^8.2.2",
"babel-plugin-transform-remove-strict-mode": "^0.0.2",
"css-loader": "^5.0.1",
"expose-loader": "^1.0.3",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^6.2.0",
"gulp": "^4.0.2",
"gulp-clean-css": "^4.3.0",
"gulp-less": "^4.0.1",
"gulp-print": "^5.0.2",
"gulp-style-aliases": "^1.1.11",
"jsx-loader": "^0.13.2",
"less": "^3.13.1",
"less-loader": "^5.0.0",
"merge-stream": "^2.0.0",
"on-build-webpack": "^0.1.0",
"package-json-cleanup-loader": "^1.0.3",
"style-loader": "^2.0.0",
"uglify-js": "^3.12.6",
"url-loader": "^4.1.1",
"vue-loader": "^15.9.6",
"vue-template-compiler": "^2.6.12",
"webpack": "^4.46.0",
"webpack-build-notifier": "^2.1.1",
"webpack-cli": "^4.5.0"
},
"dependencies": {
"dateformat": "^4.5.1",
"element-ui": "^2.15.1",
"isutf8": "^3.0.0",
"jquery": "^3.5.1",
"js-cookie": "^2.2.1",
"md5": "^2.3.0",
"pinyin": "^2.10.2",
"query-string": "^6.14.0",
"randomstring": "^1.1.5",
"sprintf-js": "^1.1.2",
"ua-parser-js": "^0.7.24",
"vue": "^2.6.12",
"vue-clipboard2": "^0.3.1",
"xlsx": "^0.16.9"
}
}
$(function () {
$(document).on('click', '[data-topic-follow-item] [data-action]', function () {
const $btn = $(this)
const $box = $btn.closest('[data-topic-follow-item]')
const action = $btn.attr('data-action')
const alias = $box.attr('data-alias')
window.api.base.postSuccess(window.__msRoot + 'api/topic/' + action, {alias: alias}, function (res) {
switch (action) {
case 'follow':
$box.attr('data-status', 'is_follow')
break
case 'unfollow':
$box.attr('data-status', 'not_follow')
break
}
})
return false
});
$(document).on('click', '[data-post-like-item] [data-action]', function () {
const $btn = $(this)
const $box = $btn.closest('[data-post-like-item]')
const action = $btn.attr('data-action')
const alias = $box.attr('data-alias')
window.api.base.postSuccess(window.__msRoot + 'api/post/'+action, {alias: alias}, function (res) {
switch (action) {
case 'like':
$box.attr('data-status', 'is_like')
break
case 'unlike':
$box.attr('data-status', 'not_like')
break
}
$box.find('.cnt').html(res.data.count)
})
return false
});
})
[data-topic-follow-item], [data-post-like-item] {
[data-action] {
display: none;
}
&[data-status=is_follow], &[data-status=is_like] {
[data-action="unfollow"], [data-action="unlike"] {
display: inline-block;
}
}
&[data-status=not_follow], &[data-status=not_like] {
[data-action="follow"], [data-action="like"] {
display: inline-block;
}
}
}
<template>
<div>
<div v-if="loading" class="ub-text-muted">
正在加载中...
</div>
<div v-if="!loading && !records.length" class="ub-text-muted">
暂无分类,请先 <a :href="$url.web('writer/category')">添加分类</a>
</div>
<div v-if="records.length>0">
<el-select v-if="records.length>0" v-model="currentData" style="width:100%;">
<el-option v-for="item in records"
:key="item.id"
:label="item.title"
:value="item.id"></el-option>
</el-select>
</div>
</div>
</template>
<script>
import {FieldVModel} from "@ModStartAsset/svue/lib/fields-config"
export default {
name: "MemberPostCategorySelector",
mixins: [FieldVModel],
data() {
return {
loading: true,
records: [],
}
},
mounted() {
this.load()
},
methods: {
load() {
this.$api.post(this.$url.api('writer/category/all'), {}, res => {
this.records = res.data
this.loading = false
if (!this.currentData) {
for (let record of this.records) {
this.currentData = record.id
return
}
}
})
}
}
}
</script>
import {VueManager} from "@ModStartAsset/lib/vue-manager";
VueManager.QuickMount('#app', '<writer-post-edit />', require('./../pages/WriterPostEdit.vue').default)
export const CmsEditorType = {
"RICH_TEXT": {
"key": "RICH_TEXT",
"value": 1,
"name": "富文本"
},
"MARKDOWN": {
"key": "MARKDOWN",
"value": 2,
"name": "Markdown"
}
};
<template>
<div class="ub-panel">
<div class="head">
<div class="title">编辑文章</div>
</div>
<div class="body" v-loading="loading">
<div class="tw-p-1">
<div class="row">
<div class="col-md-3">
<MemberPostCategorySelector v-model="data.categoryId"></MemberPostCategorySelector>
</div>
<div class="col-md-9">
<el-input v-model="data.title" placeholder="标题"></el-input>
</div>
</div>
</div>
<div class="tw-p-1">
<div class="pb-content-editor">
<div class="item" :class="{show:data.contentType===CmsEditorType.RICH_TEXT.value}">
<script id="htmlEditor" name="htmlEditor" type="text/plain"></script>
</div>
<div class="item" :class="{show:data.contentType===CmsEditorType.MARKDOWN.value}">
<textarea name="markdownEditor" id="markdownEditor"></textarea>
</div>
</div>
</div>
<div class="tw-p-1">
标签
<el-input v-model="data.tags"></el-input>
<div class="ub-text-muted">多个标签使用逗号分隔</div>
</div>
<div class="tw-p-1">
原创
<el-switch v-model="data.isOriginal"></el-switch>
</div>
<div class="tw-p-1">
<a href="javascript:;" class="btn btn-primary" @click="doSubmit">保存</a>
</div>
</div>
</div>
</template>
<script>
import MemberPostCategorySelector from "../components/MemberPostCategorySelector";
import {CmsEditorType} from "../lib/constant";
import {BeanUtil} from "@ModStartAsset/svue/lib/util";
export default {
name: "WriterPostEdit",
components: {MemberPostCategorySelector},
data() {
return {
CmsEditorType,
loading: true,
setting: {
cmsEditorType: 0,
},
data: {
id: window.__data.id,
categoryId: 0,
title: '',
contentType: 0,
content: '',
isOriginal: false,
tags: '',
},
htmlEditor: null,
markdownEditor: null,
}
},
mounted() {
this.htmlEditor = window.api.editor.basic('htmlEditor')
this.markdownEditor = window.api.editorMarkdown.basic('markdownEditor')
// window.htmlEditor = this.htmlEditor
// window.markdownEditor = this.markdownEditor
this.doLoadSetting(() => {
this.doLoad()
})
},
methods: {
doLoadSetting(cb) {
this.$api.post(this.$url.api('writer/setting/get'), {id: this.data.id}, res => {
BeanUtil.update(this.setting, res.data)
cb()
})
},
doLoad() {
this.loading = true
if (this.data.id) {
this.$api.post(this.$url.api('writer/post/get'), {id: this.data.id}, res => {
BeanUtil.update(this.data, res.data.memberPost)
this.loading = false
switch (this.data.contentType) {
case CmsEditorType.RICH_TEXT.value:
this.htmlEditor.setContent(this.data.content)
break
case CmsEditorType.MARKDOWN.value:
this.markdownEditor.value(this.data.content)
break
default:
this.$dialog.tipError('错误的文章类型')
break
}
}, res => {
this.loading = false
})
} else {
this.data.contentType = this.setting.cmsEditorType
this.loading = false
}
},
doSubmit() {
let data = BeanUtil.clone(this.data)
switch (data.contentType) {
case CmsEditorType.RICH_TEXT.value:
data.content = this.htmlEditor.getContent()
break
case CmsEditorType.MARKDOWN.value:
data.content = this.markdownEditor.value()
break
default:
this.$dialog.tipError('错误的文章类型')
return
}
this.$dialog.loadingOn()
this.$api.post(this.$url.api('writer/post/edit'), data, res => {
this.$dialog.loadingOff()
this.$dialog.tipSuccess('保存成功')
setTimeout(() => {
window.location.href = this.$url.web('writer/post')
}, 3000)
}, res => {
this.$dialog.loadingOff()
})
}
}
}
</script>
<style lang="less">
.pb-content-editor {
.item {
visibility: hidden;
height: 0;
&.show {
visibility: visible;
height: auto;
}
}
}
</style>
const webpack = require('./../../../../vendor/modstart/modstart/resources/asset/src/mod/webpack.js');
module.exports = webpack(__dirname)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册