mirror of
https://gitee.com/ulthon/ulthon_information.git
synced 2026-07-01 16:22:49 +08:00
feat: 添加Vditor编辑器支持并扩展文件上传功能
- 新增Vditor编辑器静态资源文件,包括图片、字体和样式文件 - 在文件上传控制器中添加vditorSave方法,支持Vditor编辑器文件上传 - 在文章创建页面添加编辑器类型选择(富文本/Markdown) - 更新.gitignore文件,排除Playwright和QA截图目录 - 扩展UploadFiles类以支持Vditor编辑器的文件上传格式
This commit is contained in:
@@ -79,6 +79,13 @@
|
||||
<input type="radio" name="status" value="0" title="不发布" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-form-label">编辑器类型</div>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="content_type" value="html" title="富文本" checked>
|
||||
<input type="radio" name="content_type" value="markdown" title="Markdown">
|
||||
</div>
|
||||
</div>
|
||||
{notin name='$Request.param.type' value='category-start,category-end' }
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-form-label">发表时间</div>
|
||||
|
||||
224
view/admin/post/edit_content_markdown.html
Normal file
224
view/admin/post/edit_content_markdown.html
Normal file
@@ -0,0 +1,224 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>内容管理</title>
|
||||
{include file="common/_require"}
|
||||
<link rel="stylesheet" href="/static/lib/vditor/dist/index.css">
|
||||
<script src="/static/lib/vditor/dist/index.min.js"></script>
|
||||
<script>
|
||||
var currentHeaderNavItem = 'Post-{$Request.param.type|default="1"}';
|
||||
var currentLeftNavItem = 'post-{$Request.param.type|default="1"}';
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
background-color: #fff;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#top-container {
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
#content {
|
||||
height: calc(100% - 440px);
|
||||
background-color: rgb(245, 245, 245);
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#editor-container {
|
||||
width: 850px;
|
||||
margin: 30px auto 30px auto;
|
||||
background-color: #fff;
|
||||
padding: 20px 50px 50px 50px;
|
||||
border: 1px solid #e8e8e8;
|
||||
box-shadow: 0 2px 10px rgb(0 0 0 / 12%);
|
||||
}
|
||||
|
||||
#editor-container li {
|
||||
list-style: inherit;
|
||||
}
|
||||
|
||||
#title-container {
|
||||
padding: 20px 0;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
#title-container input {
|
||||
font-size: 30px;
|
||||
border: 0;
|
||||
outline: none;
|
||||
width: 100%;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
#editor-text-area {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="layui-layout-body">
|
||||
<div class="layui-layout layui-layout-admin">
|
||||
{include file="common/_header"}
|
||||
{include file="common/left_post"}
|
||||
<div class="layui-body">
|
||||
<div style="">
|
||||
<div class="">
|
||||
<div id="content">
|
||||
<div id="editor-container">
|
||||
<div id="title-container">
|
||||
<input id="title-input" value="{$post->title}">
|
||||
</div>
|
||||
<div id="editor-text-area"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 30px;line-height: 30px;padding-left: 15px;border-top: 1px solid #e8e8e8;color: #666;">
|
||||
<span id="content-state">内容变动自动提交</span>
|
||||
<a href="{:url('output',['id'=>$post.id])}">
|
||||
去导出
|
||||
</a>
|
||||
</div>
|
||||
<div id="content-data" style="display: none;">{:rawurlencode($post->content??$post->content_html??'')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include file="common/_footer"}
|
||||
</div>
|
||||
<script>
|
||||
var lastContent = '';
|
||||
var contentSaveLock = true;
|
||||
function autoSaveContent() {
|
||||
if (contentSaveLock) {
|
||||
setTimeout(() => {
|
||||
autoSaveContent();
|
||||
}, 2600);
|
||||
} else {
|
||||
contentSaveLock = true;
|
||||
$.post('{:url("update")}', {
|
||||
content: vditor.getValue(),
|
||||
id: '{$post->id}'
|
||||
}, function (result) {
|
||||
$('#content-state').text('自动提交成功')
|
||||
setTimeout(() => {
|
||||
autoSaveContent();
|
||||
}, 2600);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
autoSaveContent();
|
||||
|
||||
var vditor = new Vditor('editor-text-area', {
|
||||
height: 'auto',
|
||||
cache: { enable: false },
|
||||
mode: 'wysiwyg',
|
||||
toolbar: [
|
||||
'headings', 'bold', 'italic', 'strike', '|',
|
||||
'list', 'ordered-list', 'check', '|',
|
||||
'quote', 'code', 'inline-code', '|',
|
||||
'link', 'upload', 'table', '|',
|
||||
'undo', 'redo', '|',
|
||||
'fullscreen', 'preview'
|
||||
],
|
||||
upload: {
|
||||
url: '{:url("File/vditorSave")}',
|
||||
fieldName: 'file[]',
|
||||
extraData: function () {
|
||||
return { type: 'editor' };
|
||||
}
|
||||
},
|
||||
value: decodeURIComponent($('#content-data').html()),
|
||||
input: function (value) {
|
||||
contentSaveLock = false;
|
||||
$('#content-state').text('等待自动提交');
|
||||
},
|
||||
after: function () {
|
||||
setTimeout(function () {
|
||||
var toolbarHeight = 0;
|
||||
var toolbarEl = document.querySelector('.vditor-toolbar');
|
||||
if (toolbarEl) {
|
||||
toolbarHeight = toolbarEl.offsetHeight;
|
||||
}
|
||||
$('#content').height(window.innerHeight - toolbarHeight - 30 - 45 - 7 - 31);
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
||||
// 外部 URL 图片粘贴处理
|
||||
document.addEventListener('paste', function (e) {
|
||||
var pasteStr = e.clipboardData.getData('text/html');
|
||||
if (!pasteStr) return;
|
||||
|
||||
var imgReg = /<img.*?(?:>|\/>)/gi;
|
||||
var srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i;
|
||||
var arr = pasteStr.match(imgReg);
|
||||
|
||||
if (!arr || arr.length === 0) return;
|
||||
|
||||
layer.load();
|
||||
var pending = arr.length;
|
||||
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
(function (imgTag) {
|
||||
var src = imgTag.match(srcReg);
|
||||
if (src && src[1]) {
|
||||
var imgSrc = src[1];
|
||||
if (imgSrc.substr(0, 4) === 'http') {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: "{:url('File/urlSave')}",
|
||||
data: { url: imgSrc, type: 'editor' },
|
||||
success: function (result) {
|
||||
if (result.code === 0) {
|
||||
var mdImg = '';
|
||||
var oldMdImg = '';
|
||||
var current = vditor.getValue();
|
||||
vditor.setValue(current.replace(oldMdImg, mdImg));
|
||||
}
|
||||
pending--;
|
||||
if (pending === 0) layer.closeAll('loading');
|
||||
},
|
||||
error: function () {
|
||||
pending--;
|
||||
if (pending === 0) layer.closeAll('loading');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
pending--;
|
||||
if (pending === 0) layer.closeAll('loading');
|
||||
}
|
||||
} else {
|
||||
pending--;
|
||||
if (pending === 0) layer.closeAll('loading');
|
||||
}
|
||||
})(arr[i]);
|
||||
}
|
||||
});
|
||||
|
||||
// 标题变更保存
|
||||
$('#title-input').change(function () {
|
||||
window.loading = layer.load();
|
||||
$.post('{:url("update")}', {
|
||||
title: $('#title-input').val(),
|
||||
id: '{$post->id}'
|
||||
}, function (result) {
|
||||
layer.close(window.loading);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user