Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
F
front-backend
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
framework
front-backend
Commits
4ccb6cb8
Commit
4ccb6cb8
authored
Dec 20, 2019
by
Elune
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
优化图片上传,加入图床同步功能
parent
b9b48e13
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
272 additions
and
75 deletions
+272
-75
src/api/system/timing.js
+4
-3
src/api/tools/picture.js
+8
-1
src/utils/upload.js
+11
-0
src/views/components/Editor.vue
+33
-20
src/views/components/MarkDown.vue
+7
-33
src/views/system/timing/index.vue
+0
-0
src/views/tools/email/send.vue
+24
-18
src/views/tools/picture/index.vue
+185
-0
No files found.
src/api/system/timing.js
View file @
4ccb6cb8
...
@@ -8,10 +8,11 @@ export function add(data) {
...
@@ -8,10 +8,11 @@ export function add(data) {
})
})
}
}
export
function
del
(
id
)
{
export
function
del
(
id
s
)
{
return
request
({
return
request
({
url
:
'api/jobs/'
+
id
,
url
:
'api/jobs'
,
method
:
'delete'
method
:
'delete'
,
data
:
ids
})
})
}
}
...
...
src/api/tools/picture.js
View file @
4ccb6cb8
...
@@ -8,4 +8,11 @@ export function del(ids) {
...
@@ -8,4 +8,11 @@ export function del(ids) {
})
})
}
}
export
default
{
del
}
export
function
sync
()
{
return
request
({
url
:
'api/pictures/synchronize'
,
method
:
'post'
})
}
export
default
{
del
,
sync
}
src/utils/upload.js
0 → 100644
View file @
4ccb6cb8
import
axios
from
'axios'
import
{
getToken
}
from
'@/utils/auth'
export
function
upload
(
api
,
file
)
{
var
data
=
new
FormData
()
data
.
append
(
'file'
,
file
)
const
config
=
{
headers
:
{
'Authorization'
:
getToken
()
}
}
return
axios
.
post
(
api
,
data
,
config
)
}
src/views/components/Editor.vue
View file @
4ccb6cb8
<
template
>
<
template
>
<div>
<div
class=
"app-container"
>
<div
ref=
"editor"
class=
"text"
/>
<p
class=
"warn-content"
>
<div
style=
"margin: 12px 5px;font-size: 16px;font-weight: bold;color: #696969"
>
HTML渲染如下:
</div>
Markdown 基于
<div
class=
"editor-content"
v-html=
"editorContent"
/>
<el-link
type=
"primary"
href=
"https://www.kancloud.cn/wangfupeng/wangeditor3/332599"
target=
"_blank"
>
wangEditor
</el-link>
,图片上传使用
<el-link
type=
"primary"
href=
"https://sm.ms/"
target=
"_blank"
>
SM.MS
</el-link>
</p>
<el-row
:gutter=
"10"
>
<el-col
:xs=
"24"
:sm=
"24"
:md=
"15"
:lg=
"15"
:xl=
"15"
>
<div
ref=
"editor"
class=
"text"
/>
</el-col>
<el-col
:xs=
"24"
:sm=
"24"
:md=
"9"
:lg=
"9"
:xl=
"9"
>
<div
v-html=
"editorContent"
/>
</el-col>
</el-row>
</div>
</div>
</
template
>
</
template
>
<
script
>
<
script
>
import
{
mapGetters
}
from
'vuex'
import
{
mapGetters
}
from
'vuex'
import
{
upload
}
from
'@/utils/upload'
import
E
from
'wangeditor'
import
E
from
'wangeditor'
import
{
getToken
}
from
'@/utils/auth'
export
default
{
export
default
{
name
:
'Editor'
,
name
:
'Editor'
,
data
()
{
data
()
{
return
{
return
{
headers
:
{
'Authorization'
:
getToken
()
},
editorContent
:
editorContent
:
`
<h3 style="text-align: center;">欢迎使用 wangEditor 富文本编辑器!</h3>
`
<ul>
<ul>
<li>富文本中图片上传使用的是
sm.ms图床,支持上传到七牛云
:<a style="color: #42b983" target="_blank" href="https://sm.ms/">sm.ms</a></li>
<li>富文本中图片上传使用的是
SM.MS 图床
:<a style="color: #42b983" target="_blank" href="https://sm.ms/">sm.ms</a></li>
<li>更多帮助请查看官方文档:<a style="color: #42b983" target="_blank" href="https://www.kancloud.cn/wangfupeng/wangeditor3/332599">wangEditor</a></li>
<li>更多帮助请查看官方文档:<a style="color: #42b983" target="_blank" href="https://www.kancloud.cn/wangfupeng/wangeditor3/332599">wangEditor</a></li>
</ul>`
</ul>`
}
}
...
@@ -31,13 +38,20 @@ export default {
...
@@ -31,13 +38,20 @@ export default {
])
])
},
},
mounted
()
{
mounted
()
{
const
_this
=
this
var
editor
=
new
E
(
this
.
$refs
.
editor
)
var
editor
=
new
E
(
this
.
$refs
.
editor
)
editor
.
customConfig
.
uploadImgShowBase64
=
true
// 使用 base64 保存图片
// 自定义菜单配置
// 不可修改
editor
.
customConfig
.
zIndex
=
10
editor
.
customConfig
.
uploadImgHeaders
=
this
.
headers
// 文件上传
// 自定义文件名,不可修改,修改后会上传失败
editor
.
customConfig
.
customUploadImg
=
function
(
files
,
insert
)
{
editor
.
customConfig
.
uploadFileName
=
'file'
// files 是 input 中选中的文件列表
editor
.
customConfig
.
uploadImgServer
=
this
.
imagesUploadApi
// 上传图片到服务器
// insert 是获取图片 url 后,插入到编辑器的方法
files
.
forEach
(
image
=>
{
upload
(
_this
.
imagesUploadApi
,
image
).
then
(
data
=>
{
insert
(
data
.
data
.
url
)
})
})
}
editor
.
customConfig
.
onchange
=
(
html
)
=>
{
editor
.
customConfig
.
onchange
=
(
html
)
=>
{
this
.
editorContent
=
html
this
.
editorContent
=
html
}
}
...
@@ -49,11 +63,10 @@ export default {
...
@@ -49,11 +63,10 @@ export default {
</
script
>
</
script
>
<
style
scoped
>
<
style
scoped
>
.editor-content
{
padding-left
:
5px
;
}
.text
{
.text
{
text-align
:
left
;
text-align
:
left
;
margin
:
5px
}
/
deep
/
.w-e-text-container
{
height
:
420px
!important
;
}
}
</
style
>
</
style
>
src/views/components/MarkDown.vue
View file @
4ccb6cb8
...
@@ -2,24 +2,21 @@
...
@@ -2,24 +2,21 @@
<div
class=
"app-container"
>
<div
class=
"app-container"
>
<p
class=
"warn-content"
>
<p
class=
"warn-content"
>
Markdown 基于
Markdown 基于
<a
href=
"https://github.com/hinesboy/mavonEditor"
target=
"_blank"
>
mavonEditor
</a>
<el-link
type=
"primary"
href=
"https://github.com/hinesboy/mavonEditor"
target=
"_blank"
>
MavonEditor
</el-link>
,图片上传使用
<el-link
type=
"primary"
href=
"https://sm.ms/"
target=
"_blank"
>
SM.MS
</el-link>
</p>
</p>
<mavon-editor
ref=
"md"
:style=
"'height:' + height"
@
imgAdd=
"imgAdd"
@
imgDel=
"imgDel"
/>
<mavon-editor
ref=
"md"
:style=
"'height:' + height"
@
imgAdd=
"imgAdd"
/>
</div>
</div>
</
template
>
</
template
>
<
script
>
<
script
>
import
axios
from
'axios
'
import
{
upload
}
from
'@/utils/upload
'
import
{
mapGetters
}
from
'vuex'
import
{
mapGetters
}
from
'vuex'
import
{
getToken
}
from
'@/utils/auth'
import
{
del
}
from
'@/api/tools/picture'
export
default
{
export
default
{
name
:
'Markdown'
,
name
:
'Markdown'
,
data
()
{
data
()
{
return
{
return
{
height
:
document
.
documentElement
.
clientHeight
-
200
+
'px'
,
height
:
document
.
documentElement
.
clientHeight
-
200
+
'px'
data
:
null
,
images
:
{}
}
}
},
},
computed
:
{
computed
:
{
...
@@ -28,7 +25,6 @@ export default {
...
@@ -28,7 +25,6 @@ export default {
])
])
},
},
mounted
()
{
mounted
()
{
this
.
$refs
.
md
.
$refs
.
toolbar_left
.
img_file
=
[]
const
that
=
this
const
that
=
this
window
.
onresize
=
function
temp
()
{
window
.
onresize
=
function
temp
()
{
that
.
height
=
document
.
documentElement
.
clientHeight
-
200
+
'px'
that
.
height
=
document
.
documentElement
.
clientHeight
-
200
+
'px'
...
@@ -36,31 +32,9 @@ export default {
...
@@ -36,31 +32,9 @@ export default {
},
},
methods
:
{
methods
:
{
imgAdd
(
pos
,
$file
)
{
imgAdd
(
pos
,
$file
)
{
var
formdata
=
new
FormData
()
upload
(
this
.
imagesUploadApi
,
$file
).
then
(
data
=>
{
formdata
.
append
(
'file'
,
$file
)
this
.
$refs
.
md
.
$img2Url
(
pos
,
data
.
data
.
url
)
axios
({
url
:
this
.
imagesUploadApi
,
method
:
'post'
,
data
:
formdata
,
headers
:
{
'Content-Type'
:
'multipart/form-data'
,
'Authorization'
:
getToken
()
}
}).
then
((
data
)
=>
{
this
.
data
=
data
.
data
this
.
$refs
.
md
.
$img2Url
(
pos
,
this
.
data
.
data
[
0
])
this
.
images
[
this
.
data
.
data
[
0
]]
=
this
.
data
}).
catch
((
error
)
=>
{
console
.
log
(
'image upload error'
,
error
)
this
.
$refs
.
md
.
$refs
.
toolbar_left
.
$imgDel
(
pos
)
})
})
},
imgDel
(
file
,
pos
)
{
const
image
=
this
.
images
[
file
[
1
]]
if
(
image
)
{
del
(
image
.
id
).
then
(
res
=>
{
}).
catch
(
err
=>
{
console
.
log
(
err
.
response
.
data
.
message
)
})
}
}
}
}
}
}
}
...
...
src/views/system/timing/index.vue
View file @
4ccb6cb8
This diff is collapsed.
Click to expand it.
src/views/tools/email/send.vue
View file @
4ccb6cb8
...
@@ -2,14 +2,14 @@
...
@@ -2,14 +2,14 @@
<div>
<div>
<el-form
ref=
"form"
:model=
"form"
:rules=
"rules"
style=
"margin-top: 6px;"
size=
"small"
label-width=
"100px"
>
<el-form
ref=
"form"
:model=
"form"
:rules=
"rules"
style=
"margin-top: 6px;"
size=
"small"
label-width=
"100px"
>
<el-form-item
label=
"邮件标题"
prop=
"subject"
>
<el-form-item
label=
"邮件标题"
prop=
"subject"
>
<el-input
v-model=
"form.subject"
style=
"width:
40%
"
/>
<el-input
v-model=
"form.subject"
style=
"width:
646px
"
/>
</el-form-item>
</el-form-item>
<el-form-item
<el-form-item
v-for=
"(domain, index) in tos"
v-for=
"(domain, index) in tos"
:key=
"domain.key"
:key=
"domain.key"
:label=
"'收件邮箱' + (index === 0 ? '': index)"
:label=
"'收件邮箱' + (index === 0 ? '': index)"
>
>
<el-input
v-model=
"domain.value"
style=
"width:
31%
"
/>
<el-input
v-model=
"domain.value"
style=
"width:
550px
"
/>
<el-button
icon=
"el-icon-plus"
@
click=
"addDomain"
/>
<el-button
icon=
"el-icon-plus"
@
click=
"addDomain"
/>
<el-button
style=
"margin-left:0;"
icon=
"el-icon-minus"
@
click
.
prevent=
"removeDomain(domain)"
/>
<el-button
style=
"margin-left:0;"
icon=
"el-icon-minus"
@
click
.
prevent=
"removeDomain(domain)"
/>
</el-form-item>
</el-form-item>
...
@@ -20,18 +20,15 @@
...
@@ -20,18 +20,15 @@
</
template
>
</
template
>
<
script
>
<
script
>
import
{
mapGetters
}
from
'vuex'
import
{
getToken
}
from
'@/utils/auth'
import
{
send
}
from
'@/api/tools/email'
import
{
send
}
from
'@/api/tools/email'
import
{
upload
}
from
'@/utils/upload'
import
{
validEmail
}
from
'@/utils/validate'
import
{
validEmail
}
from
'@/utils/validate'
import
{
mapGetters
}
from
'vuex'
import
E
from
'wangeditor'
import
E
from
'wangeditor'
export
default
{
export
default
{
name
:
'Index'
,
name
:
'Index'
,
data
()
{
data
()
{
return
{
return
{
headers
:
{
'Authorization'
:
getToken
()
},
loading
:
false
,
form
:
{
subject
:
''
,
tos
:
[],
content
:
''
},
loading
:
false
,
form
:
{
subject
:
''
,
tos
:
[],
content
:
''
},
tos
:
[{
tos
:
[{
value
:
''
value
:
''
...
@@ -45,21 +42,26 @@ export default {
...
@@ -45,21 +42,26 @@ export default {
},
},
computed
:
{
computed
:
{
...
mapGetters
([
...
mapGetters
([
// sm.ms图床
'imagesUploadApi'
'imagesUploadApi'
,
// 七牛云 按需选择
'qiNiuUploadApi'
])
])
},
},
mounted
()
{
mounted
()
{
const
_this
=
this
var
editor
=
new
E
(
this
.
$refs
.
editor
)
var
editor
=
new
E
(
this
.
$refs
.
editor
)
editor
.
customConfig
.
uploadImgShowBase64
=
true
// 使用 base64 保存图片
// 自定义菜单配置
// 不可修改
editor
.
customConfig
.
zIndex
=
10
editor
.
customConfig
.
uploadImgHeaders
=
this
.
headers
// 文件上传
// 自定义文件名,不可修改,修改后会上传失败
editor
.
customConfig
.
customUploadImg
=
function
(
files
,
insert
)
{
editor
.
customConfig
.
uploadFileName
=
'file'
// files 是 input 中选中的文件列表
// 上传到哪儿,按需选择
// insert 是获取图片 url 后,插入到编辑器的方法
editor
.
customConfig
.
uploadImgServer
=
this
.
imagesUploadApi
// 上传图片到服务器
files
.
forEach
(
image
=>
{
files
.
forEach
(
image
=>
{
upload
(
_this
.
imagesUploadApi
,
image
).
then
(
data
=>
{
insert
(
data
.
data
.
url
)
})
})
})
}
editor
.
customConfig
.
onchange
=
(
html
)
=>
{
editor
.
customConfig
.
onchange
=
(
html
)
=>
{
this
.
form
.
content
=
html
this
.
form
.
content
=
html
}
}
...
@@ -132,5 +134,9 @@ export default {
...
@@ -132,5 +134,9 @@ export default {
.editor
{
.editor
{
text-align
:
left
;
text-align
:
left
;
margin
:
20px
;
margin
:
20px
;
width
:
730px
;
}
/
deep
/
.w-e-text-container
{
height
:
360px
!important
;
}
}
</
style
>
</
style
>
src/views/tools/picture/index.vue
0 → 100644
View file @
4ccb6cb8
<
template
>
<div
class=
"app-container"
>
<!--工具栏-->
<div
class=
"head-container"
>
<div
v-if=
"crud.props.searchToggle"
>
<!--搜索-->
<el-input
v-model=
"query.filename"
clearable
size=
"small"
placeholder=
"输入文件名"
style=
"width: 200px;"
class=
"filter-item"
@
keyup
.
enter
.
native=
"crud.toQuery"
/>
<el-date-picker
v-model=
"query.createTime"
:default-time=
"['00:00:00','23:59:59']"
type=
"daterange"
range-separator=
":"
size=
"small"
class=
"date-item"
value-format=
"yyyy-MM-dd HH:mm:ss"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
/>
<rrOperation
:crud=
"crud"
/>
</div>
<crudOperation
:permission=
"permission"
>
<!-- 上传 -->
<el-button
slot=
"left"
v-permission=
"['admin','pictures:add']"
class=
"filter-item"
size=
"mini"
type=
"primary"
icon=
"el-icon-upload"
@
click=
"dialog = true"
>
上传
</el-button>
<el-tooltip
slot=
"right"
class=
"item"
effect=
"dark"
content=
"使用同步功能需要在 https://sm.ms/login 中注册账号,并且在 application.yml 文件中修改 Secret Token"
placement=
"top-start"
>
<el-button
v-permission=
"['admin','pictures:add']"
class=
"filter-item"
size=
"mini"
type=
"success"
icon=
"el-icon-upload"
:loading=
"syncLoading"
@
click=
"sync"
>
同步
</el-button>
</el-tooltip>
</crudOperation>
</div>
<!--上传图片-->
<el-dialog
:visible
.
sync=
"dialog"
:close-on-click-modal=
"false"
append-to-body
width=
"600px"
@
close=
"doSubmit"
>
<el-upload
:on-preview=
"handlePictureCardPreview"
:before-remove=
"handleBeforeRemove"
:on-success=
"handleSuccess"
:on-error=
"handleError"
:headers=
"headers"
:file-list=
"fileList"
:action=
"imagesUploadApi"
list-type=
"picture-card"
>
<i
class=
"el-icon-plus"
/>
</el-upload>
<el-dialog
append-to-body
:visible
.
sync=
"dialogVisible"
>
<img
:src=
"dialogImageUrl"
width=
"100%"
alt=
""
>
</el-dialog>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
type=
"primary"
@
click=
"doSubmit"
>
确认
</el-button>
</div>
</el-dialog>
<!--表格渲染-->
<el-table
ref=
"table"
v-loading=
"crud.loading"
:data=
"crud.data"
style=
"width: 100%;"
@
selection-change=
"crud.selectionChangeHandler"
>
<el-table-column
type=
"selection"
width=
"55"
/>
<el-table-column
v-if=
"columns.visible('filename')"
width=
"200"
prop=
"filename"
label=
"文件名"
/>
<el-table-column
v-if=
"columns.visible('username')"
prop=
"username"
label=
"上传者"
/>
<el-table-column
v-if=
"columns.visible('url')"
ref=
"table"
:show-overflow-tooltip=
"true"
prop=
"url"
label=
"缩略图"
>
<template
slot-scope=
"
{row}">
<el-image
:src=
"row.url"
:preview-src-list=
"[row.url]"
fit=
"contain"
lazy
class=
"el-avatar"
/>
</
template
>
</el-table-column>
<el-table-column
v-if=
"columns.visible('size')"
prop=
"size"
label=
"文件大小"
/>
<el-table-column
v-if=
"columns.visible('height')"
prop=
"height"
label=
"高度"
/>
<el-table-column
v-if=
"columns.visible('width')"
prop=
"width"
label=
"宽度"
/>
<el-table-column
v-if=
"columns.visible('createTime')"
prop=
"createTime"
label=
"创建日期"
>
<
template
slot-scope=
"scope"
>
<span>
{{
parseTime
(
scope
.
row
.
createTime
)
}}
</span>
</
template
>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination
/>
</div>
</template>
<
script
>
import
{
mapGetters
}
from
'vuex'
import
crudPic
from
'@/api/tools/picture'
import
CRUD
,
{
presenter
,
header
,
crud
}
from
'@crud/crud'
import
{
getToken
}
from
'@/utils/auth'
import
rrOperation
from
'@crud/RR.operation'
import
crudOperation
from
'@crud/CRUD.operation'
import
pagination
from
'@crud/Pagination'
// crud交由presenter持有
const
defaultCrud
=
CRUD
({
title
:
'图片'
,
url
:
'api/pictures'
,
crudMethod
:
{
...
crudPic
}})
export
default
{
name
:
'Pictures'
,
components
:
{
pagination
,
crudOperation
,
rrOperation
},
mixins
:
[
presenter
(
defaultCrud
),
header
(),
crud
()],
data
()
{
return
{
dialog
:
false
,
syncLoading
:
false
,
headers
:
{
'Authorization'
:
getToken
()
},
permission
:
{
del
:
[
'admin'
,
'pictures:del'
]
},
dialogImageUrl
:
''
,
dialogVisible
:
false
,
fileList
:
[],
pictures
:
[]
}
},
computed
:
{
...
mapGetters
([
'imagesUploadApi'
])
},
created
()
{
this
.
crud
.
optShow
.
add
=
false
this
.
crud
.
optShow
.
edit
=
false
},
methods
:
{
handleSuccess
(
response
,
file
,
fileList
)
{
const
uid
=
file
.
uid
const
id
=
response
.
id
this
.
pictures
.
push
({
uid
,
id
})
},
handleBeforeRemove
(
file
,
fileList
)
{
for
(
let
i
=
0
;
i
<
this
.
pictures
.
length
;
i
++
)
{
if
(
this
.
pictures
[
i
].
uid
===
file
.
uid
)
{
crudPic
.
del
(
this
.
pictures
[
i
].
id
).
then
(
res
=>
{})
return
true
}
}
},
handlePictureCardPreview
(
file
)
{
this
.
dialogImageUrl
=
file
.
url
this
.
dialogVisible
=
true
},
// 刷新列表数据
doSubmit
()
{
this
.
fileList
=
[]
this
.
dialogVisible
=
false
this
.
dialogImageUrl
=
''
this
.
dialog
=
false
this
.
crud
.
toQuery
()
},
// 监听上传失败
handleError
(
e
,
file
,
fileList
)
{
const
msg
=
JSON
.
parse
(
e
.
message
)
this
.
$notify
({
title
:
msg
.
message
,
type
:
'error'
,
duration
:
2500
})
},
sync
()
{
this
.
syncLoading
=
true
crudPic
.
sync
().
then
(
res
=>
{
this
.
crud
.
notify
(
'同步成功'
,
CRUD
.
NOTIFICATION_TYPE
.
SUCCESS
)
this
.
crud
.
toQuery
()
this
.
syncLoading
=
false
})
}
}
}
</
script
>
<
style
scoped
>
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment