Skip to content

Commit 1ea9221

Browse files
authored
功能优化和新增 (#956)
* feat: 首页项目拖拽排序功能 * feat: 增加首页项目拖拽排序增加只能管理员进行, 排序失败元素回到原本位置 * perf: 新建文章以后直接进入到编辑文章页面 * perf: 优化文档打开时或刷新时样式闪动问题 * perf: 优化表格样式 * feat: 支持上传视频功能 * feat: 视频样式调整 * feat: 直接粘贴视频上传功能 * perf: 优化markdown目录显示
1 parent 710d5bc commit 1ea9221

File tree

12 files changed

+243
-131
lines changed

12 files changed

+243
-131
lines changed

conf/app.conf.example

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ avatar=/static/images/headimgurl.jpg
7979
token_size=12
8080

8181
#上传文件的后缀,如果不限制后缀可以设置为 *
82-
upload_file_ext=txt|doc|docx|xls|xlsx|ppt|pptx|pdf|7z|rar|jpg|jpeg|png|gif
82+
upload_file_ext=txt|doc|docx|xls|xlsx|ppt|pptx|pdf|7z|rar|jpg|jpeg|png|gif|mp4|webm|avi
8383

8484
#上传的文件大小限制
8585
# - 如果不填写, 则默认1GB,如果希望超过1GB,必须带单位

conf/enumerate.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ func GetDefaultCover() string {
106106
return URLForWithCdnImage(web.AppConfig.DefaultString("cover", "/static/images/book.jpg"))
107107
}
108108

109-
// 获取允许的商城文件的类型.
109+
// 获取允许的上传文件的类型.
110110
func GetUploadFileExt() []string {
111-
ext := web.AppConfig.DefaultString("upload_file_ext", "png|jpg|jpeg|gif|txt|doc|docx|pdf")
111+
ext := web.AppConfig.DefaultString("upload_file_ext", "png|jpg|jpeg|gif|txt|doc|docx|pdf|mp4")
112112

113113
temp := strings.Split(ext, "|")
114114

@@ -201,7 +201,7 @@ func GetExportOutputPath() string {
201201
return exportOutputPath
202202
}
203203

204-
// 判断是否是允许商城的文件类型.
204+
// 判断是否是允许上传的文件类型.
205205
func IsAllowUploadFileExt(ext string) bool {
206206

207207
if strings.HasPrefix(ext, ".") {

controllers/DocumentController.go

+38-73
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"html/template"
88
"image/png"
99
"io"
10+
"mime/multipart"
1011
"net/http"
1112
"net/url"
1213
"os"
@@ -486,66 +487,30 @@ func (c *DocumentController) Upload() {
486487
c.JsonResult(6001, i18n.Tr(c.Lang, "message.param_error"))
487488
}
488489

489-
name := "editormd-file-file"
490-
491-
// file, moreFile, err := c.GetFile(name)
492-
// if err == http.ErrMissingFile || moreFile == nil {
493-
// name = "editormd-image-file"
494-
// file, moreFile, err = c.GetFile(name)
495-
// if err == http.ErrMissingFile || moreFile == nil {
496-
// c.JsonResult(6003, i18n.Tr(c.Lang, "message.upload_file_empty"))
497-
// return
498-
// }
499-
// }
500-
// ****3xxx
501-
files, err := c.GetFiles(name)
502-
if err == http.ErrMissingFile {
503-
name = "editormd-image-file"
504-
files, err = c.GetFiles(name)
505-
if err == http.ErrMissingFile {
506-
// c.JsonResult(6003, i18n.Tr(c.Lang, "message.upload_file_empty"))
507-
// return
508-
name = "file"
509-
files, err = c.GetFiles(name)
510-
// logs.Info(files)
511-
if err == http.ErrMissingFile {
512-
c.JsonResult(6003, i18n.Tr(c.Lang, "message.upload_file_empty"))
513-
return
514-
}
490+
names := []string{"editormd-file-file", "editormd-image-file", "file", "editormd-resource-file"}
491+
var files []*multipart.FileHeader
492+
for _, name := range names {
493+
file, err := c.GetFiles(name)
494+
if err != nil {
495+
continue
496+
}
497+
if len(file) > 0 && err == nil {
498+
files = append(files, file...)
515499
}
516500
}
517501

518-
// if err != nil {
519-
// http.Error(w, err.Error(), http.StatusNoContent)
520-
// return
521-
// }
522-
// jMap := make(map[string]interface{})
523-
// s := []map[int]interface{}{}
502+
if len(files) == 0 {
503+
c.JsonResult(6003, i18n.Tr(c.Lang, "message.upload_file_empty"))
504+
return
505+
}
506+
524507
result2 := []map[string]interface{}{}
525508
var result map[string]interface{}
526509
for i, _ := range files {
527510
//for each fileheader, get a handle to the actual file
528511
file, err := files[i].Open()
529512

530513
defer file.Close()
531-
// if err != nil {
532-
// http.Error(w, err.Error(), http.StatusInternalServerError)
533-
// return
534-
// }
535-
// //create destination file making sure the path is writeable.
536-
// dst, err := os.Create("upload/" + files[i].Filename)
537-
// defer dst.Close()
538-
// if err != nil {
539-
// http.Error(w, err.Error(), http.StatusInternalServerError)
540-
// return
541-
// }
542-
// //copy the uploaded file to the destination file
543-
// if _, err := io.Copy(dst, file); err != nil {
544-
// http.Error(w, err.Error(), http.StatusInternalServerError)
545-
// return
546-
// }
547-
// }
548-
// ****
549514

550515
if err != nil {
551516
c.JsonResult(6002, err.Error())
@@ -619,19 +584,25 @@ func (c *DocumentController) Upload() {
619584
filePath := filepath.Join(conf.WorkingDirectory, "uploads", identify)
620585

621586
//将图片和文件分开存放
622-
// if filetil.IsImageExt(moreFile.Filename) {
587+
attachment := models.NewAttachment()
588+
var strategy filetil.FileTypeStrategy
623589
if filetil.IsImageExt(files[i].Filename) {
624-
filePath = filepath.Join(filePath, "images", fileName+ext)
590+
strategy = filetil.ImageStrategy{}
591+
attachment.ResourceType = "image"
592+
} else if filetil.IsVideoExt(files[i].Filename) {
593+
strategy = filetil.VideoStrategy{}
594+
attachment.ResourceType = "video"
625595
} else {
626-
filePath = filepath.Join(filePath, "files", fileName+ext)
596+
strategy = filetil.DefaultStrategy{}
597+
attachment.ResourceType = "file"
627598
}
628599

600+
filePath = strategy.GetFilePath(filePath, fileName, ext)
601+
629602
path := filepath.Dir(filePath)
630603

631604
_ = os.MkdirAll(path, os.ModePerm)
632605

633-
// err = c.SaveToFile(name, filePath) // frome beego controller.go: savetofile it only operates the first one of mutil-upload form file field.
634-
635606
//copy the uploaded file to the destination file
636607
dst, err := os.Create(filePath)
637608
defer dst.Close()
@@ -640,12 +611,6 @@ func (c *DocumentController) Upload() {
640611
c.JsonResult(6005, i18n.Tr(c.Lang, "message.failed"))
641612
}
642613

643-
// if err != nil {
644-
// logs.Error("保存文件失败 -> ", err)
645-
// c.JsonResult(6005, i18n.Tr(c.Lang, "message.failed"))
646-
// }
647-
648-
attachment := models.NewAttachment()
649614
attachment.BookId = bookId
650615
// attachment.FileName = moreFile.Filename
651616
attachment.FileName = files[i].Filename
@@ -662,8 +627,7 @@ func (c *DocumentController) Upload() {
662627
attachment.DocumentId = docId
663628
}
664629

665-
// if filetil.IsImageExt(moreFile.Filename) {
666-
if filetil.IsImageExt(files[i].Filename) {
630+
if filetil.IsImageExt(files[i].Filename) || filetil.IsVideoExt(files[i].Filename) {
667631
attachment.HttpPath = "/" + strings.Replace(strings.TrimPrefix(filePath, conf.WorkingDirectory), "\\", "/", -1)
668632
if strings.HasPrefix(attachment.HttpPath, "//") {
669633
attachment.HttpPath = conf.URLForWithCdnImage(string(attachment.HttpPath[1:]))
@@ -689,19 +653,20 @@ func (c *DocumentController) Upload() {
689653
}
690654
}
691655
result = map[string]interface{}{
692-
"errcode": 0,
693-
"success": 1,
694-
"message": "ok",
695-
"url": attachment.HttpPath,
696-
"link": attachment.HttpPath,
697-
"alt": attachment.FileName,
698-
"is_attach": isAttach,
699-
"attach": attachment,
656+
"errcode": 0,
657+
"success": 1,
658+
"message": "ok",
659+
"url": attachment.HttpPath,
660+
"link": attachment.HttpPath,
661+
"alt": attachment.FileName,
662+
"is_attach": isAttach,
663+
"attach": attachment,
664+
"resource_type": attachment.ResourceType,
700665
}
701666
result2 = append(result2, result)
702667
}
703-
if name == "file" {
704-
// froala单图片上传
668+
if len(files) == 1 {
669+
// froala单文件上传
705670
c.Ctx.Output.JSON(result, true, false)
706671
} else {
707672
c.Ctx.Output.JSON(result2, true, false)

models/AttachmentModel.go

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type Attachment struct {
3333
FileExt string `orm:"column(file_ext);size(50);description(文件后缀)" json:"file_ext"`
3434
CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add;description(创建时间)" json:"create_time"`
3535
CreateAt int `orm:"column(create_at);type(int);description(创建人id)" json:"create_at"`
36+
ResourceType string `orm:"-" json:"resource_type"`
3637
}
3738

3839
// TableName 获取对应上传附件数据库表名.

static/css/markdown.preview.css

+21-7
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
width: 100%;
2121
overflow: auto;
2222
border-bottom: none;
23-
line-height: 1.5
23+
line-height: 1.5;
24+
display: table;
2425
}
2526

2627
.editormd-preview-container table td,.editormd-preview-container table th {
@@ -50,30 +51,43 @@
5051
width: 100%;
5152
}
5253

54+
.whole-article-wrap {
55+
display: flex;
56+
flex-direction: column;
57+
}
58+
5359
.article-body .markdown-toc{
5460
position: fixed;
55-
right: 0;
61+
right: 50px;
5662
width: 260px;
5763
font-size: 12px;
58-
margin-top: -70px;
5964
overflow: auto;
60-
margin-right: 50px;
65+
border: 1px solid #e8e8e8;
66+
border-radius: 6px;
6167
}
6268
.markdown-toc ul{
6369
list-style:none;
6470
}
71+
72+
.markdown-toc-list {
73+
padding:20px 0 !important;
74+
margin-bottom: 0 !important;
75+
}
76+
6577
.markdown-toc .markdown-toc-list>li{
6678
padding: 3px 10px 3px 16px;
6779
line-height: 18px;
68-
border-left: 2px solid #e8e8e8;
80+
/*border-left: 2px solid #e8e8e8;*/
6981
color: #595959;
82+
margin-left: -2px;
7083
}
7184
.markdown-toc .markdown-toc-list>li.active{
7285
border-right: 2px solid #25b864;
7386
}
7487

7588
.article-body .markdown-article{
76-
margin-right: 250px;
89+
width: calc(100% - 260px);
90+
/*margin-right: 250px;*/
7791
}
7892
.article-body.content .markdown-toc{
7993
position: relative;
@@ -86,7 +100,7 @@
86100
.markdown-toc-list .directory-item {
87101
padding: 3px 10px 3px 16px;
88102
line-height: 18px;
89-
border-left: 2px solid #e8e8e8;
103+
/*border-left: 2px solid #e8e8e8;*/
90104
color: #595959;
91105
}
92106
.markdown-toc-list .directory-item-link {

static/editor.md/css/editormd.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -3594,7 +3594,7 @@
35943594
background-color: #f8f8f8;
35953595
}
35963596

3597-
.markdown-body img {
3597+
.markdown-body img, .markdown-body video {
35983598
max-width: 100%;
35993599
-moz-box-sizing: border-box;
36003600
box-sizing: border-box;

static/editor.md/css/editormd.preview.css

+2-1
Original file line numberDiff line numberDiff line change
@@ -2878,7 +2878,8 @@
28782878
background-color: #f8f8f8;
28792879
}
28802880

2881-
.markdown-body img {
2881+
2882+
.markdown-body img, .markdown-body video {
28822883
max-width: 100%;
28832884
-moz-box-sizing: border-box;
28842885
box-sizing: border-box;

static/js/editor.js

+79
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,85 @@ function uploadImage($id, $callback) {
437437
});
438438
}
439439

440+
441+
function uploadResource($id, $callback) {
442+
locales = {
443+
'zh-CN': {
444+
unsupportType: '不支持的图片/视频格式',
445+
uploadFailed: '图片/视频上传失败'
446+
},
447+
'en': {
448+
unsupportType: 'Unsupport image/video type',
449+
uploadFailed: 'Upload image/video failed'
450+
}
451+
}
452+
/** 粘贴上传的资源 **/
453+
document.getElementById($id).addEventListener('paste', function (e) {
454+
if (e.clipboardData && e.clipboardData.items) {
455+
var clipboard = e.clipboardData;
456+
for (var i = 0, len = clipboard.items.length; i < len; i++) {
457+
if (clipboard.items[i].kind === 'file' || clipboard.items[i].type.indexOf('image') > -1) {
458+
459+
var resource = clipboard.items[i].getAsFile();
460+
461+
var fileName = String((new Date()).valueOf());
462+
console.log(resource.type)
463+
switch (resource.type) {
464+
case "image/png" :
465+
fileName += ".png";
466+
break;
467+
case "image/jpg" :
468+
fileName += ".jpg";
469+
break;
470+
case "image/jpeg" :
471+
fileName += ".jpeg";
472+
break;
473+
case "image/gif" :
474+
fileName += ".gif";
475+
break;
476+
case "video/mp4":
477+
fileName += ".mp4";
478+
break;
479+
case "video/webm":
480+
fileName += ".webm";
481+
break;
482+
default :
483+
layer.msg(locales[lang].unsupportType);
484+
return;
485+
}
486+
var form = new FormData();
487+
488+
form.append('editormd-resource-file', resource, fileName);
489+
490+
var layerIndex = 0;
491+
492+
$.ajax({
493+
url: window.imageUploadURL,
494+
type: "POST",
495+
dataType: "json",
496+
data: form,
497+
processData: false,
498+
contentType: false,
499+
beforeSend: function () {
500+
layerIndex = $callback('before');
501+
},
502+
error: function () {
503+
layer.close(layerIndex);
504+
$callback('error');
505+
layer.msg(locales[lang].uploadFailed);
506+
},
507+
success: function (data) {
508+
layer.close(layerIndex);
509+
$callback('success', data);
510+
}
511+
});
512+
e.preventDefault();
513+
}
514+
}
515+
}
516+
});
517+
}
518+
440519
/**
441520
* 初始化代码高亮
442521
*/

0 commit comments

Comments
 (0)