Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
Litemall
Commits
6fc6cb6c
Commit
6fc6cb6c
authored
Jun 09, 2019
by
Junling Bu
Browse files
feat[litemall-admin, litemall-wx]: 支持专题商品添加和编辑
parent
82a20dc5
Changes
9
Hide whitespace changes
Inline
Side-by-side
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminTopicController.java
View file @
6fc6cb6c
...
...
@@ -7,7 +7,9 @@ import org.linlinjava.litemall.admin.annotation.RequiresPermissionsDesc;
import
org.linlinjava.litemall.core.util.ResponseUtil
;
import
org.linlinjava.litemall.core.validator.Order
;
import
org.linlinjava.litemall.core.validator.Sort
;
import
org.linlinjava.litemall.db.domain.LitemallGoods
;
import
org.linlinjava.litemall.db.domain.LitemallTopic
;
import
org.linlinjava.litemall.db.service.LitemallGoodsService
;
import
org.linlinjava.litemall.db.service.LitemallTopicService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.util.StringUtils
;
...
...
@@ -16,7 +18,10 @@ import org.springframework.web.bind.annotation.*;
import
javax.validation.constraints.NotNull
;
import
java.math.BigDecimal
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
@RestController
@RequestMapping
(
"/admin/topic"
)
...
...
@@ -26,6 +31,8 @@ public class AdminTopicController {
@Autowired
private
LitemallTopicService
topicService
;
@Autowired
private
LitemallGoodsService
goodsService
;
@RequiresPermissions
(
"admin:topic:list"
)
@RequiresPermissionsDesc
(
menu
={
"推广管理"
,
"专题管理"
},
button
=
"查询"
)
...
...
@@ -72,7 +79,18 @@ public class AdminTopicController {
@GetMapping
(
"/read"
)
public
Object
read
(
@NotNull
Integer
id
)
{
LitemallTopic
topic
=
topicService
.
findById
(
id
);
return
ResponseUtil
.
ok
(
topic
);
Integer
[]
goodsIds
=
topic
.
getGoods
();
List
<
LitemallGoods
>
goodsList
=
null
;
if
(
goodsIds
==
null
||
goodsIds
.
length
==
0
){
goodsList
=
new
ArrayList
<>();
}
else
{
goodsList
=
goodsService
.
queryByIds
(
goodsIds
);
}
Map
<
String
,
Object
>
data
=
new
HashMap
<>(
2
);
data
.
put
(
"topic"
,
topic
);
data
.
put
(
"goodsList"
,
goodsList
);
return
ResponseUtil
.
ok
(
data
);
}
@RequiresPermissions
(
"admin:topic:update"
)
...
...
litemall-admin/src/api/topic.js
View file @
6fc6cb6c
...
...
@@ -16,11 +16,11 @@ export function createTopic(data) {
})
}
export
function
readTopic
(
data
)
{
export
function
readTopic
(
query
)
{
return
request
({
url
:
'
/topic/read
'
,
method
:
'
get
'
,
data
params
:
query
})
}
...
...
litemall-admin/src/router/index.js
View file @
6fc6cb6c
...
...
@@ -331,6 +331,28 @@ export const asyncRouterMap = [
noCache
:
true
}
},
{
path
:
'
topic-create
'
,
component
:
()
=>
import
(
'
@/views/promotion/topicCreate
'
),
name
:
'
topicCreate
'
,
meta
:
{
perms
:
[
'
POST /admin/topic/create
'
],
title
:
'
专题创建
'
,
noCache
:
true
},
hidden
:
true
},
{
path
:
'
topic-edit
'
,
component
:
()
=>
import
(
'
@/views/promotion/topicEdit
'
),
name
:
'
topicEdit
'
,
meta
:
{
perms
:
[
'
GET /admin/topic/read
'
,
'
POST /admin/topic/update
'
],
title
:
'
专题编辑
'
,
noCache
:
true
},
hidden
:
true
},
{
path
:
'
groupon-rule
'
,
component
:
()
=>
import
(
'
@/views/promotion/grouponRule
'
),
...
...
litemall-admin/src/views/promotion/topic.vue
View file @
6fc6cb6c
...
...
@@ -35,7 +35,7 @@
<el-table-column
align=
"center"
label=
"阅读数量"
prop=
"readCount"
/>
<el-table-column
align=
"center"
label=
"操作"
min-width=
"
2
00"
class-name=
"small-padding fixed-width"
>
<el-table-column
align=
"center"
label=
"操作"
min-width=
"
1
00"
class-name=
"small-padding fixed-width"
>
<
template
slot-scope=
"scope"
>
<el-button
v-permission=
"['POST /admin/topic/update']"
type=
"primary"
size=
"mini"
@
click=
"handleUpdate(scope.row)"
>
编辑
</el-button>
<el-button
v-permission=
"['POST /admin/topic/delete']"
type=
"danger"
size=
"mini"
@
click=
"handleDelete(scope.row)"
>
删除
</el-button>
...
...
@@ -49,44 +49,6 @@
<back-to-top
:visibility-height=
"100"
/>
</el-tooltip>
<!-- 添加或修改对话框 -->
<el-dialog
:title=
"textMap[dialogStatus]"
:visible.sync=
"dialogFormVisible"
>
<el-form
ref=
"dataForm"
:rules=
"rules"
:model=
"dataForm"
status-icon
label-position=
"left"
label-width=
"100px"
style=
"width: 400px; margin-left:50px;"
>
<el-form-item
label=
"专题标题"
prop=
"title"
>
<el-input
v-model=
"dataForm.title"
/>
</el-form-item>
<el-form-item
label=
"专题子标题"
prop=
"subtitle"
>
<el-input
v-model=
"dataForm.subtitle"
/>
</el-form-item>
<el-form-item
label=
"专题图片"
prop=
"picUrl"
>
<el-upload
:headers=
"headers"
:action=
"uploadPath"
:show-file-list=
"false"
:on-success=
"uploadPicUrl"
class=
"avatar-uploader"
accept=
".jpg,.jpeg,.png,.gif"
>
<img
v-if=
"dataForm.picUrl"
:src=
"dataForm.picUrl"
class=
"avatar"
>
<i
v-else
class=
"el-icon-plus avatar-uploader-icon"
/>
</el-upload>
</el-form-item>
<el-form-item
style=
"width: 700px;"
label=
"专题内容"
>
<editor
:init=
"editorInit"
v-model=
"dataForm.content"
/>
</el-form-item>
<el-form-item
label=
"商品低价"
prop=
"price"
>
<el-input
v-model=
"dataForm.price"
/>
</el-form-item>
<el-form-item
label=
"阅读量"
prop=
"readCount"
>
<el-input
v-model=
"dataForm.readCount"
/>
</el-form-item>
</el-form>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"dialogFormVisible = false"
>
取消
</el-button>
<el-button
v-if=
"dialogStatus=='create'"
type=
"primary"
@
click=
"createData"
>
确定
</el-button>
<el-button
v-else
type=
"primary"
@
click=
"updateData"
>
确定
</el-button>
</div>
</el-dialog>
</div>
</template>
...
...
@@ -120,19 +82,15 @@
</
style
>
<
script
>
import
{
listTopic
,
createTopic
,
updateTopic
,
deleteTopic
}
from
'
@/api/topic
'
import
{
createStorage
,
uploadPath
}
from
'
@/api/storage
'
import
{
listTopic
,
deleteTopic
}
from
'
@/api/topic
'
import
BackToTop
from
'
@/components/BackToTop
'
import
Editor
from
'
@tinymce/tinymce-vue
'
import
Pagination
from
'
@/components/Pagination
'
// Secondary package based on el-pagination
import
{
getToken
}
from
'
@/utils/auth
'
export
default
{
name
:
'
Topic
'
,
components
:
{
BackToTop
,
Editor
,
Pagination
},
components
:
{
BackToTop
,
Pagination
},
data
()
{
return
{
uploadPath
,
list
:
[],
total
:
0
,
listLoading
:
true
,
...
...
@@ -143,65 +101,6 @@ export default {
subtitle
:
undefined
,
sort
:
'
add_time
'
,
order
:
'
desc
'
},
dataForm
:
{
id
:
undefined
,
titile
:
undefined
,
subtitle
:
undefined
,
picUrl
:
undefined
,
content
:
''
,
price
:
undefined
,
readCount
:
undefined
,
goods
:
[]
},
contentDetail
:
''
,
contentDialogVisible
:
false
,
dialogFormVisible
:
false
,
dialogStatus
:
''
,
textMap
:
{
update
:
'
编辑
'
,
create
:
'
创建
'
},
rules
:
{
title
:
[
{
required
:
true
,
message
:
'
专题标题不能为空
'
,
trigger
:
'
blur
'
}
],
subtitle
:
[
{
required
:
true
,
message
:
'
专题子标题不能为空
'
,
trigger
:
'
blur
'
}
],
content
:
[
{
required
:
true
,
message
:
'
专题内容不能为空
'
,
trigger
:
'
blur
'
}
]
},
downloadLoading
:
false
,
editorInit
:
{
language
:
'
zh_CN
'
,
convert_urls
:
false
,
plugins
:
[
'
advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount
'
],
toolbar
:
[
'
searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample
'
,
'
hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen
'
],
images_upload_handler
:
function
(
blobInfo
,
success
,
failure
)
{
const
formData
=
new
FormData
()
formData
.
append
(
'
file
'
,
blobInfo
.
blob
())
createStorage
(
formData
)
.
then
(
res
=>
{
success
(
res
.
data
.
data
.
url
)
})
.
catch
(()
=>
{
failure
(
'
上传失败,请重新上传
'
)
})
}
}
}
},
computed
:
{
headers
()
{
return
{
'
X-Litemall-Admin-Token
'
:
getToken
()
}
}
},
...
...
@@ -227,88 +126,11 @@ export default {
this
.
listQuery
.
page
=
1
this
.
getList
()
},
resetForm
()
{
this
.
dataForm
=
{
id
:
undefined
,
titile
:
undefined
,
subtitle
:
undefined
,
picUrl
:
undefined
,
content
:
''
,
price
:
undefined
,
readCount
:
undefined
,
goods
:
[]
}
},
handleCreate
()
{
this
.
resetForm
()
this
.
dialogStatus
=
'
create
'
this
.
dialogFormVisible
=
true
this
.
$nextTick
(()
=>
{
this
.
$refs
[
'
dataForm
'
].
clearValidate
()
})
},
uploadPicUrl
:
function
(
response
)
{
this
.
dataForm
.
picUrl
=
response
.
data
.
url
},
createData
()
{
this
.
$refs
[
'
dataForm
'
].
validate
(
valid
=>
{
if
(
valid
)
{
createTopic
(
this
.
dataForm
)
.
then
(
response
=>
{
this
.
list
.
unshift
(
response
.
data
.
data
)
this
.
dialogFormVisible
=
false
this
.
$notify
.
success
({
title
:
'
成功
'
,
message
:
'
创建专题成功
'
})
})
.
catch
(
response
=>
{
this
.
$notify
.
error
({
title
:
'
失败
'
,
message
:
response
.
data
.
errmsg
})
})
}
})
},
showContent
(
content
)
{
this
.
contentDetail
=
content
this
.
contentDialogVisible
=
true
this
.
$router
.
push
({
path
:
'
/promotion/topic-create
'
})
},
handleUpdate
(
row
)
{
this
.
dataForm
=
Object
.
assign
({},
row
)
this
.
dialogStatus
=
'
update
'
this
.
dialogFormVisible
=
true
this
.
$nextTick
(()
=>
{
this
.
$refs
[
'
dataForm
'
].
clearValidate
()
})
},
updateData
()
{
this
.
$refs
[
'
dataForm
'
].
validate
(
valid
=>
{
if
(
valid
)
{
updateTopic
(
this
.
dataForm
)
.
then
(()
=>
{
for
(
const
v
of
this
.
list
)
{
if
(
v
.
id
===
this
.
dataForm
.
id
)
{
const
index
=
this
.
list
.
indexOf
(
v
)
this
.
list
.
splice
(
index
,
1
,
this
.
dataForm
)
break
}
}
this
.
dialogFormVisible
=
false
this
.
$notify
.
success
({
title
:
'
成功
'
,
message
:
'
更新专题成功
'
})
})
.
catch
(
response
=>
{
this
.
$notify
.
error
({
title
:
'
失败
'
,
message
:
response
.
data
.
errmsg
})
})
}
})
this
.
$router
.
push
({
path
:
'
/promotion/topic-edit
'
,
query
:
{
id
:
row
.
id
}})
},
handleDelete
(
row
)
{
deleteTopic
(
row
)
...
...
litemall-admin/src/views/promotion/topicCreate.vue
0 → 100644
View file @
6fc6cb6c
<
template
>
<div
class=
"app-container"
>
<el-form
ref=
"topic"
:rules=
"rules"
:model=
"topic"
status-icon
label-position=
"left"
label-width=
"100px"
style=
"width: 800px; margin-left:50px;"
>
<el-form-item
label=
"专题标题"
prop=
"title"
>
<el-input
v-model=
"topic.title"
/>
</el-form-item>
<el-form-item
label=
"专题子标题"
prop=
"subtitle"
>
<el-input
v-model=
"topic.subtitle"
/>
</el-form-item>
<el-form-item
label=
"专题图片"
prop=
"picUrl"
>
<el-upload
:headers=
"headers"
:action=
"uploadPath"
:show-file-list=
"false"
:on-success=
"uploadPicUrl"
class=
"avatar-uploader"
accept=
".jpg,.jpeg,.png,.gif"
>
<img
v-if=
"topic.picUrl"
:src=
"topic.picUrl"
class=
"avatar"
>
<i
v-else
class=
"el-icon-plus avatar-uploader-icon"
/>
</el-upload>
</el-form-item>
<el-form-item
label=
"专题内容"
prop=
"content"
>
<editor
:init=
"editorInit"
v-model=
"topic.content"
/>
</el-form-item>
<el-form-item
label=
"商品低价"
prop=
"price"
>
<el-input
v-model=
"topic.price"
/>
</el-form-item>
<el-form-item
label=
"阅读量"
prop=
"readCount"
>
<el-input
v-model=
"topic.readCount"
/>
</el-form-item>
<el-form-item
label=
"专题商品"
prop=
"goods"
>
<el-button
style=
"float:right;"
size=
"mini"
type=
"primary"
@
click=
"handleCreate()"
>
创建商品
</el-button>
<!-- 查询结果 -->
<el-table
:data=
"goodsList"
border
fit
highlight-current-row
>
<el-table-column
align=
"center"
label=
"商品ID"
prop=
"id"
/>
<el-table-column
align=
"center"
property=
"picUrl"
label=
"图片"
>
<template
slot-scope=
"scope"
>
<img
:src=
"scope.row.picUrl"
width=
"60"
>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"商品名称"
prop=
"name"
/>
<el-table-column
align=
"center"
label=
"商品介绍"
prop=
"brief"
/>
<el-table-column
align=
"center"
label=
"操作"
class-name=
"small-padding fixed-width"
>
<
template
slot-scope=
"scope"
>
<el-button
type=
"danger"
size=
"mini"
@
click=
"handleDelete(scope.row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"handleCancel"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleConfirm"
>
确定
</el-button>
</div>
<el-dialog
:visible.sync=
"addVisiable"
title=
"添加商品"
>
<div
class=
"search"
>
<el-input
v-model=
"listQuery.goodsSn"
clearable
class=
"filter-item"
style=
"width: 200px;"
placeholder=
"请输入商品编号"
/>
<el-input
v-model=
"listQuery.name"
clearable
class=
"filter-item"
style=
"width: 200px;"
placeholder=
"请输入商品名称"
/>
<el-button
class=
"filter-item"
type=
"primary"
icon=
"el-icon-search"
@
click=
"handleFilter"
>
查找
</el-button>
<el-table
v-loading=
"listLoading"
:data=
"list"
element-loading-text=
"正在查询中。。。"
border
fit
highlight-current-row
@
selection-change=
"handleSelectionChange"
>
<el-table-column
type=
"selection"
width=
"55"
/>
<el-table-column
align=
"center"
label=
"商品ID"
prop=
"id"
/>
<el-table-column
align=
"center"
property=
"picUrl"
label=
"图片"
>
<
template
slot-scope=
"scope"
>
<img
:src=
"scope.row.picUrl"
width=
"40"
>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"商品名称"
prop=
"name"
/>
</el-table>
<pagination
v-show=
"total>0"
:total=
"total"
:page.sync=
"listQuery.page"
:limit.sync=
"listQuery.limit"
@
pagination=
"getList"
/>
</div>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"addVisiable = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"confirmAdd"
>
确定
</el-button>
</div>
</el-dialog>
</div>
</template>
<
style
>
.el-dialog
{
width
:
800px
;
}
.avatar-uploader
.el-upload
{
border
:
1px
dashed
#d9d9d9
;
border-radius
:
6px
;
cursor
:
pointer
;
position
:
relative
;
overflow
:
hidden
;
}
.avatar-uploader
.el-upload
:hover
{
border-color
:
#20a0ff
;
}
.avatar-uploader-icon
{
font-size
:
28px
;
color
:
#8c939d
;
width
:
120px
;
height
:
120px
;
line-height
:
120px
;
text-align
:
center
;
}
.avatar
{
width
:
145px
;
height
:
145px
;
display
:
block
;
}
</
style
>
<
script
>
import
{
createTopic
}
from
'
@/api/topic
'
import
{
listGoods
}
from
'
@/api/goods
'
import
{
createStorage
,
uploadPath
}
from
'
@/api/storage
'
import
BackToTop
from
'
@/components/BackToTop
'
import
Editor
from
'
@tinymce/tinymce-vue
'
import
Pagination
from
'
@/components/Pagination
'
// Secondary package based on el-pagination
import
{
getToken
}
from
'
@/utils/auth
'
export
default
{
name
:
'
TopicEdit
'
,
components
:
{
BackToTop
,
Editor
,
Pagination
},
data
()
{
return
{
uploadPath
,
id
:
0
,
topic
:
{
goods
:
[]
},
goodsList
:
[],
addVisiable
:
false
,
list
:
[],
total
:
0
,
listLoading
:
false
,
listQuery
:
{
page
:
1
,
limit
:
5
,
id
:
undefined
,
name
:
undefined
,
sort
:
'
add_time
'
,
order
:
'
desc
'
},
selectedlist
:
[],
rules
:
{
title
:
[
{
required
:
true
,
message
:
'
专题标题不能为空
'
,
trigger
:
'
blur
'
}
],
subtitle
:
[
{
required
:
true
,
message
:
'
专题子标题不能为空
'
,
trigger
:
'
blur
'
}
],
content
:
[
{
required
:
true
,
message
:
'
专题内容不能为空
'
,
trigger
:
'
blur
'
}
],
price
:
[
{
required
:
true
,
message
:
'
专题低价不能为空
'
,
trigger
:
'
blur
'
}
]
},
editorInit
:
{
language
:
'
zh_CN
'
,
convert_urls
:
false
,
height
:
500
,
plugins
:
[
'
advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount
'
],
toolbar
:
[
'
searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample
'
,
'
hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen
'
],
images_upload_handler
:
function
(
blobInfo
,
success
,
failure
)
{
const
formData
=
new
FormData
()
formData
.
append
(
'
file
'
,
blobInfo
.
blob
())
createStorage
(
formData
)
.
then
(
res
=>
{
success
(
res
.
data
.
data
.
url
)
})
.
catch
(()
=>
{
failure
(
'
上传失败,请重新上传
'
)
})
}
}
}
},
computed
:
{
headers
()
{
return
{
'
X-Litemall-Admin-Token
'
:
getToken
()
}
}
},
created
()
{
},
methods
:
{
getList
()
{
this
.
listLoading
=
true
listGoods
(
this
.
listQuery
).
then
(
response
=>
{
this
.
list
=
response
.
data
.
data
.
list
this
.
total
=
response
.
data
.
data
.
total
this
.
listLoading
=
false
}).
catch
(()
=>
{
this
.
list
=
[]
this
.
total
=
0
this
.
listLoading
=
false
})
},
handleFilter
()
{
this
.
listQuery
.
page
=
1
this
.
getList
()
},
handleSelectionChange
(
val
)
{
this
.
selectedlist
=
val
},
uploadPicUrl
:
function
(
response
)
{
this
.
topic
.
picUrl
=
response
.
data
.
url
},
handleCreate
()
{
this
.
listQuery
=
{
page
:
1
,
limit
:
5
,
id
:
undefined
,
name
:
undefined
,
sort
:
'
add_time
'
,
order
:
'
desc
'
}
this
.
list
=
[]
this
.
total
=
0
this
.
selectedlist
=
[]
this
.
addVisiable
=
true
},
confirmAdd
()
{
const
newGoodsIds
=
[]
const
newGoodsList
=
[]
this
.
selectedlist
.
forEach
(
item
=>
{
const
id
=
item
.
id
let
found
=
false
this
.
topic
.
goods
.
forEach
(
goodsId
=>
{
if
(
id
===
goodsId
)
{
found
=
true
}
})
if
(
!
found
)
{
newGoodsIds
.
push
(
id
)
newGoodsList
.
push
(
item
)
}
})
if
(
newGoodsIds
.
length
>
0
)
{
this
.
topic
.
goods
=
this
.
topic
.
goods
.
concat
(
newGoodsIds
)
this
.
goodsList
=
this
.
goodsList
.
concat
(
newGoodsList
)
}
this
.
addVisiable
=
false
},
handleDelete
(
row
)
{
for
(
var
index
=
0
;
index
<
this
.
topic
.
goods
.
length
;
index
++
)
{
if
(
row
.
id
===
this
.
topic
.
goods
[
index
])
{
this
.
topic
.
goods
.
splice
(
index
,
1
)
}
}
for
(
var
index2
=
0
;
index2
<
this
.
goodsList
.
length
;
index2
++
)
{
if
(
row
.
id
===
this
.
goodsList
[
index2
].
id
)
{
this
.
goodsList
.
splice
(
index2
,
1
)
}
}
},
handleCancel
()
{
this
.
$router
.
push
({
path
:
'
/promotion/topic
'
})
},
handleConfirm
()
{
this
.
$refs
[
'
topic
'
].
validate
(
valid
=>
{
if
(
valid
)
{
createTopic
(
this
.
topic
).
then
(
response
=>
{
this
.
$router
.
push
({
path
:
'
/promotion/topic
'
})
})
.
catch
(
response
=>
{
this
.
$notify
.
error
({
title
:
'
失败
'
,
message
:
response
.
data
.
errmsg
})
})
}
})
}
}
}
</
script
>
litemall-admin/src/views/promotion/topicEdit.vue
0 → 100644
View file @
6fc6cb6c
<
template
>
<div
class=
"app-container"
>
<el-form
ref=
"topic"
:rules=
"rules"
:model=
"topic"
status-icon
label-position=
"left"
label-width=
"100px"
style=
"width: 800px; margin-left:50px;"
>
<el-form-item
label=
"专题标题"
prop=
"title"
>
<el-input
v-model=
"topic.title"
/>
</el-form-item>
<el-form-item
label=
"专题子标题"
prop=
"subtitle"
>
<el-input
v-model=
"topic.subtitle"
/>
</el-form-item>
<el-form-item
label=
"专题图片"
prop=
"picUrl"
>
<el-upload
:headers=
"headers"
:action=
"uploadPath"
:show-file-list=
"false"
:on-success=
"uploadPicUrl"
class=
"avatar-uploader"
accept=
".jpg,.jpeg,.png,.gif"
>
<img
v-if=
"topic.picUrl"
:src=
"topic.picUrl"
class=
"avatar"
>
<i
v-else
class=
"el-icon-plus avatar-uploader-icon"
/>
</el-upload>
</el-form-item>
<el-form-item
label=
"专题内容"
prop=
"content"
>
<editor
:init=
"editorInit"
v-model=
"topic.content"
/>
</el-form-item>
<el-form-item
label=
"商品低价"
prop=
"price"
>
<el-input
v-model=
"topic.price"
/>
</el-form-item>
<el-form-item
label=
"阅读量"
prop=
"readCount"
>
<el-input
v-model=
"topic.readCount"
/>
</el-form-item>
<el-form-item
label=
"专题商品"
prop=
"goods"
>
<el-button
style=
"float:right;"
size=
"mini"
type=
"primary"
@
click=
"handleCreate()"
>
创建商品
</el-button>
<!-- 查询结果 -->
<el-table
:data=
"goodsList"
border
fit
highlight-current-row
>
<el-table-column
align=
"center"
label=
"商品ID"
prop=
"id"
/>
<el-table-column
align=
"center"
property=
"picUrl"
label=
"图片"
>
<template
slot-scope=
"scope"
>
<img
:src=
"scope.row.picUrl"
width=
"60"
>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"商品名称"
prop=
"name"
/>
<el-table-column
align=
"center"
label=
"商品介绍"
prop=
"brief"
/>
<el-table-column
align=
"center"
label=
"操作"
class-name=
"small-padding fixed-width"
>
<
template
slot-scope=
"scope"
>
<el-button
type=
"danger"
size=
"mini"
@
click=
"handleDelete(scope.row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"handleCancel"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleConfirm"
>
确定
</el-button>
</div>
<el-dialog
:visible.sync=
"addVisiable"
title=
"添加商品"
>
<div
class=
"search"
>
<el-input
v-model=
"listQuery.goodsSn"
clearable
class=
"filter-item"
style=
"width: 200px;"
placeholder=
"请输入商品编号"
/>
<el-input
v-model=
"listQuery.name"
clearable
class=
"filter-item"
style=
"width: 200px;"
placeholder=
"请输入商品名称"
/>
<el-button
class=
"filter-item"
type=
"primary"
icon=
"el-icon-search"
@
click=
"handleFilter"
>
查找
</el-button>
<el-table
v-loading=
"listLoading"
:data=
"list"
element-loading-text=
"正在查询中。。。"
border
fit
highlight-current-row
@
selection-change=
"handleSelectionChange"
>
<el-table-column
type=
"selection"
width=
"55"
/>
<el-table-column
align=
"center"
label=
"商品ID"
prop=
"id"
/>
<el-table-column
align=
"center"
property=
"picUrl"
label=
"图片"
>
<
template
slot-scope=
"scope"
>
<img
:src=
"scope.row.picUrl"
width=
"40"
>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"商品名称"
prop=
"name"
/>
</el-table>
<pagination
v-show=
"total>0"
:total=
"total"
:page.sync=
"listQuery.page"
:limit.sync=
"listQuery.limit"
@
pagination=
"getList"
/>
</div>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"addVisiable = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"confirmAdd"
>
确定
</el-button>
</div>
</el-dialog>
</div>
</template>
<
style
>
.el-dialog
{
width
:
800px
;
}
.avatar-uploader
.el-upload
{
border
:
1px
dashed
#d9d9d9
;
border-radius
:
6px
;
cursor
:
pointer
;
position
:
relative
;
overflow
:
hidden
;
}
.avatar-uploader
.el-upload
:hover
{
border-color
:
#20a0ff
;
}
.avatar-uploader-icon
{
font-size
:
28px
;
color
:
#8c939d
;
width
:
120px
;
height
:
120px
;
line-height
:
120px
;
text-align
:
center
;
}
.avatar
{
width
:
145px
;
height
:
145px
;
display
:
block
;
}
</
style
>
<
script
>
import
{
readTopic
,
updateTopic
}
from
'
@/api/topic
'
import
{
listGoods
}
from
'
@/api/goods
'
import
{
createStorage
,
uploadPath
}
from
'
@/api/storage
'
import
BackToTop
from
'
@/components/BackToTop
'
import
Editor
from
'
@tinymce/tinymce-vue
'
import
Pagination
from
'
@/components/Pagination
'
// Secondary package based on el-pagination
import
{
getToken
}
from
'
@/utils/auth
'
export
default
{
name
:
'
TopicEdit
'
,
components
:
{
BackToTop
,
Editor
,
Pagination
},
data
()
{
return
{
uploadPath
,
id
:
0
,
topic
:
{},
goodsList
:
[],
addVisiable
:
false
,
list
:
[],
total
:
0
,
listLoading
:
false
,
listQuery
:
{
page
:
1
,
limit
:
5
,
id
:
undefined
,
name
:
undefined
,
sort
:
'
add_time
'
,
order
:
'
desc
'
},
selectedlist
:
[],
rules
:
{
title
:
[
{
required
:
true
,
message
:
'
专题标题不能为空
'
,
trigger
:
'
blur
'
}
],
subtitle
:
[
{
required
:
true
,
message
:
'
专题子标题不能为空
'
,
trigger
:
'
blur
'
}
],
content
:
[
{
required
:
true
,
message
:
'
专题内容不能为空
'
,
trigger
:
'
blur
'
}
],
price
:
[
{
required
:
true
,
message
:
'
专题低价不能为空
'
,
trigger
:
'
blur
'
}
]
},
editorInit
:
{
language
:
'
zh_CN
'
,
convert_urls
:
false
,
height
:
500
,
plugins
:
[
'
advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount
'
],
toolbar
:
[
'
searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample
'
,
'
hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen
'
],
images_upload_handler
:
function
(
blobInfo
,
success
,
failure
)
{
const
formData
=
new
FormData
()
formData
.
append
(
'
file
'
,
blobInfo
.
blob
())
createStorage
(
formData
)
.
then
(
res
=>
{
success
(
res
.
data
.
data
.
url
)
})
.
catch
(()
=>
{
failure
(
'
上传失败,请重新上传
'
)
})
}
}
}
},
computed
:
{
headers
()
{
return
{
'
X-Litemall-Admin-Token
'
:
getToken
()
}
}
},
created
()
{
if
(
this
.
$route
.
query
.
id
==
null
)
{
return
}
this
.
id
=
this
.
$route
.
query
.
id
this
.
getTopic
()
},
methods
:
{
getTopic
()
{
this
.
listLoading
=
true
readTopic
({
id
:
this
.
id
})
.
then
(
response
=>
{
this
.
topic
=
response
.
data
.
data
.
topic
this
.
goodsList
=
response
.
data
.
data
.
goodsList
this
.
listLoading
=
false
})
.
catch
(()
=>
{
this
.
topic
=
{}
this
.
goodsList
=
[]
this
.
listLoading
=
false
})
},
getList
()
{
this
.
listLoading
=
true
listGoods
(
this
.
listQuery
).
then
(
response
=>
{
this
.
list
=
response
.
data
.
data
.
list
this
.
total
=
response
.
data
.
data
.
total
this
.
listLoading
=
false
}).
catch
(()
=>
{
this
.
list
=
[]
this
.
total
=
0
this
.
listLoading
=
false
})
},
handleFilter
()
{
this
.
listQuery
.
page
=
1
this
.
getList
()
},
handleSelectionChange
(
val
)
{
this
.
selectedlist
=
val
},
uploadPicUrl
:
function
(
response
)
{
this
.
topic
.
picUrl
=
response
.
data
.
url
},
handleCreate
()
{
this
.
listQuery
=
{
page
:
1
,
limit
:
5
,
id
:
undefined
,
name
:
undefined
,
sort
:
'
add_time
'
,
order
:
'
desc
'
}
this
.
list
=
[]
this
.
total
=
0
this
.
selectedlist
=
[]
this
.
addVisiable
=
true
},
confirmAdd
()
{
const
newGoodsIds
=
[]
const
newGoodsList
=
[]
this
.
selectedlist
.
forEach
(
item
=>
{
const
id
=
item
.
id
let
found
=
false
this
.
topic
.
goods
.
forEach
(
goodsId
=>
{
if
(
id
===
goodsId
)
{
found
=
true
}
})
if
(
!
found
)
{
newGoodsIds
.
push
(
id
)
newGoodsList
.
push
(
item
)
}
})
if
(
newGoodsIds
.
length
>
0
)
{
this
.
topic
.
goods
=
this
.
topic
.
goods
.
concat
(
newGoodsIds
)
this
.
goodsList
=
this
.
goodsList
.
concat
(
newGoodsList
)
}
this
.
addVisiable
=
false
},
handleDelete
(
row
)
{
for
(
var
index
=
0
;
index
<
this
.
topic
.
goods
.
length
;
index
++
)
{
if
(
row
.
id
===
this
.
topic
.
goods
[
index
])
{
this
.
topic
.
goods
.
splice
(
index
,
1
)
}
}
for
(
var
index2
=
0
;
index2
<
this
.
goodsList
.
length
;
index2
++
)
{
if
(
row
.
id
===
this
.
goodsList
[
index2
].
id
)
{
this
.
goodsList
.
splice
(
index2
,
1
)
}
}
},
handleCancel
()
{
this
.
$router
.
push
({
path
:
'
/promotion/topic
'
})
},
handleConfirm
()
{
this
.
$refs
[
'
topic
'
].
validate
(
valid
=>
{
if
(
valid
)
{
updateTopic
(
this
.
topic
).
then
(
response
=>
{
this
.
$router
.
push
({
path
:
'
/promotion/topic
'
})
})
.
catch
(
response
=>
{
this
.
$notify
.
error
({
title
:
'
失败
'
,
message
:
response
.
data
.
errmsg
})
})
}
})
}
}
}
</
script
>
litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallGoodsService.java
View file @
6fc6cb6c
...
...
@@ -11,6 +11,7 @@ import org.springframework.util.StringUtils;
import
javax.annotation.Resource
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
@Service
...
...
@@ -247,4 +248,10 @@ public class LitemallGoodsService {
example
.
or
().
andNameEqualTo
(
name
).
andIsOnSaleEqualTo
(
true
).
andDeletedEqualTo
(
false
);
return
goodsMapper
.
countByExample
(
example
)
!=
0
;
}
public
List
<
LitemallGoods
>
queryByIds
(
Integer
[]
ids
)
{
LitemallGoodsExample
example
=
new
LitemallGoodsExample
();
example
.
or
().
andIdIn
(
Arrays
.
asList
(
ids
)).
andIsOnSaleEqualTo
(
true
).
andDeletedEqualTo
(
false
);
return
goodsMapper
.
selectByExampleSelective
(
example
,
columns
);
}
}
litemall-wx/pages/topicDetail/topicDetail.wxml
View file @
6fc6cb6c
...
...
@@ -7,7 +7,6 @@
<view class="topic-goods">
<view class="h">
<text class="t">专题商品</text>
<image bindtap="postComment" class="i" src="http://nos.netease.com/mailpub/hxm/yanxuan-wap/p/20150730/style/img/icon-normal/comment-add-2aca147c3f.png"></image>
</view>
<view class="b">
<view class="item" wx:for="{{topicGoods}}" wx:for-index="index" wx:for-item="item" wx:key="id">
...
...
litemall-wx/pages/topicDetail/topicDetail.wxss
View file @
6fc6cb6c
...
...
@@ -143,6 +143,22 @@
margin-top: 20rpx;
}
.topic-goods .h {
height: 93rpx;
line-height: 93rpx;
width: 720rpx;
padding-right: 30rpx;
border-bottom: 1px solid #d9d9d9;
}
.topic-goods .h .t {
display: block;
float: left;
width: 50%;
font-size: 29rpx;
color: #333;
}
.topic-goods .b .item {
border-top: 1px solid #d9d9d9;
margin: 0 20rpx;
...
...
Write
Preview
Supports
Markdown
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