chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>公众号式文章编辑器</title>
|
||||
<!-- 引入 Layui 样式 -->
|
||||
<link rel="stylesheet" href="/assets/layui/css/layui.css" />
|
||||
<link rel="stylesheet" href="/assets/ywxapp/css/ywxapp.css" />
|
||||
<!-- 引入 UEditorPlus 核心 -->
|
||||
|
||||
<script type="text/javascript" src=" /assets/library/ueditor/ueditor.config.js"></script>
|
||||
<script type="text/javascript" src="/assets/library/ueditor/ueditor.all.js"></script>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class=" layui-container">
|
||||
<!-- 核心编辑区 -->
|
||||
<form class="layui-form action="">
|
||||
<!-- 标题输入 -->
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-wrap">
|
||||
<input type="text" name="title" autocomplete="off" placeholder="请在这里输入标题(最多64字)" lay-verify="required" class="layui-input" maxlength="64">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-wrap">
|
||||
<input type="text" name="author" autocomplete="off" placeholder="请输入作者(最多8字)" maxlength="8" lay-verify="required" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-wrap">
|
||||
|
||||
<script id="editor" type="text/plain" style="height: 450px;"></script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 功能按钮:保存/预览/发表 -->
|
||||
<div class="function-buttons">
|
||||
<button class="layui-btn layui-btn-normal" id="saveDraft">保存为草稿</button>
|
||||
<button class="layui-btn layui-btn-primary" id="preview">预览</button>
|
||||
<button class="layui-btn layui-btn-danger" id="publish">发表</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
<!-- 引入 Layui 脚本 -->
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="backend"></script>
|
||||
<script>
|
||||
// 初始化 Layui
|
||||
layui.use(["jquery", "form"], function () {
|
||||
var $ = layui.jquery;
|
||||
var form = layui.form;
|
||||
|
||||
// 1. 初始化 UEditorPlus(富文本编辑器)
|
||||
var ue = UE.getEditor("editor", {
|
||||
toolbars: [
|
||||
[
|
||||
"undo", // 撤销
|
||||
"redo", "|", // 重做
|
||||
"removeformat", // 清除格式
|
||||
"formatmatch", // 格式刷
|
||||
"|",
|
||||
"fontsize", // 字号
|
||||
"bold", // 加粗
|
||||
"italic", // 斜体
|
||||
"underline", // 下划线
|
||||
"strikethrough",// 删除线
|
||||
"forecolor", // 字体颜色
|
||||
"backcolor", // 背景色
|
||||
"|",
|
||||
"justifyleft", // 居左对齐
|
||||
"justifycenter", // 居中对齐
|
||||
"justifyright",
|
||||
"justifyjustify", // 两端对齐
|
||||
"indent", // 首行缩进
|
||||
"|",
|
||||
"inserttable", // 插入表格
|
||||
"blockquote", // 引用
|
||||
"horizontal",
|
||||
"insertcode", // 插入代码
|
||||
"emotion", // 表情
|
||||
"|",
|
||||
"ai", // AI智能
|
||||
"|",
|
||||
"print", // 打印
|
||||
"preview", // 预览
|
||||
"searchreplace", // 查询替换
|
||||
]
|
||||
],
|
||||
autoHeightEnabled: true,
|
||||
initialFrameWidth: "100%",
|
||||
initialFrameHeight: 450,
|
||||
});
|
||||
|
||||
// 2. 功能按钮事件绑定
|
||||
// 保存草稿
|
||||
$("#saveDraft").on("click", function () {
|
||||
var title = $(".editor-title input").val().trim();
|
||||
var author = $(".editor-author input").val().trim();
|
||||
var content = ue.getContent(); // 获取编辑器内容
|
||||
|
||||
// 这里对接后端 API 保存草稿(示例仅打印)
|
||||
console.log("保存草稿:", { title, author, content });
|
||||
layui.layer.msg("草稿已保存!", { icon: 1 });
|
||||
});
|
||||
|
||||
// 预览
|
||||
$("#preview").on("click", function () {
|
||||
// 实际需打开新窗口渲染内容,这里模拟
|
||||
var previewContent = `标题:${$(".editor-title input").val()}\n作者:${$(".editor-author input").val()}\n内容:${ue.getContent()}`;
|
||||
layui.layer.open({
|
||||
type: 1,
|
||||
title: "预览",
|
||||
content: `<p>${previewContent}</p>`,
|
||||
area: ["500px", "400px"],
|
||||
});
|
||||
});
|
||||
|
||||
// 发表
|
||||
$("#publish").on("click", function () {
|
||||
var title = $(".editor-title input").val().trim();
|
||||
var author = $(".editor-author input").val().trim();
|
||||
var content = ue.getContent();
|
||||
|
||||
// 对接后端 API 发表文章(示例仅打印)
|
||||
console.log("发表文章:", { title, author, content });
|
||||
layui.layer.msg("文章已发表!", { icon: 1 });
|
||||
});
|
||||
|
||||
// 3. 表单开关事件(原创/赞赏/留言等)
|
||||
form.on("switch()", function (data) {
|
||||
var label = data.othis.parents("div").prev("label").text();
|
||||
console.log(`${label} 状态:`, data.elem.checked);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">编辑文章</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" id="articleForm" action="{:url('blog/backend.article/update', ['id' => $article.id])}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文章标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" value="{$article.title}" required lay-verify="required" placeholder="请输入文章标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文章分类</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="cid" lay-verify="required">
|
||||
<option value="">请选择分类</option>
|
||||
{volist name="categories" id="category"}
|
||||
<option value="{$category.id}" {if $article.cid==$category.id}selected{/if}>{$category.name}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文章标签</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="tags" value="{$tagNamesStr}" placeholder="多个标签用逗号分隔" autocomplete="off" class="layui-input">
|
||||
<div class="layui-form-mid layui-word-aux">例如:PHP,ThinkPHP,编程</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文章摘要</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="summary" class="layui-textarea" placeholder="选填,留空将自动截取正文前 150 字" style="max-width:600px;">{$article.summary}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">封面图</label>
|
||||
<div class="layui-input-block">
|
||||
<button type="button" class="layui-btn layui-btn-normal" id="uploadCover">
|
||||
<i class="layui-icon"></i>上传图片
|
||||
</button>
|
||||
<input type="hidden" name="cover_image" id="coverImage" value="{$article.cover_image}">
|
||||
<div class="layui-word-aux">建议尺寸:800x450</div>
|
||||
<div id="coverPreview" style="margin-top:10px;">
|
||||
{if $article.cover_image}
|
||||
<img src="{$article.cover_image}" style="max-width:200px;max-height:150px;border:1px solid #eee;">
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文章状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="发布" {if $article.status==1}checked{/if}>
|
||||
<input type="radio" name="status" value="0" title="草稿" {if $article.status==0}checked{/if}>
|
||||
<input type="checkbox" name="is_top" value="1" title="置顶" {if $article.is_top==1}checked{/if}>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文章内容</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea id="editor" name="content" style="display:none;">{$article.content}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="articleSubmit">更新文章</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/lib/wangEditor/wangEditor.min.js"></script>
|
||||
<script>
|
||||
layui.use(['form', 'layer', 'upload'], function(){
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var upload = layui.upload;
|
||||
var $ = layui.$;
|
||||
|
||||
// 初始化富文本编辑器
|
||||
var editor = new window.wangEditor('#editor');
|
||||
editor.config.uploadImgServer = '{:url("upload/image")}';
|
||||
editor.config.uploadFileName = 'image';
|
||||
editor.config.zIndex = 1000;
|
||||
editor.create();
|
||||
|
||||
// 封面图上传
|
||||
upload.render({
|
||||
elem: '#uploadCover',
|
||||
url: '{:url("upload/image")}',
|
||||
done: function(res){
|
||||
if(res.code === 1){
|
||||
$('#coverImage').val(res.data.url);
|
||||
$('#coverPreview').html('<img src="'+res.data.url+'" style="max-width:200px;max-height:150px;border:1px solid #eee;">');
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 监听提交
|
||||
form.on('submit(articleSubmit)', function(data){
|
||||
data.field.content = editor.txt.html();
|
||||
$.post(data.form.action, data.field, function(res){
|
||||
if(res.code === 1){
|
||||
layer.msg(res.msg, {icon: 1}, function(){
|
||||
location.href = res.url;
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,154 @@
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="admin-title">文章管理</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form layui-inline" lay-filter="searchForm">
|
||||
<div class="layui-inline">
|
||||
<select name="status">
|
||||
<option value="all">全部状态</option>
|
||||
<option value="1">已发布</option>
|
||||
<option value="0">草稿</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="audit">
|
||||
<option value="all">全部审核</option>
|
||||
<option value="1">待审</option>
|
||||
<option value="2">通过</option>
|
||||
<option value="3">驳回</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="keyword" placeholder="搜索标题/内容" class="layui-input" id="keywordInput">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-primary" lay-submit lay-filter="search">搜索</button>
|
||||
</div>
|
||||
<button type="button" class="layui-btn layui-btn-danger" id="batchDeleteBtn">批量删除</button>
|
||||
</form>
|
||||
<table class="layui-hide" id="articleTable" lay-filter="articleTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="rowTpl">
|
||||
<a class="layui-btn layui-btn-xs" href="{{ d.edit_url }}">编辑</a>
|
||||
{{# if (d.audit_status == 1) { }}
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="audit">通过</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-warm" lay-event="reject">驳回</a>
|
||||
{{# } }}
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete">删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['table', 'layer', 'form'], function () {
|
||||
var table = layui.table;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var $ = layui.$;
|
||||
|
||||
var status = '{$status|default="all"}';
|
||||
var audit = '{$audit|default="all"}';
|
||||
var keyword = '{$keyword|default=""}';
|
||||
$('select[name="status"]').val(status);
|
||||
$('select[name="audit"]').val(audit);
|
||||
$('#keywordInput').val(keyword);
|
||||
|
||||
var renderTable = function () {
|
||||
table.render({
|
||||
elem: '#articleTable',
|
||||
url: '{:url("blog/backend.article/index")}',
|
||||
where: { status: status, audit: audit, keyword: keyword },
|
||||
page: true,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'title', title: '标题', minWidth: 220, templet: function (d) {
|
||||
var html = '<a href="' + d.edit_url + '">' + d.title + '</a>';
|
||||
if (d.is_top == 1) { html += ' <span class="layui-badge layui-bg-red">置顶</span>'; }
|
||||
return html;
|
||||
} },
|
||||
{ field: 'author', title: '作者', width: 120 },
|
||||
{ field: 'category', title: '分类', width: 120 },
|
||||
{ field: 'tags', title: '标签', width: 150, templet: function (d) { return d.tags || '-'; } },
|
||||
{ field: 'status', title: '状态', width: 90, templet: function (d) {
|
||||
return d.status == 1
|
||||
? '<span class="layui-badge layui-bg-green">已发布</span>'
|
||||
: '<span class="layui-badge">草稿</span>';
|
||||
} },
|
||||
{ field: 'audit_status', title: '审核', width: 90, templet: function (d) {
|
||||
var map = { 0: '<span class="layui-badge">草稿</span>', 1: '<span class="layui-badge layui-bg-orange">待审</span>', 2: '<span class="layui-badge layui-bg-green">通过</span>', 3: '<span class="layui-badge layui-bg-red">驳回</span>' };
|
||||
return map[d.audit_status] || '-';
|
||||
} },
|
||||
{ field: 'view_count', title: '阅读', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'comment_count', title: '评论', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'like_count', title: '点赞', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'favorite_count', title: '收藏', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'share_count', title: '分享', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'create_text', title: '发布时间', width: 160 },
|
||||
{ title: '操作', width: 130, align: 'center', toolbar: '#rowTpl', fixed: 'right' }
|
||||
]]
|
||||
});
|
||||
};
|
||||
renderTable();
|
||||
|
||||
// 搜索
|
||||
form.on('submit(search)', function () {
|
||||
var statusVal = $('select[name="status"]').val();
|
||||
var auditVal = $('select[name="audit"]').val();
|
||||
var kw = $('#keywordInput').val();
|
||||
table.reload('articleTable', { where: { status: statusVal, audit: auditVal, keyword: kw }, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
|
||||
// 批量删除
|
||||
$('#batchDeleteBtn').click(function () {
|
||||
var checkData = table.checkStatus('articleTable').data;
|
||||
if (! checkData.length) {
|
||||
return layer.msg('请选择要删除的文章');
|
||||
}
|
||||
var ids = checkData.map(function (i) { return i.id; });
|
||||
layer.confirm('确定要删除选中的 ' + ids.length + ' 篇文章吗?', function (index) {
|
||||
$.post('{:url("blog/backend.article/batch")}', { action: 'delete', ids: ids }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
});
|
||||
|
||||
// 行操作
|
||||
table.on('tool(articleTable)', function (obj) {
|
||||
if (obj.event === 'audit') {
|
||||
layer.confirm('确认审核通过该文章?', function (index) {
|
||||
$.post('{:url("blog/backend.article/audit")}', { id: obj.data.id }, function (res) {
|
||||
layer.msg(res.msg, { icon: res.code === 1 ? 1 : 2 }, function () { renderTable(); });
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'reject') {
|
||||
layer.prompt({ title: '驳回理由', formType: 2 }, function (val, index) {
|
||||
$.post('{:url("blog/backend.article/reject")}', { id: obj.data.id, reason: val }, function (res) {
|
||||
layer.close(index);
|
||||
layer.msg(res.msg, { icon: res.code === 1 ? 1 : 2 }, function () { renderTable(); });
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除这篇文章吗?', function (index) {
|
||||
$.post('{:url("blog/backend.article/delete")}', { id: obj.data.id }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">添加分类</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{:url('blog/backend.category/save')}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" required lay-verify="required" placeholder="请输入分类名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上级分类</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="pid">
|
||||
<option value="0">顶级分类</option>
|
||||
{volist name="categories" id="c"}
|
||||
<option value="{$c.id}">{$c.name}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入分类描述" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" value="0" placeholder="请输入排序值" autocomplete="off" class="layui-input">
|
||||
<div class="layui-form-mid layui-word-aux">数值越小越靠前</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="正常" checked>
|
||||
<input type="radio" name="status" value="0" title="禁用">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="categorySubmit">添加分类</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">编辑分类</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{:url('blog/backend.category/update', ['id' => $category.id])}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" value="{$category.name}" required lay-verify="required" placeholder="请输入分类名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上级分类</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="pid">
|
||||
<option value="0" {if $category.pid==0}selected{/if}>顶级分类</option>
|
||||
{volist name="categories" id="c"}
|
||||
<option value="{$c.id}" {if $category.pid==$c.id}selected{/if}>{$c.name}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入分类描述" class="layui-textarea">{$category.description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" value="{$category.sort}" placeholder="请输入排序值" autocomplete="off" class="layui-input">
|
||||
<div class="layui-form-mid layui-word-aux">数值越小越靠前</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="正常" {if $category.status==1}checked{/if}>
|
||||
<input type="radio" name="status" value="0" title="禁用" {if $category.status==0}checked{/if}>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="categorySubmit">更新分类</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,228 @@
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<button class="layui-btn layui-btn-sm" id="addRoot">添加根分类</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" id="batchDelete">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm" id="expandAll">展开全部</button>
|
||||
<button class="layui-btn layui-btn-sm" id="foldAll">折叠全部</button>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 行操作模板 -->
|
||||
<script type="text/html" id="dataBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="addChild">添加子分类</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete">删除</a>
|
||||
</script>
|
||||
|
||||
<!-- 新增/编辑 表单模板(弹窗内渲染) -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<div style="padding:15px;">
|
||||
<form class="layui-form" lay-filter="dataForm">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" value="{{ d.name || '' }}" required lay-verify="required" placeholder="请输入分类名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入分类描述" class="layui-textarea">{{ d.description || '' }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上级分类</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="pid" id="pidSelect"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" value="{{ d.sort || 0 }}" placeholder="数值越小越靠前" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" value="1" {{ d.status == 1 ? 'checked' : '' }} lay-skin="switch" lay-text="正常|禁用">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="dataFormSubmit" id="dataFormSubmit">保存</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="cancelBtn">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['treeTable', 'layer', 'form', 'laytpl', 'http'], function () {
|
||||
var treeTable = layui.treeTable;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
var form = layui.form;
|
||||
var laytpl = layui.laytpl;
|
||||
var http = layui.http;
|
||||
|
||||
var treeData = {$treeData|raw};
|
||||
var pmap = {};
|
||||
treeData.forEach(function (c) { pmap[c.id] = c; });
|
||||
|
||||
// 构建上级分类下拉(编辑时排除自身及其子孙节点,避免形成环)
|
||||
function buildPidOptions(selfId) {
|
||||
var html = '<option value="0">顶级分类</option>';
|
||||
treeData.forEach(function (c) {
|
||||
if (selfId && c.id === selfId) return;
|
||||
if (selfId) {
|
||||
var cur = pmap[c.id];
|
||||
while (cur && cur.pid) {
|
||||
if (cur.pid == selfId) return;
|
||||
cur = pmap[cur.pid];
|
||||
}
|
||||
}
|
||||
html += '<option value="' + c.id + '">' + c.title + '</option>';
|
||||
});
|
||||
return html;
|
||||
}
|
||||
|
||||
var renderTable = function () {
|
||||
treeTable.render({
|
||||
elem: '#dataTable',
|
||||
data: treeData,
|
||||
tree: {
|
||||
customName: {
|
||||
isParent: "is_parent",
|
||||
name: "title",
|
||||
id: "id",
|
||||
pid: "pid"
|
||||
},
|
||||
data: { isSimpleData: true, rootPid: 0 },
|
||||
view: { showIcon: false }
|
||||
},
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80 },
|
||||
{ field: 'title', title: '分类名称', minWidth: 160 },
|
||||
{ field: 'owner', title: '归属', width: 150 },
|
||||
{ field: 'description', title: '描述', minWidth: 160 },
|
||||
{ field: 'articles_count', title: '文章数', width: 90 },
|
||||
{ field: 'sort', title: '排序', width: 80, sort: true },
|
||||
{
|
||||
field: 'status', title: '状态', width: 90, templet: function (d) {
|
||||
return d.status == 1
|
||||
? '<span class="layui-badge layui-bg-blue">正常</span>'
|
||||
: '<span class="layui-badge layui-bg-gray">禁用</span>';
|
||||
}
|
||||
},
|
||||
{ title: '操作', width: 210, align: 'center', toolbar: '#dataBarTpl' }
|
||||
]],
|
||||
page: false,
|
||||
skin: 'line'
|
||||
});
|
||||
};
|
||||
renderTable();
|
||||
|
||||
// 展开 / 折叠全部
|
||||
$('#expandAll').click(function () { treeTable.expandAll('#dataTable'); });
|
||||
$('#foldAll').click(function () { treeTable.foldAll('#dataTable'); });
|
||||
|
||||
// 批量删除
|
||||
$('#batchDelete').click(function () {
|
||||
var checkData = treeTable.checkStatus('dataTable').data;
|
||||
if (!checkData.length) {
|
||||
return layer.msg('请选择要删除的分类');
|
||||
}
|
||||
var ids = checkData.map(function (item) { return item.id; });
|
||||
layer.confirm('确定删除选中的 ' + ids.length + ' 个分类吗?', function (index) {
|
||||
$.post('{:url("blog/backend.category/batchDelete")}', { ids: ids.join(',') }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { location.reload(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
});
|
||||
|
||||
// 新增 / 编辑 弹窗
|
||||
function openForm(data) {
|
||||
data = data || {};
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data);
|
||||
layer.open({
|
||||
title: data.id ? '编辑分类' : (data.pid ? '添加子分类' : '添加分类'),
|
||||
content: formHtml,
|
||||
anim: 'slideLeft',
|
||||
offset: 'r',
|
||||
area: ['480px', '98%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['保存', '取消'],
|
||||
success: function (layero, index) {
|
||||
$('#pidSelect').html(buildPidOptions(data.id));
|
||||
if (data.pid) { $('#pidSelect').val(data.pid); }
|
||||
form.render('select');
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
layero.contents().find('#dataFormSubmit').trigger('click');
|
||||
},
|
||||
btn2: function (index) { layer.close(index); }
|
||||
});
|
||||
}
|
||||
|
||||
// 表单提交:仅绑定一次(layui form submit 为事件委托,弹窗内同 lay-filter 表单均可触发)
|
||||
form.on('submit(dataFormSubmit)', function (elem) {
|
||||
var field = elem.field;
|
||||
var isEdit = !!field.id;
|
||||
var url = isEdit
|
||||
? '{:url("blog/backend.category/update")}'
|
||||
: '{:url("blog/backend.category/save")}';
|
||||
var postData = $.extend({}, field);
|
||||
postData.status = field.status ? 1 : 0;
|
||||
if (isEdit) { postData.id = field.id; }
|
||||
http.post(url, postData).then(function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.closeAll('dialog');
|
||||
layer.msg(res.msg, { icon: 1 });
|
||||
setTimeout(function () { location.reload(); }, 500);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败', { icon: 2 });
|
||||
}
|
||||
}).catch(function () { layer.msg('请求失败,请重试', { icon: 2 }); });
|
||||
return false;
|
||||
});
|
||||
|
||||
// 行操作
|
||||
treeTable.on('tool(dataTable)', function (obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'edit') {
|
||||
openForm(data);
|
||||
} else if (obj.event === 'addChild') {
|
||||
openForm({ pid: data.id, sort: 0, status: 1 });
|
||||
} else if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除该分类吗?', function (index) {
|
||||
$.post('{:url("blog/backend.category/delete")}', { id: data.id }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { location.reload(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 添加根分类
|
||||
$('#addRoot').click(function () {
|
||||
openForm({ pid: 0, sort: 0, status: 1 });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,143 @@
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="admin-title">评论管理</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form layui-inline" lay-filter="searchForm">
|
||||
<div class="layui-inline">
|
||||
<select name="status">
|
||||
<option value="all">全部状态</option>
|
||||
<option value="1">已通过</option>
|
||||
<option value="0">待审核</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="keyword" placeholder="搜索评论内容" class="layui-input" id="keywordInput">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-primary" lay-submit lay-filter="search">搜索</button>
|
||||
</div>
|
||||
<button type="button" class="layui-btn layui-btn-normal" id="batchApproveBtn">批量通过</button>
|
||||
<button type="button" class="layui-btn layui-btn-warm" id="batchRejectBtn">批量拒绝</button>
|
||||
<button type="button" class="layui-btn layui-btn-danger" id="batchDeleteBtn">批量删除</button>
|
||||
</form>
|
||||
<table class="layui-hide" id="commentTable" lay-filter="commentTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="rowTpl">
|
||||
{{# if (d.status == 0) { }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="approve">通过</a>
|
||||
{{# } }}
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete">删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['table', 'layer', 'form'], function () {
|
||||
var table = layui.table;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var $ = layui.$;
|
||||
|
||||
var status = '{$status|default="all"}';
|
||||
var keyword = '{$keyword|default=""}';
|
||||
$('select[name="status"]').val(status);
|
||||
$('#keywordInput').val(keyword);
|
||||
|
||||
var renderTable = function () {
|
||||
table.render({
|
||||
elem: '#commentTable',
|
||||
url: '{:url("blog/backend.comment/index")}',
|
||||
where: { status: status, keyword: keyword },
|
||||
page: true,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'nickname', title: '用户', width: 140, templet: function (d) {
|
||||
var av = d.avatar ? d.avatar : '/assets/images/avatar.png';
|
||||
return '<img src="' + av + '" class="layui-nav-img" style="width:30px;height:30px;border-radius:50%;">' + (d.nickname || '-');
|
||||
} },
|
||||
{ field: 'content', title: '评论内容', minWidth: 220 },
|
||||
{ field: 'article_title', title: '文章', minWidth: 160, templet: function (d) {
|
||||
if (d.article_url) {
|
||||
return '<a href="' + d.article_url + '">' + (d.article_title || '-') + '</a>';
|
||||
}
|
||||
return d.article_title || '-';
|
||||
} },
|
||||
{ field: 'create_text', title: '时间', width: 160 },
|
||||
{ field: 'status', title: '状态', width: 90, templet: function (d) {
|
||||
return d.status == 1
|
||||
? '<span class="status-badge status-approved">已通过</span>'
|
||||
: '<span class="status-badge status-pending">待审核</span>';
|
||||
} },
|
||||
{ title: '操作', width: 110, align: 'center', toolbar: '#rowTpl', fixed: 'right' }
|
||||
]]
|
||||
});
|
||||
};
|
||||
renderTable();
|
||||
|
||||
// 搜索
|
||||
form.on('submit(search)', function () {
|
||||
var statusVal = $('select[name="status"]').val();
|
||||
var kw = $('#keywordInput').val();
|
||||
table.reload('commentTable', { where: { status: statusVal, keyword: kw }, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
|
||||
// 批量通过
|
||||
$('#batchApproveBtn').click(function () {
|
||||
batchOp('approve', '确定要批量通过选中的评论吗?');
|
||||
});
|
||||
// 批量拒绝
|
||||
$('#batchRejectBtn').click(function () {
|
||||
batchOp('reject', '确定要批量拒绝选中的评论吗?');
|
||||
});
|
||||
// 批量删除
|
||||
$('#batchDeleteBtn').click(function () {
|
||||
batchOp('delete', '确定要删除选中的评论吗?');
|
||||
});
|
||||
|
||||
function batchOp(action, tip) {
|
||||
var checkData = table.checkStatus('commentTable').data;
|
||||
if (! checkData.length) {
|
||||
return layer.msg('请选择评论');
|
||||
}
|
||||
var ids = checkData.map(function (i) { return i.id; });
|
||||
layer.confirm(tip, function (index) {
|
||||
$.post('{:url("blog/backend.comment/batch")}', { action: action, ids: ids }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
|
||||
// 行操作
|
||||
table.on('tool(commentTable)', function (obj) {
|
||||
if (obj.event === 'approve') {
|
||||
$.post('{:url("blog/backend.comment/approve")}', { id: obj.data.id }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
} else if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除这条评论吗?', function (index) {
|
||||
$.post('{:url("blog/backend.comment/delete")}', { id: obj.data.id }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,153 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">控制面板</div>
|
||||
|
||||
<!-- 数据概览 -->
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">文章总数</div>
|
||||
<div class="layui-card-body">
|
||||
<h1 style="color: #1E9FFF; font-size: 28px; margin: 0;">{$stats.article_count}</h1>
|
||||
<p style="margin: 5px 0 0 0; color: #666;">今日新增: {$stats.today_article}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">用户总数</div>
|
||||
<div class="layui-card-body">
|
||||
<h1 style="color: #5FB878; font-size: 28px; margin: 0;">{$stats.user_count}</h1>
|
||||
<p style="margin: 5px 0 0 0; color: #666;">今日新增: {$stats.today_user}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">评论总数</div>
|
||||
<div class="layui-card-body">
|
||||
<h1 style="color: #FFB800; font-size: 28px; margin: 0;">{$stats.comment_count}</h1>
|
||||
<p style="margin: 5px 0 0 0; color: #666;">今日新增: {$stats.today_comment}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">今日访问</div>
|
||||
<div class="layui-card-body">
|
||||
<h1 style="color: #FF5722; font-size: 28px; margin: 0;">{$stats.today_visit}</h1>
|
||||
<p style="margin: 5px 0 0 0; color: #666;">总访问量: {$stats.total_visit}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最新文章 -->
|
||||
<div class="layui-row layui-col-space15" style="margin-top: 20px;">
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">最新文章</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table">
|
||||
<colgroup>
|
||||
<col width="60%">
|
||||
<col width="20%">
|
||||
<col width="20%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>标题</th>
|
||||
<th>作者</th>
|
||||
<th>发布时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{volist name="latestArticles" id="article"}
|
||||
<tr>
|
||||
<td><a href="{:url('blog/backend.article/edit', ['id' => $article.id])}" style="color: #333; text-decoration: none;">{$article.title}</a></td>
|
||||
<td>{$article.author.nickname}</td>
|
||||
<td>{:date('Y-m-d', $article.create_at)}</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最新评论 -->
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">最新评论</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table">
|
||||
<colgroup>
|
||||
<col width="60%">
|
||||
<col width="20%">
|
||||
<col width="20%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>内容</th>
|
||||
<th>用户</th>
|
||||
<th>文章</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{volist name="latestComments" id="comment"}
|
||||
<tr>
|
||||
<td>{$comment.content|mb_substr=0,20}</td>
|
||||
<td>{$comment.user.nickname}</td>
|
||||
<td><a href="{:url('blog/backend.article/edit', ['id' => $comment.article_id])}" style="color: #333; text-decoration: none;">{$comment.article.title|mb_substr=0,20}</a></td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 热门文章 -->
|
||||
<div class="layui-row layui-col-space15" style="margin-top: 20px;">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">热门文章</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table">
|
||||
<colgroup>
|
||||
<col width="5%">
|
||||
<col width="45%">
|
||||
<col width="15%">
|
||||
<col width="15%">
|
||||
<col width="10%">
|
||||
<col width="10%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>排名</th>
|
||||
<th>标题</th>
|
||||
<th>作者</th>
|
||||
<th>分类</th>
|
||||
<th>阅读量</th>
|
||||
<th>点赞数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{volist name="hotArticles" id="article" key="k"}
|
||||
<tr>
|
||||
<td>{$k}</td>
|
||||
<td><a href="{:url('index/article/detail', ['id' => $article.id])}" target="_blank" style="color: #333; text-decoration: none;">{$article.title}</a></td>
|
||||
<td>{$article.author.nickname}</td>
|
||||
<td>{$article.category.name}</td>
|
||||
<td>{$article.view_count}</td>
|
||||
<td>{$article.like_count}</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">博客管理首页</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">欢迎使用</div>
|
||||
<div class="layui-card-body">
|
||||
<p>当前管理员:<strong>{$admin.nickname|default='管理员'}</strong>
|
||||
(账号:{$admin.account|default='-'})</p>
|
||||
<p>这是插件 <code>blog</code> 的后台入口页,对应文件:
|
||||
<code>addon/blog/controller/admin/Index.php</code></p>
|
||||
<a href="{:url('blog/backend.dashboard/index')}" class="layui-btn">前往仪表盘</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">本页链路说明</div>
|
||||
<div class="layui-card-body">
|
||||
<ol>
|
||||
<li>路由:<code>addon/blog/route/app.php</code> 的 admin 分组映射 <code>/blog/backend/</code> → <code>backend.Index/index</code></li>
|
||||
<li>鉴权:admin 分组挂 <code>AdminAuth</code> 中间件,将容器 auth 绑定为 <code>\ywxapp\library\Admin</code> 并强制登录</li>
|
||||
<li>基类:<code>Index extends \ywxapp\controller\AddonBackend</code>,视图目录指向 <code>view/backend/</code></li>
|
||||
<li>模板:经全局 layout(<code>view/layout.html</code>)渲染为完整 HTML,并加载 layui 的 css/js</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,99 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">邮件设置</div>
|
||||
|
||||
<!-- 设置表单 -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{:url('blog/backend.setting/email')}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">SMTP服务器</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="smtp_host" value="{$settings.email.smtp_host}" placeholder="请输入SMTP服务器地址" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">SMTP端口</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="smtp_port" value="{$settings.email.smtp_port}" placeholder="请输入SMTP端口" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱账号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="email" name="smtp_user" value="{$settings.email.smtp_user}" placeholder="请输入邮箱账号" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="smtp_pass" value="{$settings.email.smtp_pass}" placeholder="请输入邮箱密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">发件人名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="from_name" value="{$settings.email.from_name}" placeholder="请输入发件人名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="emailSubmit">保存设置</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="testEmailBtn">测试发送</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function(){
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
|
||||
// 表单提交
|
||||
form.on('submit(emailSubmit)', function(data){
|
||||
$.post(data.form.action, data.field, function(res){
|
||||
if(res.code === 1){
|
||||
layer.msg(res.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 测试发送邮件
|
||||
$('#testEmailBtn').click(function(){
|
||||
var formData = {
|
||||
smtp_host: $('input[name="smtp_host"]').val(),
|
||||
smtp_port: $('input[name="smtp_port"]').val(),
|
||||
smtp_user: $('input[name="smtp_user"]').val(),
|
||||
smtp_pass: $('input[name="smtp_pass"]').val(),
|
||||
from_name: $('input[name="from_name"]').val()
|
||||
};
|
||||
|
||||
if (!formData.smtp_host || !formData.smtp_port || !formData.smtp_user || !formData.smtp_pass) {
|
||||
layer.msg('请填写完整的SMTP配置', {icon: 2});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.load(2);
|
||||
$.post('{:url("blog/backend.setting/testEmail")}', formData, function(res){
|
||||
layer.closeAll('loading');
|
||||
if(res.code === 1){
|
||||
layer.msg(res.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,186 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">系统设置</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="settingTab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">基本设置</li>
|
||||
<li>SEO设置</li>
|
||||
<li>邮件设置</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content" style="padding-top:20px;">
|
||||
|
||||
<!-- 基本设置 -->
|
||||
<div class="layui-tab-item layui-show">
|
||||
<form class="layui-form" action="{:url('blog/backend.setting/site')}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站点名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="site_name" value="{$settings.site.site_name|default=''}" required lay-verify="required" placeholder="请输入站点名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站点描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="site_description" placeholder="请输入站点描述" class="layui-textarea">{$settings.site.site_description|default=''}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站点关键词</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="site_keywords" value="{$settings.site.site_keywords|default=''}" placeholder="请输入站点关键词,多个用逗号分隔" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站长邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="email" name="site_email" value="{$settings.site.site_email|default=''}" placeholder="请输入站长邮箱" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备案号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="site_icp" value="{$settings.site.site_icp|default=''}" placeholder="请输入备案号" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="siteSubmit">保存设置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- SEO设置 -->
|
||||
<div class="layui-tab-item">
|
||||
<form class="layui-form" action="{:url('blog/backend.setting/seo')}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="seo_title" value="{$settings.seo.seo_title|default=''}" placeholder="请输入网站标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站关键词</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="seo_keywords" value="{$settings.seo.seo_keywords|default=''}" placeholder="请输入网站关键词,多个用逗号分隔" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="seo_description" placeholder="请输入网站描述" class="layui-textarea">{$settings.seo.seo_description|default=''}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">百度推送Token</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="baidu_token" value="{$settings.seo.baidu_token|default=''}" placeholder="请输入百度推送Token" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="seoSubmit">保存设置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 邮件设置 -->
|
||||
<div class="layui-tab-item">
|
||||
<form class="layui-form" action="{:url('blog/backend.setting/email')}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">SMTP服务器</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="smtp_host" value="{$settings.email.smtp_host|default=''}" placeholder="请输入SMTP服务器地址" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">SMTP端口</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="smtp_port" value="{$settings.email.smtp_port|default=''}" placeholder="请输入SMTP端口" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱账号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="email" name="smtp_user" value="{$settings.email.smtp_user|default=''}" placeholder="请输入邮箱账号" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="smtp_pass" value="{$settings.email.smtp_pass|default=''}" placeholder="请输入邮箱密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">发件人名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="from_name" value="{$settings.email.from_name|default=''}" placeholder="请输入发件人名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="emailSubmit">保存设置</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="testEmailBtn">测试发送</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['form', 'element', 'layer'], function(){
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
|
||||
// 通用表单提交
|
||||
function bindSubmit(filter){
|
||||
form.on('submit(' + filter + ')', function(data){
|
||||
$.post(data.form.action, data.field, function(res){
|
||||
if(res.code === 1){
|
||||
layer.msg(res.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
bindSubmit('siteSubmit');
|
||||
bindSubmit('seoSubmit');
|
||||
bindSubmit('emailSubmit');
|
||||
|
||||
// 测试发送邮件
|
||||
$('#testEmailBtn').click(function(){
|
||||
var formData = {
|
||||
smtp_host: $('input[name="smtp_host"]').val(),
|
||||
smtp_port: $('input[name="smtp_port"]').val(),
|
||||
smtp_user: $('input[name="smtp_user"]').val(),
|
||||
smtp_pass: $('input[name="smtp_pass"]').val(),
|
||||
from_name: $('input[name="from_name"]').val()
|
||||
};
|
||||
if (!formData.smtp_host || !formData.smtp_port || !formData.smtp_user || !formData.smtp_pass) {
|
||||
layer.msg('请填写完整的SMTP配置', {icon: 2});
|
||||
return;
|
||||
}
|
||||
layer.load(2);
|
||||
$.post('{:url("blog/backend.setting/testEmail")}', formData, function(res){
|
||||
layer.closeAll('loading');
|
||||
if(res.code === 1){
|
||||
layer.msg(res.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">SEO设置</div>
|
||||
|
||||
<!-- 设置表单 -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{:url('blog/backend.setting/seo')}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="seo_title" value="{$settings.seo.seo_title}" placeholder="请输入网站标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站关键词</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="seo_keywords" value="{$settings.seo.seo_keywords}" placeholder="请输入网站关键词,多个用逗号分隔" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="seo_description" placeholder="请输入网站描述" class="layui-textarea">{$settings.seo.seo_description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">百度推送Token</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="baidu_token" value="{$settings.seo.baidu_token}" placeholder="请输入百度推送Token" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="seoSubmit">保存设置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['form'], function(){
|
||||
var form = layui.form;
|
||||
|
||||
// 表单提交
|
||||
form.on('submit(seoSubmit)', function(data){
|
||||
$.post(data.form.action, data.field, function(res){
|
||||
if(res.code === 1){
|
||||
layer.msg(res.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">基本设置</div>
|
||||
|
||||
<!-- 设置表单 -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{:url('blog/backend.setting/site')}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站点名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="site_name" value="{$settings.site.site_name}" required lay-verify="required" placeholder="请输入站点名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站点描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="site_description" placeholder="请输入站点描述" class="layui-textarea">{$settings.site.site_description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站点关键词</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="site_keywords" value="{$settings.site.site_keywords}" placeholder="请输入站点关键词,多个用逗号分隔" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">站长邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="email" name="site_email" value="{$settings.site.site_email}" placeholder="请输入站长邮箱" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备案号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="site_icp" value="{$settings.site.site_icp}" placeholder="请输入备案号" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">主题色</label>
|
||||
<div class="layui-input-block" style="display:flex;align-items:center;gap:12px;">
|
||||
<input type="color" name="theme_color" value="{$settings.site.theme_color|default='#2d6cdf'}" style="width:46px;height:38px;border:1px solid #eee;border-radius:6px;padding:2px;cursor:pointer;">
|
||||
<input type="text" name="theme_color_text" id="themeColorText" value="{$settings.site.theme_color|default='#2d6cdf'}" placeholder="#2d6cdf" class="layui-input" style="max-width:160px;">
|
||||
<span class="layui-form-mid" style="color:#999;">前台主题色(顶部导航/按钮/底部Tab等)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="siteSubmit">保存设置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['form'], function(){
|
||||
var form = layui.form, $ = layui.$;
|
||||
|
||||
// 颜色选择器 <-> 文本框 双向同步
|
||||
$('input[name="theme_color"]').on('input', function(){
|
||||
$('#themeColorText').val(this.value);
|
||||
});
|
||||
$('#themeColorText').on('input', function(){
|
||||
var v = $.trim(this.value);
|
||||
if (/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(v)) {
|
||||
$('input[name="theme_color"]').val(v);
|
||||
}
|
||||
});
|
||||
|
||||
// 表单提交(统一使用文本框的值为最终主题色)
|
||||
form.on('submit(siteSubmit)', function(data){
|
||||
data.field.theme_color = $('#themeColorText').val() || data.field.theme_color;
|
||||
$.post(data.form.action, data.field, function(res){
|
||||
if(res.code === 1){
|
||||
layer.msg(res.msg, {icon: 1});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,120 @@
|
||||
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">统计分析</div>
|
||||
|
||||
<!-- 时间范围选择 -->
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" id="statForm">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">时间范围</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="range" lay-filter="range">
|
||||
<option value="week" {if $range=='week'}selected{/if}>近7天</option>
|
||||
<option value="month" {if $range=='month'}selected{/if}>近30天</option>
|
||||
<option value="year" {if $range=='year'}selected{/if}>近1年</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<div class="layui-row layui-col-space15" style="margin-top: 20px;">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">总访问量</div>
|
||||
<div class="layui-card-body">
|
||||
<h1 style="color: #1E9FFF; font-size: 28px; margin: 0;">{$stats.total_visit}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">今日访问</div>
|
||||
<div class="layui-card-body">
|
||||
<h1 style="color: #5FB878; font-size: 28px; margin: 0;">{$stats.today_visit}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">总用户数</div>
|
||||
<div class="layui-card-body">
|
||||
<h1 style="color: #FFB800; font-size: 28px; margin: 0;">{$stats.total_user}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">总文章数</div>
|
||||
<div class="layui-card-body">
|
||||
<h1 style="color: #FF5722; font-size: 28px; margin: 0;">{$stats.total_article}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 热门文章 -->
|
||||
<div class="layui-row layui-col-space15" style="margin-top: 20px;">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">热门文章</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table">
|
||||
<colgroup>
|
||||
<col width="5%">
|
||||
<col width="45%">
|
||||
<col width="15%">
|
||||
<col width="15%">
|
||||
<col width="10%">
|
||||
<col width="10%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>排名</th>
|
||||
<th>标题</th>
|
||||
<th>作者</th>
|
||||
<th>分类</th>
|
||||
<th>阅读量</th>
|
||||
<th>点赞数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{volist name="hotArticles" id="article" key="k"}
|
||||
<tr>
|
||||
<td>{$k}</td>
|
||||
<td><a href="{:url('index/article/detail', ['id' => $article.id])}" target="_blank">{$article.title}</a></td>
|
||||
<td>{$article.author.nickname}</td>
|
||||
<td>{$article.category.name}</td>
|
||||
<td>{$article.view_count}</td>
|
||||
<td>{$article.like_count}</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['form'], function(){
|
||||
var form = layui.form;
|
||||
var $ = layui.$;
|
||||
|
||||
// 时间范围筛选
|
||||
form.on('select(range)', function(data){
|
||||
location.href = '{:url("blog/backend.stat/index")}?range=' + data.value;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">添加标签</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{:url('blog/backend.tag/save')}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标签名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" required lay-verify="required" placeholder="请输入标签名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标签描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入标签描述" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="tagSubmit">添加标签</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">编辑标签</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{:url('blog/backend.tag/update', ['id' => $tag.id])}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标签名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" value="{$tag.name}" required lay-verify="required" placeholder="请输入标签名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标签描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入标签描述" class="layui-textarea">{$tag.description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="tagSubmit">更新标签</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,164 @@
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="admin-title">标签管理</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="table-toolbar" style="margin-bottom:15px;">
|
||||
<button type="button" class="layui-btn layui-btn-normal" id="addTagBtn">添加标签</button>
|
||||
<button type="button" class="layui-btn layui-btn-danger" id="batchDeleteBtn">批量删除</button>
|
||||
</div>
|
||||
<table class="layui-hide" id="tagTable" lay-filter="tagTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 行操作 -->
|
||||
<script type="text/html" id="rowTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete">删除</a>
|
||||
</script>
|
||||
|
||||
<!-- 新增/编辑 表单模板(弹窗内渲染) -->
|
||||
<script type="text/html" id="tagFormTpl">
|
||||
<div style="padding:15px;">
|
||||
<form class="layui-form" lay-filter="tagForm">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标签名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" value="{{ d.name || '' }}" required lay-verify="required" placeholder="请输入标签名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标签描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入标签描述" class="layui-textarea">{{ d.description || '' }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="tagFormSubmit" id="tagFormSubmit">保存</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="cancelBtn">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['table', 'layer', 'form', 'laytpl', 'http'], function () {
|
||||
var table = layui.table;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
var form = layui.form;
|
||||
var laytpl = layui.laytpl;
|
||||
var http = layui.http;
|
||||
|
||||
var renderTable = function () {
|
||||
table.render({
|
||||
elem: '#tagTable',
|
||||
url: '{:url("blog/backend.tag/index")}',
|
||||
page: true,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||||
{ field: 'name', title: '标签名称', minWidth: 160 },
|
||||
{ field: 'description', title: '描述', minWidth: 160, templet: function (d) { return d.description || '-'; } },
|
||||
{ field: 'articles_count', title: '文章数', width: 100 },
|
||||
{ field: 'create_text', title: '创建时间', width: 130 },
|
||||
{ title: '操作', width: 130, align: 'center', toolbar: '#rowTpl', fixed: 'right' }
|
||||
]]
|
||||
});
|
||||
};
|
||||
renderTable();
|
||||
|
||||
// 新增 / 编辑 弹窗
|
||||
function openForm(data) {
|
||||
data = data || {};
|
||||
var formHtml = laytpl($('#tagFormTpl').html()).render(data);
|
||||
layer.open({
|
||||
title: data.id ? '编辑标签' : '添加标签',
|
||||
content: formHtml,
|
||||
anim: 'slideLeft',
|
||||
offset: 'r',
|
||||
area: ['480px', '98%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['保存', '取消'],
|
||||
success: function () {
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
layero.contents().find('#tagFormSubmit').trigger('click');
|
||||
},
|
||||
btn2: function (index) { layer.close(index); }
|
||||
});
|
||||
}
|
||||
|
||||
// 表单提交:仅绑定一次
|
||||
form.on('submit(tagFormSubmit)', function (elem) {
|
||||
var field = elem.field;
|
||||
var isEdit = !!field.id;
|
||||
var url = isEdit
|
||||
? '{:url("blog/backend.tag/update")}'
|
||||
: '{:url("blog/backend.tag/save")}';
|
||||
var postData = $.extend({}, field);
|
||||
if (isEdit) { postData.id = field.id; }
|
||||
http.post(url, postData).then(function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.closeAll('dialog');
|
||||
layer.msg(res.msg, { icon: 1 });
|
||||
setTimeout(function () { renderTable(); }, 500);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败', { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () { layer.msg('请求失败,请重试', { icon: 2 }); }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 添加标签
|
||||
$('#addTagBtn').click(function () {
|
||||
openForm({});
|
||||
});
|
||||
|
||||
// 批量删除
|
||||
$('#batchDeleteBtn').click(function () {
|
||||
var checkData = table.checkStatus('tagTable').data;
|
||||
if (! checkData.length) {
|
||||
return layer.msg('请选择要删除的标签');
|
||||
}
|
||||
var ids = checkData.map(function (i) { return i.id; });
|
||||
layer.confirm('确定要删除选中的 ' + ids.length + ' 个标签吗?', function (index) {
|
||||
$.post('{:url("blog/backend.tag/batchDelete")}', { ids: ids }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
});
|
||||
|
||||
// 行操作
|
||||
table.on('tool(tagTable)', function (obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'edit') {
|
||||
openForm(data);
|
||||
} else if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除这个标签吗?', function (index) {
|
||||
$.post('{:url("blog/backend.tag/delete")}', { id: data.id }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="admin-title">编辑用户</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="userForm" style="max-width: 600px; margin-top: 20px;">
|
||||
<input type="hidden" name="id" value="{$user.uid}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">账号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" class="layui-input" value="{$user.account}" disabled>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="nickname" value="{$user.nickname}" placeholder="请输入昵称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="email" value="{$user.email}" placeholder="请输入邮箱" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="mobile" value="{$user.mobile}" placeholder="请输入手机号" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="正常" {if $user.status == 1}checked{/if}>
|
||||
<input type="radio" name="status" value="0" title="禁用" {if $user.status == 0}checked{/if}>
|
||||
<input type="radio" name="status" value="-1" title="删除" {if $user.status == -1}checked{/if}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="userFormSubmit">保存</button>
|
||||
<a class="layui-btn layui-btn-primary" href="{:url('blog/backend.user/index')}">返回</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['form', 'layer', 'http'], function () {
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
var http = layui.http;
|
||||
|
||||
form.on('submit(userFormSubmit)', function (elem) {
|
||||
var field = elem.field;
|
||||
http.post('{:url("blog/backend.user/update")}', field).then(function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () {
|
||||
location.href = '{:url("blog/backend.user/index")}';
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败', { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () { layer.msg('请求失败,请重试', { icon: 2 }); }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,115 @@
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="admin-title">用户管理</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form layui-inline" lay-filter="searchForm">
|
||||
<div class="layui-inline">
|
||||
<select name="status">
|
||||
<option value="all">全部状态</option>
|
||||
<option value="1">正常</option>
|
||||
<option value="0">禁用</option>
|
||||
<option value="-1">删除</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="keyword" placeholder="搜索账号/昵称/邮箱/手机号" class="layui-input" id="keywordInput">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-primary" lay-submit lay-filter="search">搜索</button>
|
||||
</div>
|
||||
<button type="button" class="layui-btn layui-btn-danger" id="batchDeleteBtn">批量删除</button>
|
||||
</form>
|
||||
<table class="layui-hide" id="userTable" lay-filter="userTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="rowTpl">
|
||||
<a class="layui-btn layui-btn-xs" href="{{ d.edit_url }}">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete">删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['table', 'layer', 'form'], function () {
|
||||
var table = layui.table;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var $ = layui.$;
|
||||
|
||||
var status = '{$status|default="all"}';
|
||||
var keyword = '{$keyword|default=""}';
|
||||
$('select[name="status"]').val(status);
|
||||
$('#keywordInput').val(keyword);
|
||||
|
||||
var renderTable = function () {
|
||||
table.render({
|
||||
elem: '#userTable',
|
||||
url: '{:url("blog/backend.user/index")}',
|
||||
where: { status: status, keyword: keyword },
|
||||
page: true,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'uid', title: 'UID', width: 80, sort: true },
|
||||
{ field: 'account', title: '账号', width: 140 },
|
||||
{ field: 'nickname', title: '昵称', width: 140 },
|
||||
{ field: 'email', title: '邮箱', minWidth: 160 },
|
||||
{ field: 'mobile', title: '手机号', width: 130 },
|
||||
{ field: 'article_count', title: '文章数', width: 90, sort: true, align: 'center' },
|
||||
{ field: 'status_text', title: '状态', width: 90, templet: function (d) {
|
||||
var map = { '正常': 'layui-bg-green', '禁用': 'layui-bg-gray', '删除': 'layui-bg-red' };
|
||||
var cls = map[d.status_text] || 'layui-bg-gray';
|
||||
return '<span class="layui-badge ' + cls + '">' + d.status_text + '</span>';
|
||||
} },
|
||||
{ field: 'create_at', title: '注册时间', width: 160 },
|
||||
{ field: 'update_at', title: '最后登录', width: 160 },
|
||||
{ title: '操作', width: 130, align: 'center', toolbar: '#rowTpl', fixed: 'right' }
|
||||
]]
|
||||
});
|
||||
};
|
||||
renderTable();
|
||||
|
||||
// 搜索
|
||||
form.on('submit(search)', function () {
|
||||
var statusVal = $('select[name="status"]').val();
|
||||
var kw = $('#keywordInput').val();
|
||||
table.reload('userTable', { where: { status: statusVal, keyword: kw }, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
|
||||
// 批量删除
|
||||
$('#batchDeleteBtn').click(function () {
|
||||
var checkData = table.checkStatus('userTable').data;
|
||||
if (! checkData.length) {
|
||||
return layer.msg('请选择要删除的用户');
|
||||
}
|
||||
var ids = checkData.map(function (i) { return i.uid; });
|
||||
layer.confirm('确定要删除选中的 ' + ids.length + ' 个用户吗?', function (index) {
|
||||
$.post('{:url("blog/backend.user/batch")}', { ids: ids }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
});
|
||||
|
||||
// 行操作
|
||||
table.on('tool(userTable)', function (obj) {
|
||||
if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除该用户吗?', function (index) {
|
||||
$.post('{:url("blog/backend.user/delete")}', { id: obj.data.uid }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,52 @@
|
||||
{extend name="layout" /}
|
||||
{block name="title"}{$author.nickname} 的个人博客 - {$siteConf.site_name|default='博客'}{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="fb-layout">
|
||||
<main class="fb-content">
|
||||
<!-- 个人资料卡 -->
|
||||
<div class="fb-card" style="display:flex;align-items:center;gap:18px;margin-bottom:18px;">
|
||||
<img src="{$avatar}" alt="{$author.nickname}" style="width:72px;height:72px;border-radius:50%;object-fit:cover;border:2px solid var(--theme);">
|
||||
<div>
|
||||
<h2 style="margin:0 0 6px;font-size:20px;color:var(--text);">{$author.nickname}</h2>
|
||||
<p style="margin:0 0 8px;color:var(--text-2);font-size:13px;">{$author.bio|default='这个人很懒,什么都没留下~'}</p>
|
||||
<p style="margin:0;font-size:13px;color:var(--text-3);">
|
||||
<span style="margin-right:16px;">文章 <b style="color:var(--theme);">{$stats.articles}</b></span>
|
||||
<span style="margin-right:16px;">阅读 <b style="color:var(--theme);">{$stats.views}</b></span>
|
||||
<span style="margin-right:16px;">获赞 <b style="color:var(--theme);">{$stats.likes}</b></span>
|
||||
<span>加入于 {$author_join}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fb-section-title"><h2>他的文章({$articles->total()} 篇)</h2></div>
|
||||
|
||||
{if $articles->isEmpty()}
|
||||
<div class="fb-empty"><p>该用户暂无已发布文章。</p></div>
|
||||
{else}
|
||||
<div class="fb-post-list">
|
||||
{volist name="articles" id="article"}
|
||||
<article class="fb-post">
|
||||
{if $article.cover_image}
|
||||
<a class="thumb" href="{:url('blog/article/detail', ['id' => $article.id])}">
|
||||
<img src="{$article.cover_image}" alt="{$article.title}">
|
||||
</a>
|
||||
{/if}
|
||||
<div class="body">
|
||||
<span class="cat">{$article.category.name|default='默认'}</span>
|
||||
<h3><a href="{:url('blog/article/detail', ['id' => $article.id])}">{$article.title}</a></h3>
|
||||
<p class="summary">{$article.summary|default='(暂无描述)'}</p>
|
||||
<div class="meta">
|
||||
<span class="sp">{$article.create_text}</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/volist}
|
||||
</div>
|
||||
<div class="fb-pager">{$articles|raw}</div>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
{include file="index/_sidebar" /}
|
||||
</div>
|
||||
{/block}
|
||||
@@ -0,0 +1,159 @@
|
||||
{extend name="layout" /}
|
||||
{block name="title"}{$article.title} - {$siteConf.site_name|default='博客'}{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="fb-layout">
|
||||
<main class="fb-content">
|
||||
<!-- 文章正文 -->
|
||||
<article class="fb-article">
|
||||
<div class="crumb">博文 > <a href="{:url('blog/category', ['id' => $article.cid])}">{$article.category.name|default='默认'}</a></div>
|
||||
<h1>{$article.title}</h1>
|
||||
<div class="post-meta">
|
||||
<a class="author" href="{:url('blog/article/author', ['id' => $article.uid])}">
|
||||
<img src="{$article.user.avatar|default='/static/blog/img/avatar.jpg'}" alt="">
|
||||
{$article.user.nickname|default='佚名'}
|
||||
</a>
|
||||
<span><i class="layui-icon layui-icon-read"></i> {$article.view_count|default=0}</span>
|
||||
<span>{$article.create_text}</span>
|
||||
</div>
|
||||
{if $article.cover_image}
|
||||
<div class="cover"><img src="{$article.cover_image}" alt="{$article.title}"></div>
|
||||
{/if}
|
||||
<div class="content">{$article.content|raw}</div>
|
||||
<div class="action-bar">
|
||||
<button type="button" class="fb-btn like-btn" data-id="{$article.id}"><i class="layui-icon layui-icon-praise"></i> 点赞 (<span id="likeCount">{$article.like_count}</span>)</button>
|
||||
<button type="button" class="fb-btn ghost fav-btn" data-id="{$article.id}"><i class="layui-icon layui-icon-star"></i> 收藏 (<span id="favCount">{$article.favorite_count}</span>)</button>
|
||||
<button type="button" class="fb-btn ghost share-btn"><i class="layui-icon layui-icon-share"></i> 分享</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- 评论区 -->
|
||||
<section class="fb-comments">
|
||||
<p class="ct-title">全部留言 <em id="count">{$article.comment_count}</em></p>
|
||||
|
||||
{if $is_login}
|
||||
<div class="fb-cmt-form">
|
||||
<textarea id="LAY-msg-content" placeholder="既然来了,就说几句吧" style="resize:none;"></textarea>
|
||||
<div style="margin-top:10px;display:flex;align-items:center;gap:10px;">
|
||||
<button class="fb-btn" type="button" id="item-btn">发表留言</button>
|
||||
<span class="reply-tip" id="replyTip" style="display:none;color:var(--theme);"></span>
|
||||
<button class="fb-btn ghost" type="button" id="cancelReply" style="display:none;">取消回复</button>
|
||||
</div>
|
||||
</div>
|
||||
{else /}
|
||||
<div style="padding:10px 0;color:var(--text-3);">请 <a href="{:url('auth/login')}" style="color:var(--theme);">登录</a> 后发表留言</div>
|
||||
{/if}
|
||||
|
||||
<ul class="fb-cmt-list" id="LAY-msg-box" style="list-style:none;margin:0;padding:0;">
|
||||
{volist name="comments" id="comment"}
|
||||
<li class="fb-cmt-item" data-id="{$comment.id}">
|
||||
<img src="{$comment.user.avatar|default='/static/blog/img/portrait.jpg'}" alt="">
|
||||
<div class="ci-body">
|
||||
<p style="margin:0;">
|
||||
<span class="ci-name">{$comment.user.nickname|default='佚名'}</span>
|
||||
<span class="ci-time">{$comment.create_text}</span>
|
||||
{if $is_login}<span class="ci-reply" data-id="{$comment.id}" data-name="{$comment.user.nickname}">回复</span>{/if}
|
||||
</p>
|
||||
<p class="ci-text">{$comment.content}</p>
|
||||
<ul class="fb-cmt-children">
|
||||
{volist name="comment.children" id="child"}
|
||||
<li data-id="{$child.id}">
|
||||
<img src="{$child.user.avatar|default='/static/blog/img/portrait.jpg'}" alt="">
|
||||
<div class="ci-body">
|
||||
<p style="margin:0;">
|
||||
<span class="ci-name">{$child.user.nickname|default='佚名'}</span>
|
||||
<span class="ci-time">{$child.create_text}</span>
|
||||
{if $is_login}<span class="ci-reply" data-id="{$comment.id}" data-name="{$comment.user.nickname}">回复</span>{/if}
|
||||
</p>
|
||||
<p class="ci-text">{$child.content}</p>
|
||||
</div>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
<div class="fb-pager">{$comments|raw}</div>
|
||||
</section>
|
||||
|
||||
<!-- 相关文章推荐 -->
|
||||
{if !empty($relatedArticles)}
|
||||
<section class="fb-related">
|
||||
<p class="ct-title">相关推荐</p>
|
||||
<ul class="fb-related-list">
|
||||
{volist name="relatedArticles" id="ra"}
|
||||
<li><a href="{:url('blog/article/detail', ['id' => $ra.id])}">{$ra.title}</a><span>{$ra.category.name|default=''}</span></li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</section>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
{include file="index/_sidebar" /}
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name="script"}
|
||||
<script>
|
||||
layui.use(['layer', 'jquery'], function(){
|
||||
var layer = layui.layer, $ = layui.$;
|
||||
$('.like-btn').click(function(){
|
||||
var id = $(this).data('id');
|
||||
$.post('{:url("interaction/like")}', { article_id: id }, function(res){
|
||||
if(res.code===1){ $('#likeCount').text(res.count); layer.msg(res.msg,{icon:1}); } else { layer.msg(res.msg,{icon:2}); }
|
||||
});
|
||||
});
|
||||
$('.fav-btn').click(function(){
|
||||
var id = $(this).data('id');
|
||||
$.post('{:url("interaction/favorite")}', { article_id: id }, function(res){
|
||||
if(res.code===1){ $('#favCount').text(res.count); layer.msg(res.msg,{icon:1}); } else { layer.msg(res.msg,{icon:2}); }
|
||||
});
|
||||
});
|
||||
$('.share-btn').click(function(){
|
||||
layer.open({ title:'分享文章', content:'<div style="padding:10px;"><input type="text" value="'+window.location.href+'" class="layui-input" readonly></div>', area:['500px','200px'] });
|
||||
$.post('{:url("interaction/share")}', { article_id: {$article.id} });
|
||||
});
|
||||
|
||||
// ===== 留言 / 回复 =====
|
||||
var replyTo = 0;
|
||||
$(document).on('click', '.ci-reply', function(){
|
||||
if(!$('#LAY-msg-content').length){ return; }
|
||||
replyTo = $(this).data('id');
|
||||
var name = $(this).data('name');
|
||||
$('#replyTip').text('回复 @' + name).show();
|
||||
$('#cancelReply').show();
|
||||
$('#LAY-msg-content').attr('placeholder', '回复 @' + name);
|
||||
$('#LAY-msg-content').focus();
|
||||
$('html,body').animate({ scrollTop: $('.fb-cmt-form').offset().top - 20 }, 300);
|
||||
});
|
||||
$('#cancelReply').on('click', function(){
|
||||
replyTo = 0;
|
||||
$('#replyTip').hide().text('');
|
||||
$(this).hide();
|
||||
$('#LAY-msg-content').attr('placeholder', '既然来了,就说几句吧').val('');
|
||||
});
|
||||
$('#item-btn').on('click', function(){
|
||||
var content = $('#LAY-msg-content').val();
|
||||
if(content.replace(/\s/g,'')==''){ layer.msg('请先输入留言内容'); return; }
|
||||
$.post('{:url("comment/add")}', { article_id: {$article.id}, parent_id: replyTo, content: content }, function(res){
|
||||
if(res.code===1){
|
||||
var d = res.data;
|
||||
var avatar = d.user.avatar || '/static/blog/img/portrait.jpg';
|
||||
if(replyTo > 0){
|
||||
var html = '<li data-id="'+d.id+'"><img src="'+avatar+'"><div class="ci-body"><p style="margin:0;"><span class="ci-name">'+d.user.nickname+'</span><span class="ci-time">'+d.create_text+'</span> <span class="ci-reply" data-id="'+replyTo+'" data-name="'+d.user.nickname+'">回复</span></p><p class="ci-text">'+d.content+'</p></div></li>';
|
||||
$('.fb-cmt-item[data-id="'+replyTo+'"] > .ci-body > .fb-cmt-children').prepend(html);
|
||||
} else {
|
||||
var html = '<li class="fb-cmt-item" data-id="'+d.id+'"><img src="'+avatar+'"><div class="ci-body"><p style="margin:0;"><span class="ci-name">'+d.user.nickname+'</span><span class="ci-time">'+d.create_text+'</span> <span class="ci-reply" data-id="'+d.id+'" data-name="'+d.user.nickname+'">回复</span></p><p class="ci-text">'+d.content+'</p><ul class="fb-cmt-children"></ul></div></li>';
|
||||
$('#LAY-msg-box').prepend(html);
|
||||
}
|
||||
$('#LAY-msg-content').val('');
|
||||
$('#count').text((parseInt($('#count').text())||0) + 1);
|
||||
replyTo = 0; $('#replyTip').hide(); $('#cancelReply').hide();
|
||||
layer.msg(res.msg,{icon:1});
|
||||
} else { layer.msg(res.msg,{icon:2}); }
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,47 @@
|
||||
{extend name="layout" /}
|
||||
{block name="title"}文章列表 - {$siteConf.site_name|default='博客'}{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="fb-layout">
|
||||
<main class="fb-content">
|
||||
<div class="fb-section-title"><h2>全部文章</h2></div>
|
||||
{if $articles->isEmpty()}
|
||||
<div class="fb-empty"><p>站点还没有发布文章,敬请期待。</p></div>
|
||||
{else}
|
||||
<div class="fb-post-list">
|
||||
{volist name="articles" id="article"}
|
||||
<article class="fb-post">
|
||||
{if $article.cover_image}
|
||||
<a class="thumb" href="{:url('blog/article/detail', ['id' => $article.id])}">
|
||||
<img src="{$article.cover_image}" alt="{$article.title}">
|
||||
</a>
|
||||
{/if}
|
||||
<div class="body">
|
||||
<span class="cat">{$article.category.name|default='默认'}</span>
|
||||
<h3><a href="{:url('blog/article/detail', ['id' => $article.id])}">{$article.title}</a></h3>
|
||||
<p class="summary">{$article.summary|default='(暂无描述)'}</p>
|
||||
<div class="article-stats" style="margin:2px 0 10px;color:#999;font-size:13px;">
|
||||
<span style="margin-right:12px;"><i class="layui-icon layui-icon-read"></i> {$article.view_count|default=0} 阅读</span>
|
||||
<span style="margin-right:12px;"><i class="layui-icon layui-icon-praise"></i> {$article.like_count|default=0} 点赞</span>
|
||||
<span style="margin-right:12px;"><i class="layui-icon layui-icon-star"></i> {$article.favorite_count|default=0} 收藏</span>
|
||||
<span style="margin-right:12px;"><i class="layui-icon layui-icon-reply"></i> {$article.comment_count|default=0} 评论</span>
|
||||
<span><i class="layui-icon layui-icon-share"></i> {$article.share_count|default=0} 分享</span>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<a class="author" href="{:url('blog/article/author', ['id' => $article.uid])}">
|
||||
<img src="{$article.user.avatar|default='/static/blog/img/avatar.jpg'}" alt="">
|
||||
{$article.user.nickname|default='佚名'}
|
||||
</a>
|
||||
<span class="sp">{$article.create_text}</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/volist}
|
||||
</div>
|
||||
<div class="fb-pager">{$articles|raw}</div>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
{include file="index/_sidebar" /}
|
||||
</div>
|
||||
{/block}
|
||||
@@ -0,0 +1,52 @@
|
||||
{extend name="layout" /}
|
||||
{assign name="nav_active" value="category"/}
|
||||
{block name="title"}{$category.name|default='全部分类'} - {$siteConf.site_name|default='博客'}{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="fb-layout">
|
||||
<main class="fb-content">
|
||||
{if $category}
|
||||
<div class="fb-section-title"><h2>{$category.name}</h2></div>
|
||||
{if $articles->isEmpty()}
|
||||
<div class="fb-empty"><p>该分类下暂无文章。</p></div>
|
||||
{else}
|
||||
<div class="fb-post-list">
|
||||
{volist name="articles" id="article"}
|
||||
<article class="fb-post">
|
||||
{if $article.cover_image}
|
||||
<a class="thumb" href="{:url('blog/article/detail', ['id' => $article.id])}">
|
||||
<img src="{$article.cover_image}" alt="{$article.title}">
|
||||
</a>
|
||||
{/if}
|
||||
<div class="body">
|
||||
<span class="cat">{$article.category.name|default='默认'}</span>
|
||||
<h3><a href="{:url('blog/article/detail', ['id' => $article.id])}">{$article.title}</a></h3>
|
||||
<p class="summary">{$article.summary|default='(暂无描述)'}</p>
|
||||
<div class="meta">
|
||||
<a class="author" href="{:url('blog/article/author', ['id' => $article.uid])}">
|
||||
<img src="{$article.user.avatar|default='/static/blog/img/avatar.jpg'}" alt="">
|
||||
{$article.user.nickname|default='佚名'}
|
||||
</a>
|
||||
<span class="sp">{$article.create_text}</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/volist}
|
||||
</div>
|
||||
<div class="fb-pager">{$articles|raw}</div>
|
||||
{/if}
|
||||
{else}
|
||||
<div class="fb-section-title"><h2>全部分类</h2></div>
|
||||
<div class="fb-card">
|
||||
<ul class="fb-catlist">
|
||||
{volist name="categories" id="c"}
|
||||
<li><a href="{:url('blog/category', ['id' => $c.id])}">{$c.name}<span class="cnt">{$c.card_count|default=0}</span></a></li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
{include file="index/_sidebar" /}
|
||||
</div>
|
||||
{/block}
|
||||
@@ -0,0 +1,48 @@
|
||||
<!-- 右侧栏:热门文章 / 分类 / 标签云 / 最新评论(前台共用 fb-aside 风格) -->
|
||||
<aside class="fb-aside">
|
||||
<div class="fb-widget">
|
||||
<h4>热门文章</h4>
|
||||
<ul class="fb-hot">
|
||||
{volist name="hotArticles" id="a"}
|
||||
<li>
|
||||
<span class="rank">{$i}</span>
|
||||
<a href="{:url('blog/article/detail', ['id' => $a.id])}">{$a.title}</a>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="fb-widget">
|
||||
<h4>文章分类</h4>
|
||||
<ul class="fb-catlist">
|
||||
{volist name="categories" id="c"}
|
||||
<li><a href="{:url('blog/category/index', ['id' => $c.id])}">{$c.name}<span class="cnt">{$c.card_count|default=0}</span></a></li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="fb-widget">
|
||||
<h4>标签云</h4>
|
||||
<div class="fb-tagcloud">
|
||||
{volist name="tags" id="t"}
|
||||
<a href="{:url('blog/tag/index', ['id' => $t.id])}">{$t.name}</a>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{notempty name="latestComments"}
|
||||
{if !$latestComments->isEmpty()}
|
||||
<div class="fb-widget">
|
||||
<h4>最新评论</h4>
|
||||
<ul class="fb-cmt">
|
||||
{volist name="latestComments" id="cmt"}
|
||||
<li>
|
||||
<span class="who">{$cmt.user.nickname|default='匿名'}</span>:
|
||||
<span class="txt">{$cmt.content}</span>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
{/notempty}
|
||||
</aside>
|
||||
@@ -0,0 +1,22 @@
|
||||
{extend name="layout" /}
|
||||
{assign name="nav_active" value="about"/}
|
||||
{block name="title"}关于我们 - {$siteConf.site_name|default='博客'}{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="fb-layout">
|
||||
<main class="fb-content">
|
||||
<div class="fb-page">
|
||||
<h3>关于我们</h3>
|
||||
<img src="/static/blog/img/portrait.jpg" alt="" style="width:96px;height:96px;border-radius:50%;margin:0 0 16px;border:3px solid var(--theme);">
|
||||
<p class="lead">TP-Blog 是一个基于 ThinkPHP 8 开发的现代化博客系统,致力于提供简洁、高效、安全的博客解决方案。</p>
|
||||
<h3>技术栈</h3>
|
||||
<div class="layui-progress layui-progress-big" lay-showpercent="true" style="margin-bottom:10px;"><em>PHP</em><div class="layui-progress-bar" lay-percent="80%"></div></div>
|
||||
<div class="layui-progress layui-progress-big" lay-showpercent="true" style="margin-bottom:10px;"><em>MySQL</em><div class="layui-progress-bar layui-bg-blue" lay-percent="70%"></div></div>
|
||||
<div class="layui-progress layui-progress-big" lay-showpercent="true"><em>Layui</em><div class="layui-progress-bar layui-bg-orange" lay-percent="90%"></div></div>
|
||||
<h3 style="margin-top:18px;">联系我们</h3>
|
||||
<p>邮箱:admin@example.com<br/>GitHub:https://github.com/yourname/tp-blog</p>
|
||||
</div>
|
||||
</main>
|
||||
{include file="index/_sidebar" /}
|
||||
</div>
|
||||
{/block}
|
||||
@@ -0,0 +1,47 @@
|
||||
{extend name="layout" /}
|
||||
{block name="title"}联系我们 - {$siteConf.site_name|default='博客'}{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="fb-layout">
|
||||
<main class="fb-content">
|
||||
<div class="fb-page">
|
||||
<h3>联系我们</h3>
|
||||
<p>邮箱:admin@example.com</p>
|
||||
<p>工作时间:周一至周五 9:00-18:00</p>
|
||||
<form class="layui-form" onsubmit="return false;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">姓名</label>
|
||||
<div class="layui-input-block"><input type="text" name="name" required lay-verify="required" placeholder="请输入您的姓名" class="layui-input"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-block"><input type="text" name="email" required lay-verify="required|email" placeholder="请输入您的邮箱" class="layui-input"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">留言</label>
|
||||
<div class="layui-input-block"><textarea name="message" required lay-verify="required" placeholder="请输入您的留言" class="layui-textarea"></textarea></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="fb-btn" lay-submit lay-filter="contactSubmit">提交留言</button>
|
||||
<button type="reset" class="fb-btn ghost">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
{include file="index/_sidebar" /}
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name="script"}
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function(){
|
||||
var form = layui.form, layer = layui.layer;
|
||||
form.on('submit(contactSubmit)', function(){
|
||||
layer.msg('感谢您的留言,我们会尽快与您联系!');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,124 @@
|
||||
{extend name="layout" /}
|
||||
{block name="title"}{$siteConf.site_name|default='博客'} - 首页{/block}
|
||||
|
||||
{block name="content"}
|
||||
<!-- Hero 推荐 -->
|
||||
{notempty name="recommendedArticles"}
|
||||
{if !$recommendedArticles->isEmpty()}
|
||||
<div class="fb-hero">
|
||||
<div class="fb-hero-grid">
|
||||
{volist name="recommendedArticles" id="rec" offset="0" length="1"}
|
||||
<a class="fb-hero-main" href="{:url('blog/article/detail', ['id' => $rec.id])}">
|
||||
<img src="{$rec.cover_image|default='/static/blog/img/pic.jpg'}" alt="{$rec.title}">
|
||||
<div class="fb-hero-cap">
|
||||
<span class="tag">{$rec.category.name|default='推荐'}</span>
|
||||
<h2>{$rec.title}</h2>
|
||||
</div>
|
||||
</a>
|
||||
{/volist}
|
||||
<div class="fb-hero-sub">
|
||||
{volist name="recommendedArticles" id="rec" offset="1" length="2"}
|
||||
<a class="fb-hero-sub-item" href="{:url('blog/article/detail', ['id' => $rec.id])}">
|
||||
<img src="{$rec.cover_image|default='/static/blog/img/code.jpg'}" alt="{$rec.title}">
|
||||
<div class="fb-hero-cap">
|
||||
<h3>{$rec.title}</h3>
|
||||
</div>
|
||||
</a>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/notempty}
|
||||
|
||||
<div class="fb-layout">
|
||||
<!-- 左:文章流 -->
|
||||
<main class="fb-content">
|
||||
<div class="fb-section-title"><h2>最新文章</h2></div>
|
||||
{if $articles->isEmpty()}
|
||||
<div class="fb-empty"><p>站点还没有发布文章,敬请期待。</p></div>
|
||||
{else}
|
||||
<div class="fb-post-list">
|
||||
{volist name="articles" id="article"}
|
||||
<article class="fb-post">
|
||||
<a class="thumb" href="{:url('blog/article/detail', ['id' => $article.id])}">
|
||||
<img src="{$article.cover_image|default='/static/blog/img/book.jpg'}" alt="{$article.title}">
|
||||
</a>
|
||||
<div class="body">
|
||||
<span class="cat">{$article.category.name|default='默认'}</span>
|
||||
<h3><a href="{:url('blog/article/detail', ['id' => $article.id])}">{$article.title}</a></h3>
|
||||
<p class="summary">{$article.summary|default='(暂无描述)'}</p>
|
||||
<div class="meta">
|
||||
<a class="author" href="{:url('blog/article/author', ['id' => $article.uid])}">
|
||||
<img src="{$article.user.avatar|default='/static/blog/img/avatar.jpg'}" alt="">
|
||||
{$article.user.nickname|default='佚名'}
|
||||
</a>
|
||||
<span><i class="layui-icon layui-icon-read"></i> {$article.view_count|default=0}</span>
|
||||
<span><i class="layui-icon layui-icon-praise"></i> {$article.like_count|default=0}</span>
|
||||
<span class="sp">{$article.create_text}</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/volist}
|
||||
</div>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
<!-- 右:侧栏 -->
|
||||
<aside class="fb-aside">
|
||||
<div class="fb-widget">
|
||||
<div class="fb-stat">
|
||||
<div><div class="num">{$total_articles|default=0}</div><div class="lbl">文章</div></div>
|
||||
<div><div class="num">{$total_categories|default=0}</div><div class="lbl">分类</div></div>
|
||||
<div><div class="num">{$total_views|default=0}</div><div class="lbl">阅读</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fb-widget">
|
||||
<h4>热门文章</h4>
|
||||
<ul class="fb-hot">
|
||||
{volist name="hotArticles" id="a"}
|
||||
<li>
|
||||
<span class="rank">{$i}</span>
|
||||
<a href="{:url('blog/article/detail', ['id' => $a.id])}">{$a.title}</a>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="fb-widget">
|
||||
<h4>文章分类</h4>
|
||||
<ul class="fb-catlist">
|
||||
{volist name="categories" id="c"}
|
||||
<li><a href="{:url('blog/category', ['id' => $c.id])}">{$c.name}<span class="cnt">{$c.card_count|default=0}</span></a></li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="fb-widget">
|
||||
<h4>标签云</h4>
|
||||
<div class="fb-tagcloud">
|
||||
{volist name="tags" id="t"}
|
||||
<a href="{:url('blog/tag', ['id' => $t.id])}">{$t.name}</a>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{notempty name="latestComments"}
|
||||
{if !$latestComments->isEmpty()}
|
||||
<div class="fb-widget">
|
||||
<h4>最新评论</h4>
|
||||
<ul class="fb-cmt">
|
||||
{volist name="latestComments" id="cmt"}
|
||||
<li>
|
||||
<span class="who">{$cmt.user.nickname|default='匿名'}</span>:
|
||||
<span class="txt">{$cmt.content}</span>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
{/notempty}
|
||||
</aside>
|
||||
</div>
|
||||
{/block}
|
||||
@@ -0,0 +1,35 @@
|
||||
{extend name="layout" /}
|
||||
{block name="title"}附近文章{/block}
|
||||
{block name="content"}
|
||||
<div class="main article">
|
||||
<div class="layui-tab layui-tab-brief">
|
||||
<ul class="layui-tab-title"><li class="layui-this">附近文章(半径 {$radius} km)</li></ul>
|
||||
</div>
|
||||
<div id="geo-tip" class="item"><div class="item-content"><h3>正在获取您的位置…</h3></div></div>
|
||||
{if empty($list)}
|
||||
<div class="item"><div class="item-content"><h3>附近暂无文章</h3><p>可在 URL 手动传 ?lat=&lng= 查看</p></div></div>
|
||||
{else}
|
||||
{volist name="list" id="item"}
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<h3><a href="{$item.url}">{$item.title}</a></h3>
|
||||
<p class="meta"><span>{$item.category}</span>{if $item.distance}<span>约 {$item.distance} km</span>{/if}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
{/if}
|
||||
</div>
|
||||
<script>
|
||||
(function(){
|
||||
var tip = document.getElementById('geo-tip');
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(function(p){
|
||||
if (tip) tip.style.display='none';
|
||||
window.location.href = '/blog/nearby?lat='+p.coords.latitude+'&lng='+p.coords.longitude+'&radius=10';
|
||||
}, function(){ if (tip) tip.querySelector('h3').textContent='获取位置失败,可在 URL 手动传 ?lat=&lng='; });
|
||||
} else if (tip) {
|
||||
tip.querySelector('h3').textContent='浏览器不支持定位,请在 URL 手动传 ?lat=&lng=';
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,33 @@
|
||||
{extend name="layout" /}
|
||||
{block name="title"}搜索:{$keyword} - 静谧博客{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="main article">
|
||||
<div class="layui-tab layui-tab-brief">
|
||||
<ul class="layui-tab-title"><li class="layui-this">搜索:{$keyword}</li></ul>
|
||||
</div>
|
||||
{if $articles->isEmpty()}
|
||||
<div class="item"><div class="item-content"><h3>没有找到相关文章</h3><p>尝试更换关键词搜索</p></div></div>
|
||||
{else}
|
||||
{volist name="articles" id="article"}
|
||||
<div class="item">
|
||||
{if $article.cover_image}<img src="{$article.cover_image}" alt="{$article.title}">{/if}
|
||||
<div class="item-content">
|
||||
<h3><a href="{:url('blog/article/detail', ['id' => $article.id])}">{$article.title}</a></h3>
|
||||
<span class="Subtitle">{$article.category.name|default='默认'}</span><br/>
|
||||
<p>{$article.summary}</p>
|
||||
<a href="{:url('blog/article/detail', ['id' => $article.id])}"><button class="layui-btn">阅读全文</button></a>
|
||||
</div>
|
||||
<div class="date-box">
|
||||
<div class="date">
|
||||
<h4>{:date('d', strtotime($article.create_text))}</h4>
|
||||
<span>{:date('Y/m', strtotime($article.create_text))}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
<div id="demo1">{$articles|raw}</div>
|
||||
{/if}
|
||||
</div>
|
||||
{include file="index/_sidebar" /}
|
||||
{/block}
|
||||
@@ -0,0 +1,179 @@
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{block name="title"}{$siteConf.site_name|default='博客'}{/block}</title>
|
||||
<meta name="description" content="{$siteConf.site_description|default=''}" />
|
||||
<link rel="stylesheet" href="/assets/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="/static/blog/css/theme.css">
|
||||
<style>
|
||||
/* 主题色由后台「基本设置」配置,注入 CSS 变量驱动整站配色 */
|
||||
:root { --theme: {$theme_color|default='#2d6cdf'}; }
|
||||
</style>
|
||||
{block name="style"}{/block}
|
||||
</head>
|
||||
<body class="has-tab">
|
||||
|
||||
<!-- 顶部导航 -->
|
||||
<div class="fb-nav">
|
||||
<div class="inner">
|
||||
<a href="{:url('blog/index/index')}" class="logo">{$siteConf.site_name|default='博客'}</a>
|
||||
<nav class="menu">
|
||||
<a href="{:url('blog/index/index')}" {if $nav_active=='index'}class="active"{/if}>首页</a>
|
||||
<a href="{:url('category/index')}" {if $nav_active=='category'}class="active"{/if}>分类</a>
|
||||
<a href="{:url('blog/tag/index')}" {if $nav_active=='tag'}class="active"{/if}>标签</a>
|
||||
<a href="{:url('blog/index/about')}" {if $nav_active=='about'}class="active"{/if}>关于</a>
|
||||
</nav>
|
||||
<form class="search" action="{:url('blog/search/index')}" method="get">
|
||||
<input type="text" name="keyword" placeholder="搜索文章..." autocomplete="off">
|
||||
<button type="submit"><i class="layui-icon layui-icon-search"></i></button>
|
||||
</form>
|
||||
<div class="user">
|
||||
{if $is_login}
|
||||
<a href="{:url('blog/article/author', ['id' => $current_uid])}">我的博客</a>
|
||||
<a href="{:url('/user/index/index')}">中心</a>
|
||||
{else}
|
||||
<a href="{:url('auth/login')}">登录</a>
|
||||
{/if}
|
||||
</div>
|
||||
<button class="hamburger" id="fbMenuBtn"><i class="layui-icon layui-icon-more-vertical"></i></button>
|
||||
</div>
|
||||
<div class="drawer" id="fbDrawer">
|
||||
<a href="{:url('index/index')}">首页</a>
|
||||
<a href="{:url('category')}">分类</a>
|
||||
<a href="{:url('/tag')}">标签</a>
|
||||
<a href="{:url('/index/about')}">关于</a>
|
||||
<div class="user">
|
||||
{if $is_login}
|
||||
<a href="{:url('/article/author', ['id' => $current_uid])}">我的博客</a>
|
||||
<a href="{:url('user/index')}">个人中心</a>
|
||||
{else}
|
||||
<a href="{:url('auth/login')}">登录</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="fb-main">
|
||||
<div class="fb-wrap">
|
||||
{block name="content"}{/block}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 移动端底部 Tab 导航(精简:只保留高频入口,分类/标签移入顶部汉堡菜单) -->
|
||||
<div class="fb-tabbar">
|
||||
<a href="{:url('/blog/index/index')}" {if $nav_active=='index'}class="active"{/if}><i class="layui-icon layui-icon-home"></i>首页</a>
|
||||
{if $is_login}
|
||||
<a href="{:url('/blog/article/author', ['id' => $current_uid])}"><i class="layui-icon layui-icon-username"></i>我的</a>
|
||||
{else}
|
||||
<a href="{:url('auth/login')}"><i class="layui-icon layui-icon-username"></i>我的</a>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- 页脚 -->
|
||||
<footer class="fb-footer">
|
||||
<p>© {:date('Y')} {$siteConf.site_name|default='博客'}. All Rights Reserved.</p>
|
||||
</footer>
|
||||
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.use(['element', 'layer', 'form'], function(){
|
||||
var element = layui.element, layer = layui.layer, form = layui.form;
|
||||
window.layer = layer; window.layui = layui;
|
||||
var drawer = document.getElementById('fbDrawer');
|
||||
document.getElementById('fbMenuBtn').addEventListener('click', function(e){
|
||||
e.stopPropagation();
|
||||
drawer.classList.toggle('open');
|
||||
});
|
||||
document.addEventListener('click', function(e){
|
||||
if (!drawer.contains(e.target) && e.target.id !== 'fbMenuBtn' && !document.getElementById('fbMenuBtn').contains(e.target)) {
|
||||
drawer.classList.remove('open');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 全局登录弹窗(前台通用) -->
|
||||
<div id="globalLoginBox" style="display:none; padding: 20px 24px;">
|
||||
<form class="layui-form" id="globalLoginForm" lay-filter="globalLoginForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="username" lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="password" lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">验证码</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-row layui-col-space10">
|
||||
<div class="layui-col-xs7">
|
||||
<input type="text" name="captcha" lay-verify="required" placeholder="图形验证码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs5">
|
||||
<img id="globalLoginCaptcha" src="{:url('user/ajax/verify')}" alt="点击刷新验证码" title="点击刷新验证码" style="height:38px;cursor:pointer;border-radius:2px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="globalLoginSubmit">登 录</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重 置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'jquery'], function(){
|
||||
var layer = layui.layer, form = layui.form, $ = layui.$;
|
||||
var globalLoginIndex = null;
|
||||
function refreshGlobalCaptcha(){
|
||||
$('#globalLoginCaptcha').attr('src', '{:url(\'member/ajax/verify\')}?t=' + Date.now());
|
||||
}
|
||||
$('#globalLoginCaptcha').on('click', refreshGlobalCaptcha);
|
||||
window.openLogin = function(cb){
|
||||
globalLoginIndex = layer.open({
|
||||
type: 1, title: '用户登录', area: ['480px', 'auto'],
|
||||
content: $('#globalLoginBox'),
|
||||
success: function(){
|
||||
refreshGlobalCaptcha();
|
||||
$('#globalLoginForm')[0].reset();
|
||||
if (typeof cb === 'function') { window.__loginCb = cb; }
|
||||
}
|
||||
});
|
||||
};
|
||||
form.on('submit(globalLoginSubmit)', function(data){
|
||||
$.post('{:url(\'member/login/save\')}', data.field, function(res){
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.message || '登录成功', {icon: 1});
|
||||
setTimeout(function(){
|
||||
if (globalLoginIndex) { layer.close(globalLoginIndex); }
|
||||
if (typeof window.__loginCb === 'function') {
|
||||
var cb = window.__loginCb; window.__loginCb = null; cb();
|
||||
} else { location.reload(); }
|
||||
}, 600);
|
||||
} else {
|
||||
layer.msg(res.message || '登录失败', {icon: 2});
|
||||
refreshGlobalCaptcha();
|
||||
}
|
||||
}, 'json');
|
||||
return false;
|
||||
});
|
||||
$(document).on('click', 'a[href*="auth/login"], a[href*="member/login"]', function(e){
|
||||
if ($(this).attr('target') === '_blank') { return; }
|
||||
e.preventDefault();
|
||||
window.openLogin();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{block name="script"}{/block}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
{extend name="layout" /}
|
||||
{block name="title"}搜索:{$keyword} - {$siteConf.site_name|default='博客'}{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="fb-layout">
|
||||
<main class="fb-content">
|
||||
<div class="fb-section-title"><h2>搜索:{$keyword}</h2></div>
|
||||
{if $articles->isEmpty()}
|
||||
<div class="fb-empty"><p>没有找到相关文章,尝试更换关键词搜索。</p></div>
|
||||
{else}
|
||||
<div class="fb-post-list">
|
||||
{volist name="articles" id="article"}
|
||||
<article class="fb-post">
|
||||
{if $article.cover_image}
|
||||
<a class="thumb" href="{:url('blog/article/detail', ['id' => $article.id])}">
|
||||
<img src="{$article.cover_image}" alt="{$article.title}">
|
||||
</a>
|
||||
{/if}
|
||||
<div class="body">
|
||||
<span class="cat">{$article.category.name|default='默认'}</span>
|
||||
<h3><a href="{:url('blog/article/detail', ['id' => $article.id])}">{$article.title}</a></h3>
|
||||
<p class="summary">{$article.summary|default='(暂无描述)'}</p>
|
||||
<div class="meta">
|
||||
<span class="sp">{$article.create_text}</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/volist}
|
||||
</div>
|
||||
<div class="fb-pager">{$articles|raw}</div>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
{include file="index/_sidebar" /}
|
||||
</div>
|
||||
{/block}
|
||||
@@ -0,0 +1,52 @@
|
||||
{extend name="layout" /}
|
||||
{assign name="nav_active" value="tag"/}
|
||||
{block name="title"}{$tag.name|default='全部标签'} - {$siteConf.site_name|default='博客'}{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="fb-layout">
|
||||
<main class="fb-content">
|
||||
{if $tag}
|
||||
<div class="fb-section-title"><h2>标签:{$tag.name}</h2></div>
|
||||
{if $articles->isEmpty()}
|
||||
<div class="fb-empty"><p>该标签下暂无文章。</p></div>
|
||||
{else}
|
||||
<div class="fb-post-list">
|
||||
{volist name="articles" id="article"}
|
||||
<article class="fb-post">
|
||||
{if $article.cover_image}
|
||||
<a class="thumb" href="{:url('blog/article/detail', ['id' => $article.id])}">
|
||||
<img src="{$article.cover_image}" alt="{$article.title}">
|
||||
</a>
|
||||
{/if}
|
||||
<div class="body">
|
||||
<span class="cat">{$article.category.name|default='默认'}</span>
|
||||
<h3><a href="{:url('blog/article/detail', ['id' => $article.id])}">{$article.title}</a></h3>
|
||||
<p class="summary">{$article.summary|default='(暂无描述)'}</p>
|
||||
<div class="meta">
|
||||
<a class="author" href="{:url('blog/article/author', ['id' => $article.uid])}">
|
||||
<img src="{$article.user.avatar|default='/static/blog/img/avatar.jpg'}" alt="">
|
||||
{$article.user.nickname|default='佚名'}
|
||||
</a>
|
||||
<span class="sp">{$article.create_text}</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/volist}
|
||||
</div>
|
||||
<div class="fb-pager">{$articles|raw}</div>
|
||||
{/if}
|
||||
{else}
|
||||
<div class="fb-section-title"><h2>全部标签</h2></div>
|
||||
<div class="fb-card">
|
||||
<div class="fb-tagcloud">
|
||||
{volist name="tags" id="t"}
|
||||
<a href="{:url('blog/tag', ['id' => $t.id])}">{$t.name}</a>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
{include file="index/_sidebar" /}
|
||||
</div>
|
||||
{/block}
|
||||
@@ -0,0 +1,105 @@
|
||||
{layout name="layout"}
|
||||
{block name="title"}写文章 - TP-Blog 会员中心{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">写文章</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="" id="articleForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" required lay-verify="required" placeholder="请输入文章标题" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="cid" lay-verify="required" style="max-width:320px;">
|
||||
<option value="">请选择分类</option>
|
||||
{volist name="categories" id="c"}
|
||||
<option value="{$c.id}">{$c.name}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
<a href="{:url('blog/member.category/index')}" target="_blank" class="layui-btn layui-btn-primary layui-btn-sm" style="margin-left:10px;">管理分类</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标签</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="tags" placeholder="多个标签用逗号分隔,如:PHP,ThinkPHP" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">摘要</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="summary" placeholder="选填,留空将自动截取正文" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">封面图</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="cover_image" placeholder="选填,封面图 URL" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">正文</label>
|
||||
<div class="layui-input-block">
|
||||
<script id="editor" type="text/plain" style="height:400px;"></script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="立即发布" checked>
|
||||
<input type="radio" name="status" value="0" title="存为草稿">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="articleSubmit">提交</button>
|
||||
<a href="{:url('blog/member.article/index')}" class="layui-btn layui-btn-primary">返回</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="/assets/library/ueditor/ueditor.config.js"></script>
|
||||
<script type="text/javascript" src="/assets/library/ueditor/ueditor.all.js"></script>
|
||||
<script>
|
||||
var ue = UE.getEditor('editor', {
|
||||
toolbars: [[
|
||||
'undo', 'redo', '|',
|
||||
'removeformat', 'formatmatch', '|',
|
||||
'fontsize', 'bold', 'italic', 'underline', 'strikethrough', 'forecolor', 'backcolor', '|',
|
||||
'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', 'indent', '|',
|
||||
'inserttable', 'blockquote', 'horizontal', 'insertcode', 'emotion', '|',
|
||||
'searchreplace'
|
||||
]],
|
||||
autoHeightEnabled: true,
|
||||
initialFrameWidth: '100%',
|
||||
initialFrameHeight: 400
|
||||
});
|
||||
|
||||
layui.use(['form', 'layer'], function(){
|
||||
var form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
form.on('submit(articleSubmit)', function(data){
|
||||
var content = UE.getEditor('editor').getContent();
|
||||
if (! content.trim()) {
|
||||
layer.msg('请输入文章内容', {icon:2});
|
||||
return false;
|
||||
}
|
||||
data.field.content = content;
|
||||
$.post('{:url("blog/member.article/save")}', data.field, function(res){
|
||||
if(res.code === 1){
|
||||
layer.msg(res.msg, {icon:1}, function(){ location.href = res.url; });
|
||||
} else {
|
||||
layer.msg(res.msg, {icon:2});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,106 @@
|
||||
{layout name="layout"}
|
||||
{block name="title"}编辑文章 - TP-Blog 会员中心{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">编辑文章</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="" id="articleForm">
|
||||
<input type="hidden" name="id" value="{$article.id}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" value="{$article.title}" required lay-verify="required" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="cid" lay-verify="required" style="max-width:320px;">
|
||||
<option value="">请选择分类</option>
|
||||
{volist name="categories" id="c"}
|
||||
<option value="{$c.id}" {if $c.id==$article.cid}selected{/if}>{$c.name}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
<a href="{:url('blog/member.category/index')}" target="_blank" class="layui-btn layui-btn-primary layui-btn-sm" style="margin-left:10px;">管理分类</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标签</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="tags" value="{$articleTagsStr}" placeholder="多个标签用逗号分隔" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">摘要</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="summary" placeholder="选填,留空将自动截取正文" class="layui-textarea">{$article.summary}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">封面图</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="cover_image" value="{$article.cover_image}" placeholder="选填,封面图 URL" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">正文</label>
|
||||
<div class="layui-input-block">
|
||||
<script id="editor" type="text/plain" style="height:400px;">{$article.content}</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="已发布" {if $article.status==1}checked{/if}>
|
||||
<input type="radio" name="status" value="0" title="草稿" {if $article.status==0}checked{/if}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="articleSubmit">保存</button>
|
||||
<a href="{:url('blog/member.article/index')}" class="layui-btn layui-btn-primary">返回</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="/assets/library/ueditor/ueditor.config.js"></script>
|
||||
<script type="text/javascript" src="/assets/library/ueditor/ueditor.all.js"></script>
|
||||
<script>
|
||||
var ue = UE.getEditor('editor', {
|
||||
toolbars: [[
|
||||
'undo', 'redo', '|',
|
||||
'removeformat', 'formatmatch', '|',
|
||||
'fontsize', 'bold', 'italic', 'underline', 'strikethrough', 'forecolor', 'backcolor', '|',
|
||||
'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', 'indent', '|',
|
||||
'inserttable', 'blockquote', 'horizontal', 'insertcode', 'emotion', '|',
|
||||
'searchreplace'
|
||||
]],
|
||||
autoHeightEnabled: true,
|
||||
initialFrameWidth: '100%',
|
||||
initialFrameHeight: 400
|
||||
});
|
||||
|
||||
layui.use(['form', 'layer'], function(){
|
||||
var form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
form.on('submit(articleSubmit)', function(data){
|
||||
var content = UE.getEditor('editor').getContent();
|
||||
if (! content.trim()) {
|
||||
layer.msg('请输入文章内容', {icon:2});
|
||||
return false;
|
||||
}
|
||||
data.field.content = content;
|
||||
$.post('{:url("blog/member.article/update", ["id" => $article.id])}', data.field, function(res){
|
||||
if(res.code === 1){
|
||||
layer.msg(res.msg, {icon:1}, function(){ location.href = res.url; });
|
||||
} else {
|
||||
layer.msg(res.msg, {icon:2});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,123 @@
|
||||
{layout name="layout"}
|
||||
|
||||
{block name="content"}
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">我的文章</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form layui-inline" lay-filter="searchForm">
|
||||
<div class="layui-inline">
|
||||
<select name="status">
|
||||
<option value="all">全部状态</option>
|
||||
<option value="1">已发布</option>
|
||||
<option value="0">草稿</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="keyword" placeholder="搜索标题/内容" class="layui-input" id="keywordInput">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-primary" lay-submit lay-filter="search">搜索</button>
|
||||
</div>
|
||||
<a href="{:url('blog/member.article/create')}" class="layui-btn layui-btn-normal">写文章</a>
|
||||
<button type="button" class="layui-btn layui-btn-danger" id="batchDeleteBtn">批量删除</button>
|
||||
</form>
|
||||
<table class="layui-hide" id="articleTable" lay-filter="articleTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="rowTpl">
|
||||
<a class="layui-btn layui-btn-xs" href="{{ d.edit_url }}">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete">删除</a>
|
||||
</script>
|
||||
{/block}
|
||||
|
||||
{block name="js"}
|
||||
<script>
|
||||
layui.use(['table', 'layer', 'form'], function () {
|
||||
var table = layui.table;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var $ = layui.$;
|
||||
|
||||
var status = '{$status|default="all"}';
|
||||
var keyword = '{$keyword|default=""}';
|
||||
$('select[name="status"]').val(status);
|
||||
$('#keywordInput').val(keyword);
|
||||
|
||||
var renderTable = function () {
|
||||
table.render({
|
||||
elem: '#articleTable',
|
||||
url: '{:url("blog/member.article/index")}',
|
||||
where: { status: status, keyword: keyword },
|
||||
page: true,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'title', title: '标题', minWidth: 220, templet: function (d) {
|
||||
var html = '<a href="' + d.detail_url + '" target="_blank">' + d.title + '</a>';
|
||||
if (d.is_top == 1) { html += ' <span class="layui-badge layui-bg-red">置顶</span>'; }
|
||||
return html;
|
||||
} },
|
||||
{ field: 'category', title: '分类', width: 120 },
|
||||
{ field: 'status', title: '状态', width: 90, templet: function (d) {
|
||||
return d.status == 1
|
||||
? '<span class="layui-badge layui-bg-green">已发布</span>'
|
||||
: '<span class="layui-badge">草稿</span>';
|
||||
} },
|
||||
{ field: 'view_count', title: '阅读', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'comment_count', title: '评论', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'like_count', title: '点赞', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'favorite_count', title: '收藏', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'share_count', title: '分享', width: 80, sort: true, align: 'center' },
|
||||
{ field: 'create_text', title: '发布时间', width: 160 },
|
||||
{ title: '操作', width: 130, align: 'center', toolbar: '#rowTpl', fixed: 'right' }
|
||||
]]
|
||||
});
|
||||
};
|
||||
renderTable();
|
||||
|
||||
// 搜索
|
||||
form.on('submit(search)', function () {
|
||||
var statusVal = $('select[name="status"]').val();
|
||||
var kw = $('#keywordInput').val();
|
||||
table.reload('articleTable', { where: { status: statusVal, keyword: kw }, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
|
||||
// 批量删除
|
||||
$('#batchDeleteBtn').click(function () {
|
||||
var checkData = table.checkStatus('articleTable').data;
|
||||
if (! checkData.length) {
|
||||
return layer.msg('请选择要删除的文章');
|
||||
}
|
||||
var ids = checkData.map(function (i) { return i.id; });
|
||||
layer.confirm('确定要删除选中的 ' + ids.length + ' 篇文章吗?', function (index) {
|
||||
$.post('{:url("blog/member.article/batch")}', { action: 'delete', ids: ids }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
});
|
||||
|
||||
// 行操作
|
||||
table.on('tool(articleTable)', function (obj) {
|
||||
if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除这篇文章吗?', function (index) {
|
||||
$.post('{:url("blog/member.article/delete")}', { id: obj.data.id }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { renderTable(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,43 @@
|
||||
{layout name="layout" /}
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">添加分类</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{:url('blog/member.category/save')}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" required lay-verify="required" placeholder="请输入分类名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入分类描述" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上级分类</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="pid">
|
||||
<option value="0">顶级分类</option>
|
||||
{volist name="categories" id="c"}
|
||||
<option value="{$c.id}">{$c.name}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" value="0" placeholder="数值越小越靠前" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="categorySubmit">添加分类</button>
|
||||
<a href="{:url('blog/member.category/index')}" class="layui-btn layui-btn-primary">返回</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
{layout name="layout" /}
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">编辑分类</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{:url('blog/member.category/update', ['id' => $category.id])}" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" value="{$category.name}" required lay-verify="required" placeholder="请输入分类名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入分类描述" class="layui-textarea">{$category.description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上级分类</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="pid">
|
||||
<option value="0" {if $category.pid==0}selected{/if}>顶级分类</option>
|
||||
{volist name="categories" id="c"}
|
||||
<option value="{$c.id}" {if $category.pid==$c.id}selected{/if}>{$c.name}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" value="{$category.sort}" placeholder="数值越小越靠前" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="categorySubmit">更新分类</button>
|
||||
<a href="{:url('blog/member.category/index')}" class="layui-btn layui-btn-primary">返回</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,223 @@
|
||||
{layout name="layout" /}
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">我的分类</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 顶部工具栏 -->
|
||||
<script type="text/html" id="toolbarTpl">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="createRoot">添加分类</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="batchDelete">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="expandAll">展开全部</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="foldAll">折叠全部</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 行操作 -->
|
||||
<script type="text/html" id="rowTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="addChild">添加子分类</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete">删除</a>
|
||||
</script>
|
||||
|
||||
<!-- 新增/编辑 表单模板(弹窗内渲染) -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<div style="padding:15px;">
|
||||
<form class="layui-form" lay-filter="dataForm">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" value="{{ d.name || '' }}" required lay-verify="required" placeholder="请输入分类名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入分类描述" class="layui-textarea">{{ d.description || '' }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上级分类</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="pid" id="pidSelect"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" value="{{ d.sort || 0 }}" placeholder="数值越小越靠前" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="dataFormSubmit" id="dataFormSubmit">保存</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="cancelBtn">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['treeTable', 'layer', 'form', 'laytpl', 'http'], function () {
|
||||
var treeTable = layui.treeTable;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
var form = layui.form;
|
||||
var laytpl = layui.laytpl;
|
||||
var http = layui.http;
|
||||
|
||||
// 后端注入的扁平树数据
|
||||
var treeData = {$treeData|raw};
|
||||
var pmap = {};
|
||||
treeData.forEach(function (c) { pmap[c.id] = c; });
|
||||
|
||||
// 构建上级分类下拉(编辑时排除自身及其子孙节点,避免形成环)
|
||||
function buildPidOptions(selfId) {
|
||||
var html = '<option value="0">顶级分类</option>';
|
||||
treeData.forEach(function (c) {
|
||||
if (selfId && c.id === selfId) return;
|
||||
if (selfId) {
|
||||
var cur = pmap[c.id];
|
||||
while (cur && cur.pid) {
|
||||
if (cur.pid == selfId) return;
|
||||
cur = pmap[cur.pid];
|
||||
}
|
||||
}
|
||||
html += '<option value="' + c.id + '">' + c.title + '</option>';
|
||||
});
|
||||
return html;
|
||||
}
|
||||
|
||||
// 渲染树形表格
|
||||
function renderTable() {
|
||||
treeTable.render({
|
||||
elem: '#dataTable',
|
||||
data: treeData,
|
||||
tree: {
|
||||
customName: { isParent: 'is_parent', name: 'title', id: 'id', pid: 'pid' },
|
||||
data: { isSimpleData: true, rootPid: 0 },
|
||||
view: { showIcon: false }
|
||||
},
|
||||
toolbar: '#toolbarTpl',
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '分类名称', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'description', title: '描述', minWidth: 160, templet: function (d) { return d.description || '-'; } },
|
||||
{ field: 'articles_count', title: '文章数', width: 90 },
|
||||
{ field: 'sort', title: '排序', width: 80, sort: true },
|
||||
{ title: '操作', width: 230, align: 'center', toolbar: '#rowTpl' }
|
||||
]],
|
||||
page: false,
|
||||
skin: 'line'
|
||||
});
|
||||
}
|
||||
renderTable();
|
||||
|
||||
// 新增 / 编辑 弹窗
|
||||
function openForm(data) {
|
||||
data = data || {};
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data);
|
||||
layer.open({
|
||||
title: data.id ? '编辑分类' : (data.pid ? '添加子分类' : '添加分类'),
|
||||
content: formHtml,
|
||||
anim: 'slideLeft',
|
||||
offset: 'r',
|
||||
area: ['480px', '98%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['保存', '取消'],
|
||||
success: function (layero, index) {
|
||||
$('#pidSelect').html(buildPidOptions(data.id));
|
||||
if (data.pid) { $('#pidSelect').val(data.pid); }
|
||||
form.render('select');
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
layero.contents().find('#dataFormSubmit').trigger('click');
|
||||
},
|
||||
btn2: function (index) { layer.close(index); }
|
||||
});
|
||||
}
|
||||
|
||||
// 表单提交:仅绑定一次(layui form 的 submit 为事件委托,弹窗内同 lay-filter 表单均可触发,不会叠加)
|
||||
form.on('submit(dataFormSubmit)', function (elem) {
|
||||
var field = elem.field;
|
||||
var isEdit = !!field.id;
|
||||
var url = isEdit
|
||||
? '{:url("blog/member.category/update")}'
|
||||
: '{:url("blog/member.category/save")}';
|
||||
var postData = $.extend({}, field);
|
||||
if (isEdit) { postData.id = field.id; }
|
||||
http.post(url, postData).then(function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.closeAll('dialog');
|
||||
layer.msg(res.msg, { icon: 1 });
|
||||
setTimeout(function () { location.reload(); }, 600);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败', { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () { layer.msg('请求失败,请重试', { icon: 2 }); }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 顶部工具条
|
||||
treeTable.on('toolbar(dataTable)', function (obj) {
|
||||
switch (obj.event) {
|
||||
case 'createRoot':
|
||||
openForm({ pid: 0, sort: 0 });
|
||||
break;
|
||||
case 'batchDelete':
|
||||
var checkData = treeTable.checkStatus('dataTable').data;
|
||||
if (!checkData.length) {
|
||||
return layer.msg('请选择要删除的分类');
|
||||
}
|
||||
var ids = checkData.map(function (item) { return item.id; });
|
||||
layer.confirm('确定删除选中的 ' + ids.length + ' 个分类吗?', function (index) {
|
||||
$.post('{:url("blog/member.category/batch")}', { action: 'delete', ids: ids }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { location.reload(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
break;
|
||||
case 'expandAll':
|
||||
treeTable.expandAll('#dataTable');
|
||||
break;
|
||||
case 'foldAll':
|
||||
treeTable.foldAll('#dataTable');
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 行操作
|
||||
treeTable.on('tool(dataTable)', function (obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'edit') {
|
||||
openForm(data);
|
||||
} else if (obj.event === 'addChild') {
|
||||
openForm({ pid: data.id, sort: 0 });
|
||||
} else if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除该分类吗?', function (index) {
|
||||
$.post('{:url("blog/member.category/delete")}', { id: data.id }, function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 }, function () { location.reload(); });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,23 @@
|
||||
{layout name="layout" /}
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">会员中心概览</div>
|
||||
<div class="layui-card-body">
|
||||
<p>当前会员:<strong>{$user.nickname|default='会员'}</strong>
|
||||
(账号:{$user.account|default='-'},UID:{$user.uid|default='0'})</p>
|
||||
<p>这是插件 <code>blog</code> 的会员中心入口页,对应文件:
|
||||
<code>addon/blog/controller/member/Index.php</code></p>
|
||||
<a href="{:url('blog/member.index/profile')}" class="layui-btn layui-btn-normal">查看个人资料</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">本页链路说明</div>
|
||||
<div class="layui-card-body">
|
||||
<ol>
|
||||
<li>路由:<code>addon/blog/route/app.php</code> 的 member 分组映射 <code>/blog/member/</code> → <code>member.Index/index</code></li>
|
||||
<li>鉴权:member 分组挂 <code>MemberAuth</code> 中间件,容器 auth 为 <code>\ywxapp\library\User</code> 并强制登录</li>
|
||||
<li>基类:<code>Index extends \ywxapp\controller\AddonMember</code>,视图目录指向 <code>view/member/</code></li>
|
||||
<li>模板:本页通过 <code>{layout name="layout" /}</code> 复用会员中心外壳 <code>view/layout.html</code></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
{layout name="layout" /}
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">个人资料</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table">
|
||||
<colgroup>
|
||||
<col width="30%">
|
||||
<col width="70%">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr><td>会员ID</td><td>{$user.uid|default='0'}</td></tr>
|
||||
<tr><td>账号</td><td>{$user.account|default='-'}</td></tr>
|
||||
<tr><td>昵称</td><td>{$user.nickname|default='-'}</td></tr>
|
||||
<tr><td>角色</td><td>{$user.roles|default='-'}</td></tr>
|
||||
<tr><td>积分</td><td>{$user.score|default='0'}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="{:url('blog/member.index/index')}" class="layui-btn">返回概览</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{$title|default='会员中心 - TP-Blog'}</title>
|
||||
<link rel="stylesheet" href="/assets/layui/css/layui.css">
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<style>
|
||||
body { background-color: #f2f3f5; font-family: "Microsoft YaHei", sans-serif; }
|
||||
.member-nav { background: #23262e; color: #fff; padding: 0 15px; }
|
||||
.member-nav a { color: #ccc; margin-left: 18px; line-height: 50px; text-decoration: none; font-size: 14px; }
|
||||
.member-nav a:hover { color: #fff; }
|
||||
.member-nav .member-nav-brand { font-size: 16px; font-weight: bold; margin-right: 10px; }
|
||||
.member-nav .member-nav-right { float: right; margin-right: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div style="margin-top:20px;margin-bottom:20px;">
|
||||
{__CONTENT__}
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user