记得上下班打卡 | git大法好,push需谨慎
Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
liquidnet-bus-v1
Project
Project
Details
Activity
Releases
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
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
董敬伟
liquidnet-bus-v1
Commits
7cbf19f4
Commit
7cbf19f4
authored
Mar 05, 2026
by
wangyifan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
演出管理关联艺人
parent
087c6eb9
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1306 additions
and
5 deletions
+1306
-5
zhengzai-V1.5-20260304.sql
docu/zhengzai-V1.5-20260304.sql
+2
-2
KylinArtistController.java
.../web/controller/zhengzai/kylin/KylinArtistController.java
+175
-2
KylinPerformancesController.java
...ontroller/zhengzai/kylin/KylinPerformancesController.java
+33
-0
artistLineup.html
...s/templates/zhengzai/kylin/performances/artistLineup.html
+986
-0
details.html
...ources/templates/zhengzai/kylin/performances/details.html
+14
-0
KylinArtistAssociationStatusDto.java
...et/service/kylin/dao/KylinArtistAssociationStatusDto.java
+31
-0
KylinArtistPerformanceDao.java
...iquidnet/service/kylin/dao/KylinArtistPerformanceDao.java
+25
-0
KylinArtistPerformanceMapper.java
...et/service/kylin/mapper/KylinArtistPerformanceMapper.java
+9
-0
KylinArtistPerformanceMapper.xml
...net.service.kylin.mapper/KylinArtistPerformanceMapper.xml
+31
-1
No files found.
docu/zhengzai-V1.5-20260304.sql
View file @
7cbf19f4
...
...
@@ -48,10 +48,10 @@ CREATE TABLE `kylin_artist_performance` (
`created_at`
datetime
DEFAULT
CURRENT_TIMESTAMP
COMMENT
'创建时间'
,
`updated_at`
datetime
DEFAULT
CURRENT_TIMESTAMP
ON
UPDATE
CURRENT_TIMESTAMP
COMMENT
'更新时间'
,
PRIMARY
KEY
(
`mid`
),
UNIQUE
KEY
`uk_artist_performance`
(
`artist_id`
,
`performances_id`
)
,
UNIQUE
KEY
`uk_artist_performance`
(
`artist_id`
,
`performances_id`
,
`times_id`
)
USING
BTREE
COMMENT
'艺人、演出、场次唯一索引'
,
KEY
`idx_performances_id`
(
`performances_id`
),
KEY
`idx_artist_id`
(
`artist_id`
)
)
ENGINE
=
InnoDB
AUTO_INCREMENT
=
4
DEFAULT
CHARSET
=
utf8mb4
COLLATE
=
utf8mb4_0900_ai_ci
COMMENT
=
'艺人-演出关联表'
;
)
ENGINE
=
InnoDB
AUTO_INCREMENT
=
83
DEFAULT
CHARSET
=
utf8mb4
COLLATE
=
utf8mb4_0900_ai_ci
COMMENT
=
'艺人-演出关联表'
;
-- 艺人操作记录表
...
...
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-web/src/main/java/com/liquidnet/client/admin/web/controller/zhengzai/kylin/KylinArtistController.java
View file @
7cbf19f4
package
com
.
liquidnet
.
client
.
admin
.
web
.
controller
.
zhengzai
.
kylin
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.github.pagehelper.PageInfo
;
import
com.liquidnet.client.admin.common.annotation.Log
;
import
com.liquidnet.client.admin.common.core.controller.BaseController
;
import
com.liquidnet.client.admin.common.core.domain.AjaxResult
;
import
com.liquidnet.client.admin.common.core.page.TableDataInfo
;
import
com.liquidnet.client.admin.common.enums.BusinessType
;
import
com.liquidnet.service.kylin.dao.KylinArtistAssociationStatusDto
;
import
com.liquidnet.service.kylin.dao.KylinArtistDao
;
import
com.liquidnet.service.kylin.dao.KylinArtistOperationLogDao
;
import
com.liquidnet.service.kylin.dao.KylinArtistPerformanceDao
;
import
com.liquidnet.service.kylin.dto.param.ArtistParam
;
import
com.liquidnet.service.kylin.dto.param.ArtistSearchParam
;
import
com.liquidnet.service.kylin.dto.vo.ArtistVo
;
import
com.liquidnet.service.kylin.entity.KylinArtistPerformance
;
import
com.liquidnet.service.kylin.mapper.KylinArtistPerformanceMapper
;
import
com.liquidnet.service.kylin.service.admin.IKylinArtistService
;
import
com.liquidnet.service.kylin.service.admin.IKylinArtistOperationLogService
;
import
io.swagger.annotations.Api
;
...
...
@@ -21,7 +26,10 @@ import org.springframework.stereotype.Controller;
import
org.springframework.ui.ModelMap
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
import
com.liquidnet.service.kylin.entity.KylinArtist
;
import
java.util.*
;
import
java.util.stream.Collectors
;
/**
* <p>
...
...
@@ -47,13 +55,15 @@ public class KylinArtistController extends BaseController {
@Autowired
private
IKylinArtistOperationLogService
operationLogService
;
@Autowired
private
KylinArtistPerformanceMapper
artistPerformanceMapper
;
@GetMapping
(
"/create"
)
@RequiresPermissions
(
"kylin:artist:create"
)
public
String
create
(
ModelMap
mmap
)
{
mmap
.
put
(
"platformUrl"
,
platformUrl
);
return
prefix
+
"/create"
;
}
@GetMapping
(
"/update/{artistId}"
)
@RequiresPermissions
(
"kylin:artist:update"
)
public
String
update
(
@PathVariable
(
"artistId"
)
String
artistId
,
ModelMap
mmap
)
{
...
...
@@ -200,4 +210,167 @@ public class KylinArtistController extends BaseController {
operationLogService
.
getOperationLogs
(
artistId
,
pageNum
,
pageSize
);
return
getDataTable
(
result
.
getList
());
}
/**
* 获取指定场次的艺人阵容
*/
@GetMapping
(
"/getSessionArtists"
)
@ResponseBody
public
AjaxResult
getSessionArtists
(
String
performancesId
,
String
timesId
)
{
try
{
if
(
performancesId
==
null
||
timesId
==
null
)
{
return
error
(
"参数不能为空"
);
}
// 查询该场次的艺人
List
<
KylinArtistPerformanceDao
>
artists
=
artistPerformanceMapper
.
selectArtistsByPerformanceAndTimes
(
performancesId
,
timesId
);
return
AjaxResult
.
success
(
artists
);
}
catch
(
Exception
e
)
{
return
error
(
"获取艺人阵容失败: "
+
e
.
getMessage
());
}
}
/**
* 更新艺人排序
*/
@Log
(
title
=
"更新演出艺人排序"
,
businessType
=
BusinessType
.
UPDATE
)
@PostMapping
(
"/updateArtistOrder"
)
@ResponseBody
public
AjaxResult
updateArtistOrder
(
@RequestBody
Map
<
String
,
Object
>
params
)
{
try
{
String
performancesId
=
(
String
)
params
.
get
(
"performancesId"
);
String
timesId
=
(
String
)
params
.
get
(
"timesId"
);
List
<
Map
<
String
,
Object
>>
orderData
=
(
List
<
Map
<
String
,
Object
>>)
params
.
get
(
"orderData"
);
if
(
orderData
==
null
||
orderData
.
isEmpty
())
{
return
error
(
"排序数据不能为空"
);
}
// 更新每个艺人的排序
for
(
Map
<
String
,
Object
>
item
:
orderData
)
{
Long
mid
=
Long
.
valueOf
(
item
.
get
(
"mid"
).
toString
());
Integer
sort
=
Integer
.
valueOf
(
item
.
get
(
"sort"
).
toString
());
KylinArtistPerformance
entity
=
artistPerformanceMapper
.
selectById
(
mid
);
if
(
entity
!=
null
)
{
entity
.
setSort
(
sort
);
artistPerformanceMapper
.
updateById
(
entity
);
}
}
return
success
(
"排序更新成功"
);
}
catch
(
Exception
e
)
{
return
error
(
"更新排序失败: "
+
e
.
getMessage
());
}
}
/**
* 删除演出艺人关联
*/
@Log
(
title
=
"删除演出艺人"
,
businessType
=
BusinessType
.
DELETE
)
@PostMapping
(
"/deletePerformanceArtist"
)
@ResponseBody
public
AjaxResult
deletePerformanceArtist
(
Long
mid
,
String
performancesId
,
String
timesId
)
{
try
{
if
(
mid
==
null
)
{
return
error
(
"参数错误"
);
}
int
result
=
artistPerformanceMapper
.
deleteById
(
mid
);
if
(
result
>
0
)
{
return
success
(
"删除成功"
);
}
else
{
return
error
(
"删除失败"
);
}
}
catch
(
Exception
e
)
{
return
error
(
"删除失败: "
+
e
.
getMessage
());
}
}
/**
* 获取所有艺人以供关联
*/
@GetMapping
(
"/getAllArtists"
)
@ResponseBody
public
AjaxResult
getAllArtists
(
String
performancesId
,
String
timesId
,
String
keyword
)
{
try
{
// 1. 获取所有艺人
List
<
KylinArtist
>
allArtists
=
kylinArtistService
.
list
(
new
QueryWrapper
<
KylinArtist
>()
.
like
(
keyword
!=
null
&&
!
keyword
.
isEmpty
(),
"artist_name"
,
keyword
)
.
orderByDesc
(
"created_at"
));
// 2. 获取当前场次已关联的艺人,用 Map 保留各自的 sort 值
List
<
KylinArtistPerformanceDao
>
associatedArtists
=
artistPerformanceMapper
.
selectArtistsByPerformanceAndTimes
(
performancesId
,
timesId
);
// key: artistId value: 演出关联表中的 sort(越大越靠前)
Map
<
String
,
Integer
>
associatedSortMap
=
associatedArtists
.
stream
()
.
collect
(
Collectors
.
toMap
(
KylinArtistPerformanceDao:
:
getArtistId
,
KylinArtistPerformanceDao:
:
getSort
,
(
existing
,
replacement
)
->
existing
// 重复 key 保留已有值
));
// 3. 组装返回结果
List
<
KylinArtistAssociationStatusDto
>
resultList
=
allArtists
.
stream
().
map
(
artist
->
{
KylinArtistAssociationStatusDto
dto
=
new
KylinArtistAssociationStatusDto
();
dto
.
setArtistId
(
artist
.
getArtistId
());
dto
.
setArtistName
(
artist
.
getArtistName
());
dto
.
setAvatarUrl
(
artist
.
getAvatarUrl
());
boolean
associated
=
associatedSortMap
.
containsKey
(
artist
.
getArtistId
());
dto
.
setAssociated
(
associated
);
// sort 取演出关联表的值;未关联的艺人 sort 置 0
dto
.
setSort
(
associated
?
associatedSortMap
.
get
(
artist
.
getArtistId
())
:
0
);
return
dto
;
}).
collect
(
Collectors
.
toList
());
return
AjaxResult
.
success
(
resultList
);
}
catch
(
Exception
e
)
{
return
error
(
"获取艺人列表失败: "
+
e
.
getMessage
());
}
}
/**
* 修改艺人关联
* @param payload
* @return
*/
@PostMapping
(
"/updateArtistAssociations"
)
@ResponseBody
public
AjaxResult
updateArtistAssociations
(
@RequestBody
Map
<
String
,
Object
>
payload
)
{
try
{
String
performancesId
=
(
String
)
payload
.
get
(
"performancesId"
);
String
timesId
=
(
String
)
payload
.
get
(
"timesId"
);
List
<
Map
<
String
,
Object
>>
artistOrders
=
(
List
<
Map
<
String
,
Object
>>)
payload
.
get
(
"artistOrders"
);
// 1. 删除当前场次所有已关联的艺人
artistPerformanceMapper
.
delete
(
new
QueryWrapper
<
KylinArtistPerformance
>()
.
eq
(
"performances_id"
,
performancesId
)
.
eq
(
"times_id"
,
timesId
));
// 2. 按前端传入的顺序重新关联,sort 越大越靠前
if
(
artistOrders
!=
null
&&
!
artistOrders
.
isEmpty
())
{
for
(
Map
<
String
,
Object
>
item
:
artistOrders
)
{
String
artistId
=
(
String
)
item
.
get
(
"artistId"
);
Integer
sort
=
item
.
get
(
"sort"
)
!=
null
?
Integer
.
valueOf
(
item
.
get
(
"sort"
).
toString
())
:
0
;
KylinArtistPerformance
newAssociation
=
new
KylinArtistPerformance
();
newAssociation
.
setPerformancesId
(
performancesId
);
newAssociation
.
setTimesId
(
timesId
);
newAssociation
.
setArtistId
(
artistId
);
newAssociation
.
setSort
(
sort
);
artistPerformanceMapper
.
insert
(
newAssociation
);
}
}
return
success
(
"关联更新成功"
);
}
catch
(
Exception
e
)
{
logger
.
error
(
"error"
,
e
);
return
error
(
"更新关联失败: "
+
e
.
getMessage
());
}
}
}
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-web/src/main/java/com/liquidnet/client/admin/web/controller/zhengzai/kylin/KylinPerformancesController.java
View file @
7cbf19f4
...
...
@@ -26,6 +26,7 @@ import com.liquidnet.service.kylin.dto.param.SysDamaiParam;
import
com.liquidnet.service.kylin.dto.vo.admin.*
;
import
com.liquidnet.service.kylin.dto.vo.partner.KylinPerformanceMisVo
;
import
com.liquidnet.service.kylin.dto.vo.partner.KylinPerformancesVo
;
import
com.liquidnet.service.kylin.dto.vo.partner.TicketTimesTicketCreatePartnerVo
;
import
com.liquidnet.service.kylin.entity.KylinOrderImport
;
import
com.liquidnet.service.kylin.service.admin.IKylinPerformancesAdminService
;
import
com.liquidnet.service.kylin.service.other.DamaiService
;
...
...
@@ -258,6 +259,38 @@ public class KylinPerformancesController extends BaseController {
return
prefix
+
"/subscribe"
;
}
/**
* 演出阵容页面
*/
@GetMapping
(
value
=
"/artistLineup/{performancesId}"
)
public
String
artistLineup
(
@PathVariable
(
"performancesId"
)
String
performancesId
,
ModelMap
mmap
)
{
try
{
// 获取演出信息
KylinPerformanceMisVo
performance
=
kylinPerformancesService
.
performanceDetails
(
performancesId
);
if
(
performance
==
null
)
{
mmap
.
put
(
"errorMsg"
,
"演出不存在"
);
return
prefix
+
"/artistLineup"
;
}
// 将场次数据转换为JSON
List
<
TicketTimesTicketCreatePartnerVo
>
ticketTimes
=
performance
.
getTicketTimes
();
String
ticketTimesJson
=
"[]"
;
if
(
ticketTimes
!=
null
&&
!
ticketTimes
.
isEmpty
())
{
com
.
fasterxml
.
jackson
.
databind
.
ObjectMapper
mapper
=
new
com
.
fasterxml
.
jackson
.
databind
.
ObjectMapper
();
ticketTimesJson
=
mapper
.
writeValueAsString
(
ticketTimes
);
}
mmap
.
put
(
"performancesId"
,
performancesId
);
mmap
.
put
(
"performanceTitle"
,
performance
.
getTitle
());
mmap
.
put
(
"ticketTimesJson"
,
ticketTimesJson
);
return
prefix
+
"/artistLineup"
;
}
catch
(
Exception
e
)
{
mmap
.
put
(
"errorMsg"
,
"加载演出阵容失败: "
+
e
.
getMessage
());
return
prefix
+
"/artistLineup"
;
}
}
@Log
(
title
=
"预约统计:导出列表"
)
@PostMapping
(
"/subscribe/export"
)
@ResponseBody
...
...
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-web/src/main/resources/templates/zhengzai/kylin/performances/artistLineup.html
0 → 100644
View file @
7cbf19f4
<!DOCTYPE html>
<html
lang=
"zh"
xmlns:th=
"http://www.thymeleaf.org"
>
<head>
<th:block
th:include=
"include :: header('演出阵容')"
/>
<style>
/* ===== 演出阵容主体样式 ===== */
.lineup-session
{
margin-bottom
:
30px
;
border
:
1px
solid
#e7eaec
;
padding
:
20px
;
background
:
#fff
;
border-radius
:
4px
;
}
.lineup-session-title
{
font-size
:
16px
;
font-weight
:
bold
;
margin-bottom
:
15px
;
color
:
#676a6c
;
padding-bottom
:
10px
;
border-bottom
:
2px
solid
#1ab394
;
}
.artist-list
{
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
20px
;
}
.artist-item
{
position
:
relative
;
text-align
:
center
;
cursor
:
default
;
width
:
100px
;
transition
:
all
0.3s
;
}
.edit-mode
.artist-item
{
cursor
:
move
;
}
.artist-item
:hover
{
transform
:
translateY
(
-5px
);
}
.artist-item.dragging
{
opacity
:
0.5
;
}
.artist-avatar
{
width
:
80px
;
height
:
80px
;
border-radius
:
50%
;
object-fit
:
cover
;
border
:
2px
solid
#e7eaec
;
transition
:
border-color
0.3s
;
}
.artist-item
:hover
.artist-avatar
{
border-color
:
#1ab394
;
}
.artist-name
{
margin-top
:
8px
;
font-size
:
14px
;
color
:
#676a6c
;
word-break
:
break-all
;
}
.delete-icon
{
display
:
none
;
position
:
absolute
;
top
:
-5px
;
right
:
10px
;
width
:
20px
;
height
:
20px
;
background
:
#ed5565
;
color
:
white
;
border-radius
:
50%
;
cursor
:
pointer
;
align-items
:
center
;
justify-content
:
center
;
font-size
:
14px
;
line-height
:
1
;
transition
:
background-color
0.3s
;
}
.edit-mode
.delete-icon
{
display
:
flex
;
}
.delete-icon
:hover
{
background
:
#da4453
;
}
.no-artists-tip
{
text-align
:
center
;
padding
:
40px
;
color
:
#999
;
}
/* 编辑模式下的拖拽提示(标题旁小字) */
.drag-hint
{
display
:
none
;
margin-left
:
10px
;
color
:
#aaa
;
font-size
:
11px
;
font-weight
:
normal
;
}
.edit-mode
.drag-hint
{
display
:
inline
;
}
/* ===== 关联艺人弹窗样式 ===== */
/* 搜索框容器:内嵌 × 按钮 */
.artist-search-wrap
{
position
:
relative
;
margin-bottom
:
12px
;
}
.artist-search-wrap
.form-control
{
padding-right
:
34px
;
border-radius
:
4px
;
}
.artist-search-clear
{
position
:
absolute
;
right
:
10px
;
top
:
50%
;
transform
:
translateY
(
-50%
);
cursor
:
pointer
;
color
:
#aaa
;
font-size
:
16px
;
line-height
:
1
;
display
:
none
;
background
:
none
;
border
:
none
;
padding
:
0
;
}
.artist-search-clear
:hover
{
color
:
#555
;
}
/* 搜索结果列表 */
.modal-artist-list
{
max-height
:
300px
;
overflow-y
:
auto
;
border
:
1px
solid
#eee
;
border-radius
:
4px
;
}
.modal-artist-item
{
display
:
flex
;
align-items
:
center
;
padding
:
10px
14px
;
cursor
:
pointer
;
border-bottom
:
1px
solid
#f0f0f0
;
transition
:
background
0.15s
;
}
.modal-artist-item
:last-child
{
border-bottom
:
none
;
}
.modal-artist-item
:hover
{
background
:
#f7f9fc
;
}
.modal-artist-avatar
{
width
:
44px
;
height
:
44px
;
border-radius
:
50%
;
object-fit
:
cover
;
margin-right
:
12px
;
flex-shrink
:
0
;
border
:
2px
solid
#e0e0e0
;
}
.modal-artist-name
{
flex
:
1
;
font-size
:
14px
;
color
:
#333
;
}
/* 单选按钮样式 */
.artist-radio-btn
{
width
:
22px
;
height
:
22px
;
border-radius
:
50%
;
border
:
2px
solid
#ccc
;
flex-shrink
:
0
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
transition
:
border-color
0.2s
,
background
0.2s
;
}
.artist-radio-btn.selected
{
border-color
:
#1ab394
;
background
:
#1ab394
;
}
.artist-radio-btn.selected
::after
{
content
:
''
;
display
:
block
;
width
:
8px
;
height
:
5px
;
border-left
:
2px
solid
#fff
;
border-bottom
:
2px
solid
#fff
;
transform
:
rotate
(
-45deg
)
translateY
(
-1px
);
}
/* 加载动画 */
.modal-loading
{
text-align
:
center
;
padding
:
30px
;
color
:
#999
;
}
/* 空状态 */
.modal-empty
{
text-align
:
center
;
padding
:
30px
;
color
:
#aaa
;
font-size
:
13px
;
}
/* 已选艺人区域 */
.selected-artists-section
{
margin-top
:
14px
;
}
.selected-artists-section
h5
{
font-size
:
14px
;
font-weight
:
600
;
color
:
#555
;
margin-bottom
:
10px
;
}
.selected-artists-container
{
display
:
flex
;
flex-wrap
:
nowrap
;
/* 不换行,支持横向滚动 */
overflow-x
:
auto
;
gap
:
12px
;
padding
:
10px
;
min-height
:
90px
;
border
:
1px
solid
#eee
;
border-radius
:
4px
;
background
:
#fafafa
;
align-items
:
flex-start
;
}
.selected-artists-container
::-webkit-scrollbar
{
height
:
4px
;
}
.selected-artists-container
::-webkit-scrollbar-thumb
{
background
:
#ccc
;
border-radius
:
2px
;
}
.selected-artist-card
{
position
:
relative
;
text-align
:
center
;
flex-shrink
:
0
;
width
:
72px
;
cursor
:
grab
;
transition
:
opacity
0.2s
,
transform
0.15s
;
}
.selected-artist-card
:active
{
cursor
:
grabbing
;
}
.selected-artist-card.dragging
{
opacity
:
0.4
;
transform
:
scale
(
0.95
);
}
.selected-artist-card.drag-over
{
outline
:
2px
dashed
#1ab394
;
outline-offset
:
2px
;
border-radius
:
6px
;
}
.selected-artist-avatar
{
width
:
56px
;
height
:
56px
;
border-radius
:
50%
;
object-fit
:
cover
;
border
:
2px
solid
#1ab394
;
}
.selected-artist-name
{
margin-top
:
5px
;
font-size
:
11px
;
color
:
#555
;
word-break
:
break-all
;
line-height
:
1.3
;
}
.remove-selected-artist
{
position
:
absolute
;
top
:
-4px
;
right
:
4px
;
width
:
18px
;
height
:
18px
;
background
:
#ed5565
;
color
:
white
;
border-radius
:
50%
;
cursor
:
pointer
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
font-size
:
12px
;
line-height
:
1
;
transition
:
background-color
0.2s
;
}
.remove-selected-artist
:hover
{
background
:
#da4453
;
}
.selected-empty-tip
{
width
:
100%
;
text-align
:
center
;
color
:
#bbb
;
font-size
:
13px
;
padding
:
20px
0
;
align-self
:
center
;
}
/* 弹窗底部按钮 */
.modal-footer
.btn-cancel
{
border
:
1px
solid
#ccc
;
color
:
#555
;
background
:
#fff
;
}
.modal-footer
.btn-cancel
:hover
{
background
:
#f5f5f5
;
}
</style>
</head>
<body
class=
"gray-bg"
>
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<div
class=
"row"
>
<div
class=
"col-sm-12"
>
<div
class=
"ibox"
>
<div
class=
"ibox-title"
>
<h5>
演出阵容管理
</h5>
<div
class=
"ibox-tools"
>
<span
th:text=
"${performanceTitle}"
style=
"font-size:15px;font-weight:600;color:#333;vertical-align:middle;"
></span>
</div>
</div>
<div
class=
"ibox-content"
>
<div
style=
"margin-bottom:15px;"
>
<button
class=
"btn btn-primary btn-sm"
id=
"edit-lineup-btn"
>
编辑演出阵容
</button>
</div>
<div
id=
"artist-lineup-container"
>
<div
class=
"text-center"
>
<i
class=
"fa fa-spinner fa-spin fa-3x"
></i>
<p>
加载中...
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 关联艺人弹窗 -->
<div
class=
"modal fade"
id=
"associateArtistModal"
tabindex=
"-1"
role=
"dialog"
>
<div
class=
"modal-dialog"
role=
"document"
>
<div
class=
"modal-content"
>
<div
class=
"modal-header"
>
<button
type=
"button"
class=
"close"
data-dismiss=
"modal"
aria-label=
"Close"
>
<span
aria-hidden=
"true"
>
×
</span>
</button>
<h4
class=
"modal-title"
>
关联艺人
</h4>
</div>
<div
class=
"modal-body"
>
<!-- 搜索框 -->
<div
class=
"artist-search-wrap"
>
<input
type=
"text"
class=
"form-control"
id=
"artist-search-input"
placeholder=
"搜索艺人姓名"
autocomplete=
"off"
>
<button
class=
"artist-search-clear"
id=
"clear-search-btn"
title=
"清空"
>
×
</button>
</div>
<!-- 搜索结果列表 -->
<div
class=
"modal-artist-list"
id=
"modal-artist-list"
>
<!-- 动态渲染 -->
</div>
<!-- 已选艺人区 -->
<div
class=
"selected-artists-section"
>
<h5>
已选艺人
<small
style=
"font-weight:normal;color:#aaa;font-size:11px;"
>
(可拖拽调整顺序)
</small></h5>
<div
class=
"selected-artists-container"
id=
"selected-artists-container"
>
<!-- 动态渲染 -->
</div>
</div>
</div>
<div
class=
"modal-footer"
>
<button
type=
"button"
class=
"btn btn-cancel"
id=
"cancel-associate-btn"
>
取消
</button>
<button
type=
"button"
class=
"btn btn-primary"
onclick=
"saveAssociatedArtists()"
>
保存
</button>
</div>
</div>
</div>
</div>
<th:block
th:include=
"include :: footer"
/>
<script
th:inline=
"javascript"
>
const
performancesId
=
[[
$
{
performancesId
}]];
let
ticketTimes
=
[];
try
{
const
rawTicketTimes
=
/*[[${ticketTimesJson}]]*/
'[]'
;
ticketTimes
=
JSON
.
parse
(
rawTicketTimes
);
}
catch
(
e
)
{
console
.
error
(
'Invalid ticketTimesJson:'
,
e
);
ticketTimes
=
[];
}
$
(
function
()
{
loadArtistLineup
();
// 编辑模式切换
$
(
'#edit-lineup-btn'
).
on
(
'click'
,
function
()
{
const
container
=
$
(
'#artist-lineup-container'
);
const
isEditMode
=
container
.
hasClass
(
'edit-mode'
);
if
(
isEditMode
)
{
container
.
removeClass
(
'edit-mode'
);
$
(
this
).
text
(
'编辑演出阵容'
);
$
(
'.associate-artist-btn'
).
hide
();
destroyDragAndDrop
();
}
else
{
container
.
addClass
(
'edit-mode'
);
$
(
this
).
text
(
'完成编辑'
);
$
(
'.associate-artist-btn'
).
show
();
initDragAndDrop
();
}
});
// 搜索框输入事件(防抖)
$
(
document
).
on
(
'input'
,
'#artist-search-input'
,
function
()
{
$
(
'#clear-search-btn'
).
toggle
(
$
(
this
).
val
().
length
>
0
);
debouncedSearch
();
});
// 清空搜索框
$
(
document
).
on
(
'click'
,
'#clear-search-btn'
,
function
()
{
$
(
'#artist-search-input'
).
val
(
''
).
trigger
(
'input'
);
});
// 取消按钮:关闭弹窗,不保存
$
(
document
).
on
(
'click'
,
'#cancel-associate-btn'
,
function
()
{
$
(
'#associateArtistModal'
).
modal
(
'hide'
);
});
});
// ===== 演出阵容加载与渲染 =====
function
loadArtistLineup
()
{
const
times
=
Array
.
isArray
(
ticketTimes
)
?
ticketTimes
:
[];
if
(
!
times
||
times
.
length
===
0
)
{
$
(
'#artist-lineup-container'
).
html
(
'<div class="alert alert-info">该演出暂无场次信息</div>'
);
return
;
}
let
loadedCount
=
0
;
const
allSessionData
=
[];
times
.
forEach
(
function
(
ticketTime
,
index
)
{
$
.
ajax
({
url
:
ctx
+
"kylin/artist/getSessionArtists"
,
type
:
"GET"
,
data
:
{
performancesId
:
performancesId
,
timesId
:
ticketTime
.
ticketTimesId
},
success
:
function
(
response
)
{
if
(
response
.
code
===
0
)
{
allSessionData
[
index
]
=
{
timesId
:
ticketTime
.
ticketTimesId
,
sessionDate
:
ticketTime
.
title
.
replace
(
/ 00:00/g
,
''
),
artists
:
response
.
data
||
[]
};
}
loadedCount
++
;
if
(
loadedCount
===
times
.
length
)
{
renderArtistLineup
(
allSessionData
);
}
},
error
:
function
()
{
loadedCount
++
;
allSessionData
[
index
]
=
{
timesId
:
ticketTime
.
ticketTimesId
,
sessionDate
:
ticketTime
.
title
.
replace
(
/ 00:00/g
,
''
),
artists
:
[]
};
if
(
loadedCount
===
times
.
length
)
{
renderArtistLineup
(
allSessionData
);
}
}
});
});
}
function
renderArtistLineup
(
data
)
{
const
container
=
$
(
'#artist-lineup-container'
);
if
(
!
data
||
data
.
length
===
0
)
{
container
.
html
(
'<div class="alert alert-info">暂无演出阵容数据</div>'
);
return
;
}
let
html
=
''
;
data
.
forEach
(
function
(
session
)
{
html
+=
'<div class="lineup-session">'
;
html
+=
'<div class="lineup-session-title">'
+
session
.
sessionDate
;
html
+=
'<span class="drag-hint">注:可拖拽调整出场顺序,松开后实时更新</span>'
;
html
+=
'<button class="btn btn-xs btn-primary associate-artist-btn" style="display:none; float: right;" onclick="openAssociateArtistModal(
\'
'
+
session
.
timesId
+
'
\'
)">关联艺人</button>'
;
html
+=
'</div>'
;
html
+=
'<div class="artist-list" data-times-id="'
+
session
.
timesId
+
'">'
;
if
(
session
.
artists
&&
session
.
artists
.
length
>
0
)
{
session
.
artists
.
forEach
(
function
(
artist
)
{
html
+=
'<div class="artist-item" draggable="true" data-artist-id="'
+
artist
.
artistId
+
'" data-mid="'
+
artist
.
mid
+
'">'
;
html
+=
'<div class="delete-icon" onclick="deleteArtist(
\'
'
+
artist
.
mid
+
'
\'
,
\'
'
+
session
.
timesId
+
'
\'
)">×</div>'
;
html
+=
'<img class="artist-avatar" src="'
+
artist
.
avatarUrl
+
'" alt="'
+
artist
.
artistName
+
'" onerror="this.src=
\'
/img/profile.jpg
\'
">'
;
html
+=
'<div class="artist-name">'
+
artist
.
artistName
+
'</div>'
;
html
+=
'</div>'
;
});
}
else
{
html
+=
'<div class="no-artists-tip">该场次暂无艺人</div>'
;
}
html
+=
'</div>'
;
html
+=
'</div>'
;
});
container
.
html
(
html
);
// 渲染完成后,若当前仍处于编辑模式,恢复按钮显示和拖拽绑定
if
(
container
.
hasClass
(
'edit-mode'
))
{
$
(
'.associate-artist-btn'
).
show
();
initDragAndDrop
();
}
}
// ===== 拖拽排序 =====
function
initDragAndDrop
()
{
if
(
!
$
(
'#artist-lineup-container'
).
hasClass
(
'edit-mode'
))
return
;
const
artistItems
=
document
.
querySelectorAll
(
'.artist-item'
);
artistItems
.
forEach
(
item
=>
{
item
.
setAttribute
(
'draggable'
,
'true'
);
item
.
addEventListener
(
'dragstart'
,
handleDragStart
);
item
.
addEventListener
(
'dragend'
,
handleDragEnd
);
item
.
addEventListener
(
'dragover'
,
handleDragOver
);
item
.
addEventListener
(
'drop'
,
handleDrop
);
});
}
function
destroyDragAndDrop
()
{
const
artistItems
=
document
.
querySelectorAll
(
'.artist-item'
);
artistItems
.
forEach
(
item
=>
{
item
.
setAttribute
(
'draggable'
,
'false'
);
item
.
removeEventListener
(
'dragstart'
,
handleDragStart
);
item
.
removeEventListener
(
'dragend'
,
handleDragEnd
);
item
.
removeEventListener
(
'dragover'
,
handleDragOver
);
item
.
removeEventListener
(
'drop'
,
handleDrop
);
});
}
let
draggedElement
=
null
;
function
handleDragStart
(
e
)
{
draggedElement
=
this
;
this
.
classList
.
add
(
'dragging'
);
e
.
dataTransfer
.
effectAllowed
=
'move'
;
}
function
handleDragEnd
(
e
)
{
this
.
classList
.
remove
(
'dragging'
);
draggedElement
=
null
;
}
function
handleDragOver
(
e
)
{
e
.
preventDefault
();
e
.
dataTransfer
.
dropEffect
=
'move'
;
if
(
draggedElement
&&
draggedElement
!==
this
)
{
const
parent
=
this
.
parentNode
;
const
draggedParent
=
draggedElement
.
parentNode
;
if
(
parent
===
draggedParent
)
{
const
allItems
=
Array
.
from
(
parent
.
querySelectorAll
(
'.artist-item'
));
const
draggedIndex
=
allItems
.
indexOf
(
draggedElement
);
const
targetIndex
=
allItems
.
indexOf
(
this
);
if
(
draggedIndex
<
targetIndex
)
{
parent
.
insertBefore
(
draggedElement
,
this
.
nextSibling
);
}
else
{
parent
.
insertBefore
(
draggedElement
,
this
);
}
}
}
}
function
handleDrop
(
e
)
{
e
.
preventDefault
();
e
.
stopPropagation
();
saveArtistOrder
(
this
.
parentNode
);
}
function
saveArtistOrder
(
artistListElement
)
{
const
timesId
=
artistListElement
.
getAttribute
(
'data-times-id'
);
const
artistItems
=
artistListElement
.
querySelectorAll
(
'.artist-item'
);
const
orderData
=
[];
artistItems
.
forEach
(
function
(
item
,
index
)
{
orderData
.
push
({
mid
:
item
.
getAttribute
(
'data-mid'
),
sort
:
artistItems
.
length
-
index
});
});
$
.
ajax
({
url
:
ctx
+
"kylin/artist/updateArtistOrder"
,
type
:
"POST"
,
contentType
:
"application/json"
,
data
:
JSON
.
stringify
({
performancesId
:
performancesId
,
timesId
:
timesId
,
orderData
:
orderData
}),
success
:
function
(
response
)
{
if
(
response
.
code
===
0
)
{
$
.
modal
.
msgSuccess
(
"排序已更新"
);
}
else
{
$
.
modal
.
msgError
(
response
.
msg
||
"更新排序失败"
);
loadArtistLineup
();
}
},
error
:
function
()
{
$
.
modal
.
msgError
(
"更新排序失败"
);
loadArtistLineup
();
}
});
}
// ===== 删除艺人 =====
function
deleteArtist
(
mid
,
timesId
)
{
$
.
modal
.
confirm
(
"确定要删除该艺人吗?"
,
function
()
{
$
.
ajax
({
url
:
ctx
+
"kylin/artist/deletePerformanceArtist"
,
type
:
"POST"
,
data
:
{
mid
:
mid
,
performancesId
:
performancesId
,
timesId
:
timesId
},
success
:
function
(
response
)
{
if
(
response
.
code
===
0
)
{
$
.
modal
.
msgSuccess
(
"删除成功"
);
loadArtistLineup
();
}
else
{
$
.
modal
.
msgError
(
response
.
msg
||
"删除失败"
);
}
},
error
:
function
()
{
$
.
modal
.
msgError
(
"删除失败"
);
}
});
});
}
// ===== 关联艺人弹窗逻辑 =====
let
selectedArtists
=
[];
// 当前已选艺人列表
let
currentModalArtists
=
[];
// 当前搜索结果中的艺人列表
function
openAssociateArtistModal
(
timesId
)
{
$
(
'#associateArtistModal'
).
data
(
'timesId'
,
timesId
);
// 重置状态
selectedArtists
=
[];
currentModalArtists
=
[];
$
(
'#artist-search-input'
).
val
(
''
);
$
(
'#clear-search-btn'
).
hide
();
$
(
'#modal-artist-list'
).
html
(
''
);
$
(
'#selected-artists-container'
).
html
(
''
);
// 打开弹窗
$
(
'#associateArtistModal'
).
modal
(
'show'
);
// 加载初始艺人列表(含已关联状态)
loadAllArtistsForModal
(
timesId
,
true
);
}
// 防抖
function
debounce
(
func
,
wait
)
{
let
timeout
;
return
function
(...
args
)
{
const
context
=
this
;
clearTimeout
(
timeout
);
timeout
=
setTimeout
(()
=>
func
.
apply
(
context
,
args
),
wait
);
};
}
const
debouncedSearch
=
debounce
(
function
()
{
const
timesId
=
$
(
'#associateArtistModal'
).
data
(
'timesId'
);
loadAllArtistsForModal
(
timesId
,
false
);
},
300
);
/**
* 从后端加载艺人列表
* @param {string} timesId
* @param {boolean} isInitialLoad 是否首次加载(用于初始化已选艺人)
*/
function
loadAllArtistsForModal
(
timesId
,
isInitialLoad
)
{
const
keyword
=
$
(
'#artist-search-input'
).
val
().
trim
();
// 显示加载中
$
(
'#modal-artist-list'
).
html
(
'<div class="modal-loading"><i class="fa fa-spinner fa-spin"></i> 搜索中...</div>'
);
$
.
ajax
({
url
:
ctx
+
"kylin/artist/getAllArtists"
,
type
:
"GET"
,
data
:
{
performancesId
:
performancesId
,
timesId
:
timesId
,
keyword
:
keyword
},
success
:
function
(
response
)
{
if
(
response
.
code
===
0
)
{
currentModalArtists
=
response
.
data
||
[];
renderArtistsInModal
(
currentModalArtists
,
isInitialLoad
);
}
else
{
$
(
'#modal-artist-list'
).
html
(
'<div class="modal-empty">加载艺人列表失败,请重试</div>'
);
}
},
error
:
function
()
{
$
(
'#modal-artist-list'
).
html
(
'<div class="modal-empty">加载艺人列表失败,请重试</div>'
);
}
});
}
/**
* 渲染搜索结果列表
* @param {Array} artists
* @param {boolean} isInitialLoad
*/
function
renderArtistsInModal
(
artists
,
isInitialLoad
)
{
const
listContainer
=
$
(
'#modal-artist-list'
);
if
(
!
artists
||
artists
.
length
===
0
)
{
listContainer
.
html
(
'<div class="modal-empty">暂无匹配艺人</div>'
);
updateSelectedArtistsView
();
return
;
}
// 首次加载时,从后端的 associated 字段初始化已选列表,并按 sort 降序排列(sort 越大越靠前)
if
(
isInitialLoad
)
{
selectedArtists
=
artists
.
filter
(
a
=>
a
.
associated
)
.
map
(
a
=>
({
artistId
:
a
.
artistId
,
artistName
:
a
.
artistName
,
avatarUrl
:
a
.
avatarUrl
,
sort
:
a
.
sort
||
0
}))
.
sort
((
a
,
b
)
=>
b
.
sort
-
a
.
sort
);
}
let
html
=
''
;
artists
.
forEach
(
function
(
artist
)
{
const
isSelected
=
selectedArtists
.
some
(
a
=>
a
.
artistId
===
artist
.
artistId
);
html
+=
'<div class="modal-artist-item" data-artist-id="'
+
artist
.
artistId
+
'">'
;
html
+=
'<img src="'
+
(
artist
.
avatarUrl
||
'/img/profile.jpg'
)
+
'" class="modal-artist-avatar" onerror="this.src=
\'
/img/profile.jpg
\'
">'
;
html
+=
'<div class="modal-artist-name">'
+
escapeHtml
(
artist
.
artistName
)
+
'</div>'
;
html
+=
'<div class="artist-radio-btn'
+
(
isSelected
?
' selected'
:
''
)
+
'"></div>'
;
html
+=
'</div>'
;
});
listContainer
.
html
(
html
);
updateSelectedArtistsView
();
// 点击整行切换选中状态
listContainer
.
find
(
'.modal-artist-item'
).
on
(
'click'
,
function
()
{
const
artistId
=
$
(
this
).
data
(
'artist-id'
);
const
artist
=
currentModalArtists
.
find
(
a
=>
a
.
artistId
===
artistId
);
if
(
!
artist
)
return
;
const
radioBtn
=
$
(
this
).
find
(
'.artist-radio-btn'
);
const
isSelected
=
selectedArtists
.
some
(
a
=>
a
.
artistId
===
artistId
);
if
(
isSelected
)
{
// 取消选中
selectedArtists
=
selectedArtists
.
filter
(
a
=>
a
.
artistId
!==
artistId
);
radioBtn
.
removeClass
(
'selected'
);
}
else
{
// 选中,防止重复
if
(
!
selectedArtists
.
some
(
a
=>
a
.
artistId
===
artistId
))
{
selectedArtists
.
push
({
artistId
:
artist
.
artistId
,
artistName
:
artist
.
artistName
,
avatarUrl
:
artist
.
avatarUrl
});
}
radioBtn
.
addClass
(
'selected'
);
}
updateSelectedArtistsView
();
});
}
/**
* 更新"已选艺人"区域视图,并初始化拖拽排序
*/
function
updateSelectedArtistsView
()
{
const
container
=
$
(
'#selected-artists-container'
);
if
(
selectedArtists
.
length
===
0
)
{
container
.
html
(
'<div class="selected-empty-tip">尚未选择艺人</div>'
);
return
;
}
let
html
=
''
;
selectedArtists
.
forEach
(
function
(
artist
)
{
html
+=
'<div class="selected-artist-card" draggable="true" data-artist-id="'
+
artist
.
artistId
+
'">'
;
html
+=
'<img src="'
+
(
artist
.
avatarUrl
||
'/img/profile.jpg'
)
+
'" class="selected-artist-avatar" onerror="this.src=
\'
/img/profile.jpg
\'
">'
;
html
+=
'<div class="selected-artist-name">'
+
escapeHtml
(
artist
.
artistName
)
+
'</div>'
;
html
+=
'<div class="remove-selected-artist" title="移除">×</div>'
;
html
+=
'</div>'
;
});
container
.
html
(
html
);
// 初始化已选区域拖拽排序
initSelectedArtistsDrag
();
}
// 点击"已选艺人"区域的 × 移除艺人
$
(
document
).
on
(
'click'
,
'.remove-selected-artist'
,
function
()
{
const
artistId
=
$
(
this
).
closest
(
'.selected-artist-card'
).
data
(
'artist-id'
);
selectedArtists
=
selectedArtists
.
filter
(
a
=>
a
.
artistId
!==
artistId
);
updateSelectedArtistsView
();
// 同步取消搜索列表中对应的选中状态
const
item
=
$
(
'#modal-artist-list .modal-artist-item[data-artist-id="'
+
artistId
+
'"]'
);
item
.
find
(
'.artist-radio-btn'
).
removeClass
(
'selected'
);
});
/**
* 初始化已选艺人卡片的拖拽排序
*/
let
modalDraggedCard
=
null
;
function
initSelectedArtistsDrag
()
{
const
cards
=
document
.
querySelectorAll
(
'#selected-artists-container .selected-artist-card'
);
cards
.
forEach
(
card
=>
{
card
.
addEventListener
(
'dragstart'
,
onModalDragStart
);
card
.
addEventListener
(
'dragend'
,
onModalDragEnd
);
card
.
addEventListener
(
'dragover'
,
onModalDragOver
);
card
.
addEventListener
(
'dragleave'
,
onModalDragLeave
);
card
.
addEventListener
(
'drop'
,
onModalDrop
);
});
}
function
onModalDragStart
(
e
)
{
// 若点击的是 × 按钮则不触发拖拽
if
(
e
.
target
.
classList
.
contains
(
'remove-selected-artist'
))
{
e
.
preventDefault
();
return
;
}
modalDraggedCard
=
this
;
this
.
classList
.
add
(
'dragging'
);
e
.
dataTransfer
.
effectAllowed
=
'move'
;
}
function
onModalDragEnd
()
{
if
(
modalDraggedCard
)
{
modalDraggedCard
.
classList
.
remove
(
'dragging'
);
}
document
.
querySelectorAll
(
'#selected-artists-container .selected-artist-card'
)
.
forEach
(
c
=>
c
.
classList
.
remove
(
'drag-over'
));
modalDraggedCard
=
null
;
}
function
onModalDragOver
(
e
)
{
e
.
preventDefault
();
e
.
dataTransfer
.
dropEffect
=
'move'
;
if
(
modalDraggedCard
&&
modalDraggedCard
!==
this
)
{
this
.
classList
.
add
(
'drag-over'
);
}
}
function
onModalDragLeave
()
{
this
.
classList
.
remove
(
'drag-over'
);
}
function
onModalDrop
(
e
)
{
e
.
preventDefault
();
e
.
stopPropagation
();
this
.
classList
.
remove
(
'drag-over'
);
if
(
!
modalDraggedCard
||
modalDraggedCard
===
this
)
return
;
const
container
=
document
.
getElementById
(
'selected-artists-container'
);
const
cards
=
Array
.
from
(
container
.
querySelectorAll
(
'.selected-artist-card'
));
const
fromIndex
=
cards
.
indexOf
(
modalDraggedCard
);
const
toIndex
=
cards
.
indexOf
(
this
);
if
(
fromIndex
===
-
1
||
toIndex
===
-
1
)
return
;
// 更新 selectedArtists 数组顺序
const
moved
=
selectedArtists
.
splice
(
fromIndex
,
1
)[
0
];
selectedArtists
.
splice
(
toIndex
,
0
,
moved
);
// 重新渲染(保持拖拽事件绑定)
updateSelectedArtistsView
();
}
/**
* 保存关联艺人
*/
function
saveAssociatedArtists
()
{
const
timesId
=
$
(
'#associateArtistModal'
).
data
(
'timesId'
);
if
(
selectedArtists
.
length
===
0
)
{
$
.
modal
.
msgWarning
(
"请至少选择一位艺人"
);
return
;
}
// 根据当前显示顺序计算 sort:越靠前的 sort 值越大
const
total
=
selectedArtists
.
length
;
const
artistOrders
=
selectedArtists
.
map
((
a
,
index
)
=>
({
artistId
:
a
.
artistId
,
sort
:
total
-
index
// 第 0 位 → sort 最大
}));
$
.
ajax
({
url
:
ctx
+
"kylin/artist/updateArtistAssociations"
,
type
:
"POST"
,
contentType
:
"application/json"
,
data
:
JSON
.
stringify
({
performancesId
:
performancesId
,
timesId
:
timesId
,
artistOrders
:
artistOrders
}),
success
:
function
(
response
)
{
if
(
response
.
code
===
0
)
{
$
.
modal
.
msgSuccess
(
"关联成功"
);
$
(
'#associateArtistModal'
).
modal
(
'hide'
);
loadArtistLineup
();
}
else
{
$
.
modal
.
msgError
(
response
.
msg
||
"关联失败"
);
}
},
error
:
function
()
{
$
.
modal
.
msgError
(
"关联失败"
);
}
});
}
/**
* HTML 转义,防止 XSS
*/
function
escapeHtml
(
str
)
{
if
(
!
str
)
return
''
;
return
str
.
replace
(
/&/g
,
'&'
)
.
replace
(
/</g
,
'<'
)
.
replace
(
/>/g
,
'>'
)
.
replace
(
/"/g
,
'"'
)
.
replace
(
/'/g
,
'''
);
}
</script>
</body>
</html>
\ No newline at end of file
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-web/src/main/resources/templates/zhengzai/kylin/performances/details.html
View file @
7cbf19f4
...
...
@@ -43,6 +43,8 @@
</li>
<li
id=
"li-tab-11"
><a
data-toggle=
"tab"
href=
"#tab-11"
aria-expanded=
"false"
onclick=
"subscribeInfo()"
>
预约统计
</a>
</li>
<li
id=
"li-tab-12"
><a
data-toggle=
"tab"
href=
"#tab-12"
aria-expanded=
"false"
onclick=
"artistLineupInfo()"
>
演出阵容
</a>
</li>
</ul>
<div
class=
"tab-content"
>
<div
id=
"tab-1"
class=
"tab-pane"
>
...
...
@@ -364,6 +366,13 @@
height=
800px
frameborder=
0
></iframe>
</div>
</div>
<div
id=
"tab-12"
class=
"tab-pane"
>
<div
class=
"panel-body"
>
<iframe
id=
"artist_lineup_iframe"
name=
"artist_lineup_iframe"
marginwidth=
0
marginheight=
0
width=
100%
height=
800px
frameborder=
0
></iframe>
</div>
</div>
</div>
</div>
</div>
...
...
@@ -563,6 +572,11 @@
document
.
getElementById
(
"subscribe_iframe"
).
src
=
"../subscribe/"
+
'[[${kylinPerformanceMisVo.performancesId}]]'
.
replaceAll
(
"
\"
"
,
""
);
}
//演出阵容
function
artistLineupInfo
()
{
document
.
getElementById
(
"artist_lineup_iframe"
).
src
=
"../artistLineup/"
+
'[[${kylinPerformanceMisVo.performancesId}]]'
.
replaceAll
(
"
\"
"
,
""
);
}
$
(
"#tab-nav-1"
).
bind
(
"click"
,
function
()
{
$
(
"#tab_iframe_1"
).
attr
(
"src"
,
prefix
+
"/performanceStatic/"
+
'[[${kylinPerformanceMisVo.performancesId}]]'
.
replaceAll
(
"
\"
"
,
""
));
});
...
...
liquidnet-bus-do/liquidnet-service-kylin-do/src/main/java/com/liquidnet/service/kylin/dao/KylinArtistAssociationStatusDto.java
0 → 100644
View file @
7cbf19f4
package
com
.
liquidnet
.
service
.
kylin
.
dao
;
import
lombok.Data
;
@Data
public
class
KylinArtistAssociationStatusDto
{
/**
* 艺人ID
*/
private
String
artistId
;
/**
* 艺人名称
*/
private
String
artistName
;
/**
* 艺人头像地址
*/
private
String
avatarUrl
;
/**
* 是否关联
*/
private
boolean
isAssociated
;
/**
* 排序 越大越靠前
*/
private
int
sort
;
}
liquidnet-bus-do/liquidnet-service-kylin-do/src/main/java/com/liquidnet/service/kylin/dao/KylinArtistPerformanceDao.java
View file @
7cbf19f4
...
...
@@ -11,6 +11,26 @@ public class KylinArtistPerformanceDao implements Serializable {
private
static
final
long
serialVersionUID
=
1L
;
/**
* 关联记录ID
*/
private
Long
mid
;
/**
* 艺人ID
*/
private
String
artistId
;
/**
* 艺人名称
*/
private
String
artistName
;
/**
* 艺人头像
*/
private
String
avatarUrl
;
/**
* 演出ID
*/
...
...
@@ -36,4 +56,9 @@ public class KylinArtistPerformanceDao implements Serializable {
*/
private
String
timeTitle
;
/**
* 排序权重
*/
private
Integer
sort
;
}
liquidnet-bus-do/liquidnet-service-kylin-do/src/main/java/com/liquidnet/service/kylin/mapper/KylinArtistPerformanceMapper.java
View file @
7cbf19f4
...
...
@@ -17,4 +17,13 @@ public interface KylinArtistPerformanceMapper extends BaseMapper<KylinArtistPerf
*/
List
<
KylinArtistPerformanceDao
>
selectPerformanceDaoByArtistId
(
@Param
(
"artistId"
)
String
artistId
);
/**
* 根据演出ID和场次ID查询艺人阵容
*
* @param performancesId 演出ID
* @param timesId 场次ID
* @return 艺人阵容列表
*/
List
<
KylinArtistPerformanceDao
>
selectArtistsByPerformanceAndTimes
(
@Param
(
"performancesId"
)
String
performancesId
,
@Param
(
"timesId"
)
String
timesId
);
}
liquidnet-bus-do/liquidnet-service-kylin-do/src/main/resources/com.liquidnet.service.kylin.mapper/KylinArtistPerformanceMapper.xml
View file @
7cbf19f4
...
...
@@ -4,12 +4,18 @@
<select
id=
"selectPerformanceDaoByArtistId"
parameterType=
"java.lang.String"
resultType=
"com.liquidnet.service.kylin.dao.KylinArtistPerformanceDao"
>
SELECT
ap.mid,
ap.artist_id as artistId,
a.artist_name as artistName,
a.avatar_url as avatarUrl,
p.performances_id as performanceId,
p.title,
DATE_FORMAT(p.time_start, '%Y-%m-%d %H:%i:%s') as timeStart,
t.ticket_times_id as timesId,
t.title as timeTitle
t.title as timeTitle,
ap.sort
FROM kylin_artist_performance ap
INNER JOIN kylin_artist a ON ap.artist_id = a.artist_id
INNER JOIN kylin_performances p ON ap.performances_id = p.performances_id
INNER JOIN kylin_ticket_times t ON ap.times_id = t.ticket_times_id
WHERE ap.artist_id = #{artistId}
...
...
@@ -24,4 +30,28 @@
AND status = 1
</select>
<!-- 根据演出ID和场次ID查询艺人阵容 -->
<select
id=
"selectArtistsByPerformanceAndTimes"
resultType=
"com.liquidnet.service.kylin.dao.KylinArtistPerformanceDao"
>
SELECT
ap.mid,
ap.artist_id as artistId,
ap.times_id as timesId,
ap.sort,
a.artist_name as artistName,
a.avatar_url as avatarUrl,
p.performances_id as performanceId,
p.title,
DATE_FORMAT(p.time_start, '%Y-%m-%d %H:%i:%s') as timeStart,
t.title as timeTitle
FROM kylin_artist_performance ap
INNER JOIN kylin_artist a ON ap.artist_id = a.artist_id
INNER JOIN kylin_performances p ON ap.performances_id = p.performances_id
INNER JOIN kylin_ticket_times t ON ap.times_id = t.ticket_times_id
WHERE ap.performances_id = #{performancesId}
<if
test=
"timesId != null and timesId != ''"
>
AND ap.times_id = #{timesId}
</if>
ORDER BY ap.sort DESC, ap.created_at ASC
</select>
</mapper>
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