记得上下班打卡 | 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
583f5927
Commit
583f5927
authored
Mar 26, 2026
by
姜秀龙
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
收钱吧 admin商品绑定和 redis 相关优化
parent
d7836fd9
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
534 additions
and
114 deletions
+534
-114
GoblinRedisConst.java
...m/liquidnet/service/goblin/constant/GoblinRedisConst.java
+14
-5
GoblinSqbPerfGoodsVo.java
...liquidnet/service/goblin/dto/vo/GoblinSqbPerfGoodsVo.java
+10
-0
SqbPerformanceGoodsController.java
...roller/zhengzai/goblin/SqbPerformanceGoodsController.java
+68
-18
index.html
...n/resources/templates/zhengzai/goblin/sqbGoods/index.html
+271
-0
details.html
...ources/templates/zhengzai/kylin/performances/details.html
+14
-0
SqbPerfGoodsBindItemParam.java
.../admin/zhengzai/goblin/dto/SqbPerfGoodsBindItemParam.java
+25
-0
ISqbPerformanceGoodsService.java
.../zhengzai/goblin/service/ISqbPerformanceGoodsService.java
+12
-4
SqbPerformanceGoodsServiceImpl.java
...i/goblin/service/impl/SqbPerformanceGoodsServiceImpl.java
+73
-57
GoblinRedisUtils.java
.../client/admin/zhengzai/goblin/utils/GoblinRedisUtils.java
+10
-0
RedisKeyExpireConst.java
.../liquidnet/service/base/constant/RedisKeyExpireConst.java
+15
-0
GoblinSqbPerformanceGoods.java
...dnet/service/goblin/entity/GoblinSqbPerformanceGoods.java
+11
-0
GoblinSqbRedisUtils.java
...om/liquidnet/service/goblin/util/GoblinSqbRedisUtils.java
+11
-30
No files found.
liquidnet-bus-api/liquidnet-service-goblin-api/src/main/java/com/liquidnet/service/goblin/constant/GoblinRedisConst.java
View file @
583f5927
...
...
@@ -425,9 +425,18 @@ public class GoblinRedisConst {
/* ----------------------------------------------------------------- */
public
static
final
String
ERP_GOBLIN_GOODS_LIST
=
PREFIX
.
concat
(
"erp:push:order:"
);
/* ----------------------------------------------------------------- */
/* ----------------------------------------------------------------- */
/* ----------------------------------------------------------------- */
/* ----------------------------------------------------------------- */
/* --------------------------------收钱吧相关--------------------------------- */
/**
* 收钱吧订单详情
*/
public
static
final
String
SQB_ORDER
=
PREFIX
.
concat
(
"sqb:order:"
);
/**
* 演出关联收钱吧商品缓存
*/
public
static
final
String
SQB_PERFORMANCE_GOODS
=
PREFIX
.
concat
(
"sqb:perf:goods:"
);
/**
* 收钱吧下单防重锁
*/
public
static
final
String
SQB_ORDER_LOCK
=
PREFIX
.
concat
(
"sqb:order:lock:"
);
}
liquidnet-bus-api/liquidnet-service-goblin-api/src/main/java/com/liquidnet/service/goblin/dto/vo/GoblinSqbPerfGoodsVo.java
View file @
583f5927
...
...
@@ -2,6 +2,7 @@ package com.liquidnet.service.goblin.dto.vo;
import
lombok.Data
;
import
java.io.Serializable
;
import
java.math.BigDecimal
;
@Data
public
class
GoblinSqbPerfGoodsVo
implements
Serializable
{
...
...
@@ -10,7 +11,16 @@ public class GoblinSqbPerfGoodsVo implements Serializable {
private
String
spuName
;
private
String
skuId
;
private
String
skuName
;
/** 商品原价(分/元,与原有 price 字段保持向后兼容) */
private
Long
price
;
private
String
coverPic
;
private
Integer
sort
;
/** 换购价格(为 null 时按售价) */
private
BigDecimal
settlementPrice
;
/** 演出结束自动下架 0-否 1-是 */
private
Integer
autoOffline
;
/** 商品库存(管理后台展示用) */
private
Integer
stock
;
/** 商品状态(管理后台展示用) */
private
Integer
status
;
}
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-web/src/main/java/com/liquidnet/client/admin/web/controller/zhengzai/goblin/SqbPerformanceGoodsController.java
View file @
583f5927
package
com
.
liquidnet
.
client
.
admin
.
web
.
controller
.
zhengzai
.
goblin
;
import
com.liquidnet.client.admin.common.core.controller.BaseController
;
import
com.liquidnet.client.admin.common.core.domain.AjaxResult
;
import
com.liquidnet.client.admin.zhengzai.goblin.dto.SqbPerfGoodsBindItemParam
;
import
com.liquidnet.client.admin.zhengzai.goblin.service.ISqbPerformanceGoodsService
;
import
com.liquidnet.service.base.ResponseDto
;
import
com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfGoodsVo
;
import
io.swagger.annotations.*
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.ui.ModelMap
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
/**
* 演出-收钱吧商品关联管理
接口
* 演出-收钱吧商品关联管理
*/
@Slf4j
@
Rest
Controller
@Controller
@Api
(
tags
=
"收钱吧-演出商品关联管理"
)
@RequestMapping
(
"sqb/performance/goods"
)
public
class
SqbPerformanceGoodsController
extends
BaseController
{
private
final
String
prefix
=
"zhengzai/goblin/sqbGoods"
;
@Autowired
private
ISqbPerformanceGoodsService
sqbPerformanceGoodsService
;
/**
* 关联商品管理页面(iframe 内嵌)
*/
@GetMapping
(
"page/{performancesId}"
)
public
String
sqbGoodsPage
(
@PathVariable
(
"performancesId"
)
String
performancesId
,
ModelMap
mmap
)
{
mmap
.
put
(
"performancesId"
,
performancesId
);
return
prefix
+
"/index"
;
}
/**
* 搜索可选商品(skuType=33 的收钱吧商品)
*/
@GetMapping
(
"search"
)
@ResponseBody
@ApiOperation
(
"搜索收钱吧候选商品"
)
@ApiImplicitParams
({
@ApiImplicitParam
(
type
=
"query"
,
dataType
=
"String"
,
name
=
"keyword"
,
value
=
"关键词"
,
required
=
false
),
})
public
AjaxResult
searchGoods
(
@RequestParam
(
value
=
"keyword"
,
required
=
false
)
String
keyword
)
{
ResponseDto
<
List
<
GoblinSqbPerfGoodsVo
>>
resp
=
sqbPerformanceGoodsService
.
searchGoods
(
keyword
);
if
(
resp
.
isSuccess
())
{
return
AjaxResult
.
success
(
resp
.
getData
());
}
return
AjaxResult
.
error
(
resp
.
getMessage
());
}
/**
* 批量绑定/保存关联商品配置
*/
@PostMapping
(
"bind"
)
@
ApiOperation
(
"关联演出与商品"
)
@Api
Response
(
code
=
200
,
message
=
"接口返回对象参数
"
)
@
ResponseBody
@Api
Operation
(
"批量绑定演出与商品(含换购价、自动下架配置)
"
)
@ApiImplicitParams
({
@ApiImplicitParam
(
type
=
"form"
,
required
=
true
,
dataType
=
"String"
,
name
=
"performancesId"
,
value
=
"演出ID"
),
@ApiImplicitParam
(
type
=
"form"
,
required
=
true
,
dataType
=
"String"
,
name
=
"skuIds"
,
value
=
"SKU ID列表(多个逗号分隔)"
),
@ApiImplicitParam
(
type
=
"form"
,
required
=
false
,
dataType
=
"Integer"
,
name
=
"sort"
,
value
=
"排序权重"
,
example
=
"0"
),
})
public
ResponseDto
<
Boolean
>
bind
(
@RequestParam
(
"performancesId"
)
String
performancesId
,
@RequestParam
(
"skuIds"
)
List
<
String
>
skuIds
,
@RequestParam
(
value
=
"sort"
,
required
=
false
,
defaultValue
=
"0"
)
Integer
sort
)
{
return
sqbPerformanceGoodsService
.
bind
(
performancesId
,
skuIds
,
sort
);
public
AjaxResult
bind
(
@RequestParam
(
"performancesId"
)
String
performancesId
,
@RequestBody
List
<
SqbPerfGoodsBindItemParam
>
items
)
{
ResponseDto
<
Boolean
>
resp
=
sqbPerformanceGoodsService
.
bind
(
performancesId
,
items
);
if
(
resp
.
isSuccess
())
{
return
AjaxResult
.
success
(
"保存成功"
);
}
return
AjaxResult
.
error
(
resp
.
getMessage
());
}
@DeleteMapping
(
"unbind"
)
/**
* 解除关联
*/
@PostMapping
(
"unbind"
)
@ResponseBody
@ApiOperation
(
"解除演出与商品关联"
)
@ApiResponse
(
code
=
200
,
message
=
"接口返回对象参数"
)
@ApiImplicitParams
({
@ApiImplicitParam
(
type
=
"form"
,
required
=
true
,
dataType
=
"String"
,
name
=
"performancesId"
,
value
=
"演出ID"
),
@ApiImplicitParam
(
type
=
"form"
,
required
=
true
,
dataType
=
"String"
,
name
=
"skuId"
,
value
=
"SKU ID"
),
})
public
ResponseDto
<
Boolean
>
unbind
(
@RequestParam
(
"performancesId"
)
String
performancesId
,
public
AjaxResult
unbind
(
@RequestParam
(
"performancesId"
)
String
performancesId
,
@RequestParam
(
"skuId"
)
String
skuId
)
{
return
sqbPerformanceGoodsService
.
unbind
(
performancesId
,
skuId
);
ResponseDto
<
Boolean
>
resp
=
sqbPerformanceGoodsService
.
unbind
(
performancesId
,
skuId
);
if
(
resp
.
isSuccess
())
{
return
AjaxResult
.
success
(
"已取消关联"
);
}
return
AjaxResult
.
error
(
resp
.
getMessage
());
}
/**
* 查询演出已关联商品列表
*/
@GetMapping
(
"list"
)
@ResponseBody
@ApiOperation
(
"查询演出关联商品列表(管理后台)"
)
@ApiResponse
(
code
=
200
,
message
=
"接口返回对象参数"
)
@ApiImplicitParams
({
@ApiImplicitParam
(
type
=
"query"
,
required
=
true
,
dataType
=
"String"
,
name
=
"performancesId"
,
value
=
"演出ID"
),
})
public
ResponseDto
<
List
<
GoblinSqbPerfGoodsVo
>>
list
(
@RequestParam
(
"performancesId"
)
String
performancesId
)
{
return
sqbPerformanceGoodsService
.
list
(
performancesId
);
public
AjaxResult
list
(
@RequestParam
(
"performancesId"
)
String
performancesId
)
{
ResponseDto
<
List
<
GoblinSqbPerfGoodsVo
>>
resp
=
sqbPerformanceGoodsService
.
list
(
performancesId
);
if
(
resp
.
isSuccess
())
{
return
AjaxResult
.
success
(
resp
.
getData
());
}
return
AjaxResult
.
error
(
resp
.
getMessage
());
}
}
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-web/src/main/resources/templates/zhengzai/goblin/sqbGoods/index.html
0 → 100644
View file @
583f5927
<!DOCTYPE html>
<html
lang=
"zh"
xmlns:th=
"http://www.thymeleaf.org"
>
<head>
<th:block
th:include=
"include :: header('关联推荐商品')"
/>
<link
rel=
"stylesheet"
th:href=
"@{/ajax/libs/select2/select2.min.css}"
/>
<style>
body
{
background
:
#fff
;
}
.page-wrap
{
padding
:
16px
;
}
.tip
{
color
:
#e8501a
;
font-size
:
12px
;
margin-left
:
8px
;
}
.section-title
{
font-weight
:
bold
;
margin
:
16px
0
8px
;
}
.auto-offline-bar
{
margin-bottom
:
10px
;
font-size
:
13px
;
}
.settlement-input
{
width
:
100px
;
}
.img-thumb
{
width
:
40px
;
height
:
40px
;
object-fit
:
cover
;
border-radius
:
4px
;
}
.select2-container
{
min-width
:
380px
;
}
.add-row
{
margin-bottom
:
16px
;
display
:
flex
;
align-items
:
center
;
gap
:
10px
;
}
</style>
</head>
<body
class=
"white-bg"
>
<div
class=
"page-wrap"
>
<div
class=
"section-title"
>
关联推荐商品
<span
class=
"tip"
>
如未关联商品,则APP和小程序前端推荐模块隐藏
</span>
</div>
<!-- Select2 选择框 -->
<div
class=
"add-row"
>
<select
id=
"goodsSelect"
style=
"width:400px;"
>
<option
value=
""
>
请输入商品名称搜索...
</option>
</select>
<span
style=
"color:#999;font-size:12px;"
>
选中商品后自动添加到列表
</span>
</div>
<!-- 已关联商品 -->
<div
class=
"section-title"
>
已关联商品
<span
class=
"tip"
>
⚠ 设置换购价格,则商品参与演出票换购活动,不设置则按售价售卖,换购价须小于商品售价
</span>
</div>
<div
class=
"auto-offline-bar"
>
<label>
<input
type=
"checkbox"
id=
"globalAutoOffline"
onchange=
"toggleGlobalAutoOffline(this)"
/>
演出结束商品自动下架
</label>
</div>
<div
class=
"table-responsive"
>
<table
class=
"table table-bordered"
id=
"linkedGoodsTable"
>
<thead>
<tr>
<th>
商品ID
</th>
<th>
商品头图
</th>
<th>
商品名称
</th>
<th>
商品售价(元)
</th>
<th>
换购价(元)
</th>
<th>
商品库存
</th>
<th>
自动下架
</th>
<th>
操作
</th>
</tr>
</thead>
<tbody
id=
"linkedGoodsBody"
>
<tr
id=
"emptyRow"
>
<td
colspan=
"8"
style=
"text-align:center;color:#999;"
>
暂无关联商品
</td>
</tr>
</tbody>
</table>
</div>
<button
type=
"button"
class=
"btn btn-primary"
onclick=
"saveConfig()"
>
保存配置
</button>
</div>
<th:block
th:include=
"include :: footer"
/>
<script
th:src=
"@{/ajax/libs/select2/select2.min.js}"
></script>
<script
th:inline=
"javascript"
>
var
performancesId
=
/*[[${performancesId}]]*/
''
;
var
prefix
=
ctx
+
'sqb/performance/goods'
;
// 内存中维护已关联商品列表
var
linkedGoods
=
[];
// ——— mock 数据(接口无数据时用于测试)———
var
MOCK_GOODS
=
[
{
skuId
:
'SKU_MOCK_001'
,
spuId
:
'SPU_MOCK_001'
,
spuName
:
'收钱吧周边T恤'
,
skuName
:
'收钱吧周边T恤 M码'
,
price
:
9900
,
stock
:
100
,
coverPic
:
''
},
{
skuId
:
'SKU_MOCK_002'
,
spuId
:
'SPU_MOCK_002'
,
spuName
:
'演出纪念手册'
,
skuName
:
'演出纪念手册 精装版'
,
price
:
4900
,
stock
:
200
,
coverPic
:
''
},
{
skuId
:
'SKU_MOCK_003'
,
spuId
:
'SPU_MOCK_003'
,
spuName
:
'限定徽章套装'
,
skuName
:
'限定徽章套装 五件套'
,
price
:
3900
,
stock
:
50
,
coverPic
:
''
},
{
skuId
:
'SKU_MOCK_004'
,
spuId
:
'SPU_MOCK_004'
,
spuName
:
'摇滚帽子'
,
skuName
:
'摇滚帽子 黑色'
,
price
:
5900
,
stock
:
80
,
coverPic
:
''
},
];
$
(
function
()
{
initSelect2
();
loadLinkedGoods
();
});
// 初始化 Select2(AJAX 搜索 + mock fallback)
function
initSelect2
()
{
$
(
'#goodsSelect'
).
select2
({
allowClear
:
true
,
placeholder
:
'请输入商品名称搜索...'
,
minimumInputLength
:
0
,
language
:
{
inputTooShort
:
function
()
{
return
'请输入关键词'
;
}
},
ajax
:
{
url
:
prefix
+
'/search'
,
dataType
:
'json'
,
delay
:
300
,
data
:
function
(
params
)
{
return
{
keyword
:
params
.
term
||
''
};
},
processResults
:
function
(
resp
)
{
var
list
=
(
resp
&&
resp
.
data
)
?
resp
.
data
:
[];
// 接口无数据时回退到 mock
if
(
list
.
length
===
0
)
{
list
=
filterMock
(
$
(
'#goodsSelect'
).
data
(
'select2'
).
options
.
get
(
'ajax'
).
data
({
term
:
''
}).
keyword
);
}
return
{
results
:
list
.
map
(
function
(
item
)
{
return
{
id
:
item
.
skuId
,
text
:
(
item
.
spuName
||
item
.
skuName
),
_raw
:
item
};
})};
},
error
:
function
()
{
// 接口异常时使用 mock
return
{
results
:
MOCK_GOODS
.
map
(
function
(
item
)
{
return
{
id
:
item
.
skuId
,
text
:
item
.
spuName
,
_raw
:
item
};
})};
}
}
});
// 选中即添加
$
(
'#goodsSelect'
).
on
(
'select2:select'
,
function
(
e
)
{
var
raw
=
e
.
params
.
data
.
_raw
;
if
(
!
raw
)
{
// 兼容:从 mock 中找
raw
=
MOCK_GOODS
.
find
(
function
(
m
){
return
m
.
skuId
===
e
.
params
.
data
.
id
;
});
}
if
(
raw
)
{
addLinked
(
raw
);
}
// 清空选择框
$
(
this
).
val
(
null
).
trigger
(
'change'
);
});
// 若 ajax 报错或首次打开无关键词,预填 mock
$
(
'#goodsSelect'
).
on
(
'select2:open'
,
function
()
{
// 触发一次搜索以显示 mock 数据
setTimeout
(
function
()
{
var
searchInput
=
document
.
querySelector
(
'.select2-search__field'
);
if
(
searchInput
)
{
$
(
searchInput
).
trigger
(
'input'
);
}
},
100
);
});
}
function
filterMock
(
keyword
)
{
if
(
!
keyword
)
return
MOCK_GOODS
;
return
MOCK_GOODS
.
filter
(
function
(
m
)
{
return
m
.
spuName
.
indexOf
(
keyword
)
>=
0
;
});
}
// 加载已关联商品
function
loadLinkedGoods
()
{
$
.
get
(
prefix
+
'/list'
,
{
performancesId
:
performancesId
},
function
(
resp
)
{
if
(
resp
.
code
===
0
&&
resp
.
data
&&
resp
.
data
.
length
>
0
)
{
linkedGoods
=
resp
.
data
.
map
(
function
(
item
)
{
return
{
skuId
:
item
.
skuId
,
spuId
:
item
.
spuId
,
spuName
:
item
.
spuName
||
item
.
skuName
,
skuName
:
item
.
skuName
,
coverPic
:
item
.
coverPic
||
''
,
price
:
item
.
price
,
stock
:
item
.
stock
,
settlementPrice
:
item
.
settlementPrice
||
''
,
autoOffline
:
item
.
autoOffline
||
0
};
});
renderLinkedGoods
();
}
});
}
function
renderLinkedGoods
()
{
var
tbody
=
document
.
getElementById
(
'linkedGoodsBody'
);
if
(
linkedGoods
.
length
===
0
)
{
tbody
.
innerHTML
=
'<tr id="emptyRow"><td colspan="8" style="text-align:center;color:#999;">暂无关联商品</td></tr>'
;
return
;
}
var
html
=
''
;
linkedGoods
.
forEach
(
function
(
item
,
idx
)
{
var
priceYuan
=
item
.
price
?
(
item
.
price
/
100
).
toFixed
(
2
)
:
'-'
;
var
settlementVal
=
item
.
settlementPrice
||
''
;
var
autoChecked
=
item
.
autoOffline
==
1
?
'checked'
:
''
;
var
imgHtml
=
item
.
coverPic
?
'<img src="'
+
item
.
coverPic
+
'" class="img-thumb"/>'
:
'<span style="color:#ccc;font-size:12px;">无图</span>'
;
html
+=
'<tr data-idx="'
+
idx
+
'">'
;
html
+=
'<td><small>'
+
item
.
skuId
+
'</small></td>'
;
html
+=
'<td>'
+
imgHtml
+
'</td>'
;
html
+=
'<td>'
+
(
item
.
spuName
||
item
.
skuName
||
'-'
)
+
'</td>'
;
html
+=
'<td>'
+
priceYuan
+
'</td>'
;
html
+=
'<td><input type="number" class="form-control settlement-input" value="'
+
settlementVal
+
'" placeholder="不填按售价" onchange="updateSettlement('
+
idx
+
', this.value)" min="0" step="0.01"/></td>'
;
html
+=
'<td>'
+
(
item
.
stock
!=
null
?
item
.
stock
:
'-'
)
+
'</td>'
;
html
+=
'<td><input type="checkbox" '
+
autoChecked
+
' onchange="updateAutoOffline('
+
idx
+
', this)"/></td>'
;
html
+=
'<td><button type="button" class="btn btn-xs btn-danger" onclick="removeLinked('
+
idx
+
')">取消关联</button></td>'
;
html
+=
'</tr>'
;
});
tbody
.
innerHTML
=
html
;
}
function
addLinked
(
item
)
{
for
(
var
i
=
0
;
i
<
linkedGoods
.
length
;
i
++
)
{
if
(
linkedGoods
[
i
].
skuId
===
item
.
skuId
)
{
layer
.
msg
(
'该商品已在关联列表中'
);
return
;
}
}
linkedGoods
.
push
({
skuId
:
item
.
skuId
,
spuId
:
item
.
spuId
||
''
,
spuName
:
item
.
spuName
,
skuName
:
item
.
skuName
,
coverPic
:
item
.
coverPic
||
''
,
price
:
item
.
price
,
stock
:
item
.
stock
,
settlementPrice
:
null
,
autoOffline
:
0
});
renderLinkedGoods
();
layer
.
msg
(
'已添加,可配置换购价后保存'
);
}
function
updateSettlement
(
idx
,
val
)
{
linkedGoods
[
idx
].
settlementPrice
=
val
?
parseFloat
(
val
)
:
null
;
}
function
updateAutoOffline
(
idx
,
checkbox
)
{
linkedGoods
[
idx
].
autoOffline
=
checkbox
.
checked
?
1
:
0
;
}
function
toggleGlobalAutoOffline
(
checkbox
)
{
var
val
=
checkbox
.
checked
?
1
:
0
;
linkedGoods
.
forEach
(
function
(
item
)
{
item
.
autoOffline
=
val
;
});
renderLinkedGoods
();
}
function
removeLinked
(
idx
)
{
var
skuId
=
linkedGoods
[
idx
].
skuId
;
// mock 数据直接从内存移除,无需请求接口
if
(
skuId
.
startsWith
(
'SKU_MOCK_'
))
{
linkedGoods
.
splice
(
idx
,
1
);
renderLinkedGoods
();
return
;
}
if
(
!
confirm
(
'确定取消关联该商品?'
))
return
;
$
.
post
(
prefix
+
'/unbind'
,
{
performancesId
:
performancesId
,
skuId
:
skuId
},
function
(
resp
)
{
if
(
resp
.
code
===
0
)
{
linkedGoods
.
splice
(
idx
,
1
);
renderLinkedGoods
();
}
else
{
alert
(
resp
.
msg
||
resp
.
message
||
'操作失败'
);
}
});
}
function
saveConfig
()
{
var
items
=
linkedGoods
.
map
(
function
(
item
)
{
return
{
skuId
:
item
.
skuId
,
sort
:
0
,
settlementPrice
:
item
.
settlementPrice
||
null
,
autoOffline
:
item
.
autoOffline
||
0
};
});
$
.
ajax
({
url
:
prefix
+
'/bind?performancesId='
+
encodeURIComponent
(
performancesId
),
type
:
'POST'
,
contentType
:
'application/json'
,
data
:
JSON
.
stringify
(
items
),
success
:
function
(
resp
)
{
if
(
resp
.
code
===
0
)
{
layer
.
msg
(
'保存成功'
);
}
else
{
layer
.
msg
(
resp
.
msg
||
resp
.
message
||
'保存失败'
,
{
icon
:
2
});
}
},
error
:
function
()
{
layer
.
msg
(
'请求失败,请重试'
,
{
icon
:
2
});
}
});
}
</script>
</body>
</html>
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-web/src/main/resources/templates/zhengzai/kylin/performances/details.html
View file @
583f5927
...
...
@@ -45,6 +45,8 @@
</li>
<li
id=
"li-tab-12"
><a
data-toggle=
"tab"
href=
"#tab-12"
aria-expanded=
"false"
onclick=
"artistLineupInfo()"
>
演出阵容
</a>
</li>
<li
id=
"li-tab-13"
><a
data-toggle=
"tab"
href=
"#tab-13"
aria-expanded=
"false"
onclick=
"sqbGoodsInfo()"
>
关联推荐商品
</a>
</li>
</ul>
<div
class=
"tab-content"
>
<div
id=
"tab-1"
class=
"tab-pane"
>
...
...
@@ -373,6 +375,13 @@
height=
800px
frameborder=
0
></iframe>
</div>
</div>
<div
id=
"tab-13"
class=
"tab-pane"
>
<div
class=
"panel-body"
>
<iframe
id=
"sqb_goods_iframe"
name=
"sqb_goods_iframe"
marginwidth=
0
marginheight=
0
width=
100%
height=
800px
frameborder=
0
></iframe>
</div>
</div>
</div>
</div>
</div>
...
...
@@ -578,6 +587,11 @@
document
.
getElementById
(
"artist_lineup_iframe"
).
src
=
"../artistLineup/"
+
'[[${kylinPerformanceMisVo.performancesId}]]'
.
replaceAll
(
"
\"
"
,
""
);
}
//关联推荐商品
function
sqbGoodsInfo
()
{
document
.
getElementById
(
"sqb_goods_iframe"
).
src
=
ctx
+
"sqb/performance/goods/page/"
+
'[[${kylinPerformanceMisVo.performancesId}]]'
.
replaceAll
(
"
\"
"
,
""
);
}
$
(
"#tab-nav-1"
).
bind
(
"click"
,
function
()
{
$
(
"#tab_iframe_1"
).
attr
(
"src"
,
prefix
+
"/performanceStatic/"
+
'[[${kylinPerformanceMisVo.performancesId}]]'
.
replaceAll
(
"
\"
"
,
""
));
});
...
...
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-zhengzai/src/main/java/com/liquidnet/client/admin/zhengzai/goblin/dto/SqbPerfGoodsBindItemParam.java
0 → 100644
View file @
583f5927
package
com
.
liquidnet
.
client
.
admin
.
zhengzai
.
goblin
.
dto
;
import
lombok.Data
;
import
java.io.Serializable
;
import
java.math.BigDecimal
;
/**
* 演出-商品关联绑定请求 DTO
*/
@Data
public
class
SqbPerfGoodsBindItemParam
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
/** SKU ID */
private
String
skuId
;
/** 排序权重 */
private
Integer
sort
;
/** 换购价格(null 表示不设置换购价,按原价售卖) */
private
BigDecimal
settlementPrice
;
/** 演出结束自动下架 0-否 1-是 */
private
Integer
autoOffline
;
}
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-zhengzai/src/main/java/com/liquidnet/client/admin/zhengzai/goblin/service/ISqbPerformanceGoodsService.java
View file @
583f5927
package
com
.
liquidnet
.
client
.
admin
.
zhengzai
.
goblin
.
service
;
import
com.liquidnet.client.admin.zhengzai.goblin.dto.SqbPerfGoodsBindItemParam
;
import
com.liquidnet.service.base.ResponseDto
;
import
com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfGoodsVo
;
...
...
@@ -11,14 +12,13 @@ import java.util.List;
public
interface
ISqbPerformanceGoodsService
{
/**
* 关联演出与商品(批量)
* 关联演出与商品(批量
,支持换购价/自动下架配置
)
*
* @param performancesId 演出ID
* @param skuIds SKU ID 列表
* @param sort 排序权重
* @param items 绑定项列表(含配置)
* @return 操作结果
*/
ResponseDto
<
Boolean
>
bind
(
String
performancesId
,
List
<
S
tring
>
skuIds
,
Integer
sort
);
ResponseDto
<
Boolean
>
bind
(
String
performancesId
,
List
<
S
qbPerfGoodsBindItemParam
>
items
);
/**
* 解除演出与商品关联
...
...
@@ -36,4 +36,12 @@ public interface ISqbPerformanceGoodsService {
* @return 商品列表
*/
ResponseDto
<
List
<
GoblinSqbPerfGoodsVo
>>
list
(
String
performancesId
);
/**
* 搜索收钱吧商品(skuType=33,供关联候选)
*
* @param keyword 商品名称关键词
* @return 商品列表
*/
ResponseDto
<
List
<
GoblinSqbPerfGoodsVo
>>
searchGoods
(
String
keyword
);
}
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-zhengzai/src/main/java/com/liquidnet/client/admin/zhengzai/goblin/service/impl/SqbPerformanceGoodsServiceImpl.java
View file @
583f5927
...
...
@@ -2,12 +2,11 @@ package com.liquidnet.client.admin.zhengzai.goblin.service.impl;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper
;
import
com.liquidnet.client.admin.zhengzai.goblin.dto.SqbPerfGoodsBindItemParam
;
import
com.liquidnet.client.admin.zhengzai.goblin.service.ISqbPerformanceGoodsService
;
import
com.liquidnet.common.cache.redis.util.RedisDataSourceUtil
;
import
com.liquidnet.commons.lang.util.IDGenerator
;
import
com.liquidnet.client.admin.zhengzai.goblin.utils.GoblinRedisUtils
;
import
com.liquidnet.service.base.ResponseDto
;
import
com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfGoodsVo
;
import
com.liquidnet.service.goblin.entity.GoblinGoods
;
import
com.liquidnet.service.goblin.entity.GoblinGoodsSku
;
import
com.liquidnet.service.goblin.entity.GoblinSqbPerformanceGoods
;
import
com.liquidnet.service.goblin.mapper.GoblinGoodsMapper
;
...
...
@@ -16,6 +15,7 @@ import com.liquidnet.service.goblin.mapper.GoblinSqbPerformanceGoodsMapper;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.StringUtils
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
...
...
@@ -33,8 +33,8 @@ import java.util.stream.Collectors;
@Service
public
class
SqbPerformanceGoodsServiceImpl
implements
ISqbPerformanceGoodsService
{
/**
Redis key 前缀,与 goblin C端接口保持一致
*/
private
static
final
String
PERF_GOODS_CACHE_KEY_PREFIX
=
"goblin:sqb:perf:goods:"
;
/**
skuType=33 代表收钱吧商品
*/
private
static
final
int
SQB_SKU_TYPE
=
33
;
@Autowired
private
GoblinSqbPerformanceGoodsMapper
performanceGoodsMapper
;
...
...
@@ -46,27 +46,27 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
private
GoblinGoodsSkuMapper
goblinGoodsSkuMapper
;
@Autowired
private
RedisDataSourceUtil
redisDataSourceUtil
;
private
GoblinRedisUtils
goblinRedisUtils
;
@Override
public
ResponseDto
<
Boolean
>
bind
(
String
performancesId
,
List
<
S
tring
>
skuIds
,
Integer
sort
)
{
if
(
performancesId
==
null
||
performancesId
.
isEmpty
(
))
{
public
ResponseDto
<
Boolean
>
bind
(
String
performancesId
,
List
<
S
qbPerfGoodsBindItemParam
>
items
)
{
if
(
!
StringUtils
.
hasText
(
performancesId
))
{
return
ResponseDto
.
failure
(
"演出ID不能为空"
);
}
if
(
skuIds
==
null
||
skuId
s
.
isEmpty
())
{
return
ResponseDto
.
failure
(
"
SKU
列表不能为空"
);
if
(
items
==
null
||
item
s
.
isEmpty
())
{
return
ResponseDto
.
failure
(
"
商品
列表不能为空"
);
}
String
now
=
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd HH:mm:ss"
));
int
sortVal
=
(
sort
!=
null
)
?
sort
:
0
;
try
{
for
(
String
skuId
:
skuIds
)
{
if
(
skuId
==
null
||
skuId
.
isEmpty
())
{
for
(
SqbPerfGoodsBindItemParam
item
:
items
)
{
String
skuId
=
item
.
getSkuId
();
if
(!
StringUtils
.
hasText
(
skuId
))
{
continue
;
}
// 查询 SKU 获取 spuId
// 查询 SKU 获取 spuId
,并校验 skuType=33
LambdaQueryWrapper
<
GoblinGoodsSku
>
skuQuery
=
new
LambdaQueryWrapper
<>();
skuQuery
.
eq
(
GoblinGoodsSku:
:
getSkuId
,
skuId
).
last
(
"LIMIT 1"
);
GoblinGoodsSku
sku
=
goblinGoodsSkuMapper
.
selectOne
(
skuQuery
);
...
...
@@ -74,6 +74,13 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
log
.
warn
(
"[演出商品关联] SKU不存在,skuId={}"
,
skuId
);
continue
;
}
if
(
sku
.
getSkuType
()
==
null
||
sku
.
getSkuType
()
!=
SQB_SKU_TYPE
)
{
log
.
warn
(
"[演出商品关联] 非收钱吧商品(skuType!=33),skuId={}"
,
skuId
);
continue
;
}
int
sortVal
=
item
.
getSort
()
!=
null
?
item
.
getSort
()
:
0
;
int
autoOfflineVal
=
item
.
getAutoOffline
()
!=
null
?
item
.
getAutoOffline
()
:
0
;
// 检查是否已存在关联
LambdaQueryWrapper
<
GoblinSqbPerformanceGoods
>
existQuery
=
new
LambdaQueryWrapper
<>();
...
...
@@ -83,12 +90,14 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
GoblinSqbPerformanceGoods
existing
=
performanceGoodsMapper
.
selectOne
(
existQuery
);
if
(
existing
!=
null
)
{
// 已存在则更新
sort 和 status
// 已存在则更新
配置
LambdaUpdateWrapper
<
GoblinSqbPerformanceGoods
>
updateWrapper
=
new
LambdaUpdateWrapper
<>();
updateWrapper
.
eq
(
GoblinSqbPerformanceGoods:
:
getPerformancesId
,
performancesId
)
.
eq
(
GoblinSqbPerformanceGoods:
:
getSkuId
,
skuId
)
.
set
(
GoblinSqbPerformanceGoods:
:
getSort
,
sortVal
)
.
set
(
GoblinSqbPerformanceGoods:
:
getStatus
,
1
)
.
set
(
GoblinSqbPerformanceGoods:
:
getSettlementPrice
,
item
.
getSettlementPrice
())
.
set
(
GoblinSqbPerformanceGoods:
:
getAutoOffline
,
autoOfflineVal
)
.
set
(
GoblinSqbPerformanceGoods:
:
getUpdatedAt
,
now
);
performanceGoodsMapper
.
update
(
null
,
updateWrapper
);
}
else
{
...
...
@@ -99,6 +108,8 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
entity
.
setSkuId
(
skuId
);
entity
.
setSort
(
sortVal
);
entity
.
setStatus
(
1
);
entity
.
setSettlementPrice
(
item
.
getSettlementPrice
());
entity
.
setAutoOffline
(
autoOfflineVal
);
entity
.
setCreatedAt
(
now
);
entity
.
setUpdatedAt
(
now
);
performanceGoodsMapper
.
insert
(
entity
);
...
...
@@ -106,7 +117,7 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
}
// 删除 Redis 缓存,由 C端接口下次请求时重建
delPerf
GoodsCache
(
performancesId
);
goblinRedisUtils
.
delPerformance
GoodsCache
(
performancesId
);
return
ResponseDto
.
success
(
Boolean
.
TRUE
);
}
catch
(
Exception
e
)
{
...
...
@@ -117,10 +128,10 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
@Override
public
ResponseDto
<
Boolean
>
unbind
(
String
performancesId
,
String
skuId
)
{
if
(
performancesId
==
null
||
performancesId
.
isEmpty
(
))
{
if
(
!
StringUtils
.
hasText
(
performancesId
))
{
return
ResponseDto
.
failure
(
"演出ID不能为空"
);
}
if
(
skuId
==
null
||
skuId
.
isEmpty
(
))
{
if
(
!
StringUtils
.
hasText
(
skuId
))
{
return
ResponseDto
.
failure
(
"SKU ID不能为空"
);
}
...
...
@@ -137,9 +148,7 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
return
ResponseDto
.
failure
(
"关联记录不存在"
);
}
// 删除 Redis 缓存
delPerfGoodsCache
(
performancesId
);
goblinRedisUtils
.
delPerformanceGoodsCache
(
performancesId
);
return
ResponseDto
.
success
(
Boolean
.
TRUE
);
}
catch
(
Exception
e
)
{
log
.
error
(
"[演出商品关联] unbind 异常,performancesId={}, skuId={}"
,
performancesId
,
skuId
,
e
);
...
...
@@ -149,12 +158,11 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
@Override
public
ResponseDto
<
List
<
GoblinSqbPerfGoodsVo
>>
list
(
String
performancesId
)
{
if
(
performancesId
==
null
||
performancesId
.
isEmpty
(
))
{
if
(
!
StringUtils
.
hasText
(
performancesId
))
{
return
ResponseDto
.
failure
(
"演出ID不能为空"
);
}
try
{
// 查询启用状态的关联记录
LambdaQueryWrapper
<
GoblinSqbPerformanceGoods
>
query
=
new
LambdaQueryWrapper
<>();
query
.
eq
(
GoblinSqbPerformanceGoods:
:
getPerformancesId
,
performancesId
)
.
eq
(
GoblinSqbPerformanceGoods:
:
getStatus
,
1
)
...
...
@@ -165,47 +173,32 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
return
ResponseDto
.
success
(
new
ArrayList
<>());
}
// 收集 skuId 和 spuId
List
<
String
>
skuIds
=
relations
.
stream
()
.
map
(
GoblinSqbPerformanceGoods:
:
getSkuId
)
.
collect
(
Collectors
.
toList
());
List
<
String
>
spuIds
=
relations
.
stream
()
.
map
(
GoblinSqbPerformanceGoods:
:
getSpuId
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
// 批量查询 SKU 信息
.
map
(
GoblinSqbPerformanceGoods:
:
getSkuId
).
collect
(
Collectors
.
toList
());
// 因为收钱吧商品 SKU 已经包含了名称和图片等全部信息,无需再去关联查询 SPU 表
LambdaQueryWrapper
<
GoblinGoodsSku
>
skuQuery
=
new
LambdaQueryWrapper
<>();
skuQuery
.
in
(
GoblinGoodsSku:
:
getSkuId
,
skuIds
);
List
<
GoblinGoodsSku
>
skuList
=
goblinGoodsSkuMapper
.
selectList
(
skuQuery
);
Map
<
String
,
GoblinGoodsSku
>
skuMap
=
skuList
.
stream
()
.
collect
(
Collectors
.
toMap
(
GoblinGoodsSku:
:
getSkuId
,
Function
.
identity
(),
(
a
,
b
)
->
a
));
// 批量查询 SPU 信息
LambdaQueryWrapper
<
GoblinGoods
>
spuQuery
=
new
LambdaQueryWrapper
<>();
spuQuery
.
in
(
GoblinGoods:
:
getSpuId
,
spuIds
);
List
<
GoblinGoods
>
spuList
=
goblinGoodsMapper
.
selectList
(
spuQuery
);
Map
<
String
,
GoblinGoods
>
spuMap
=
spuList
.
stream
()
.
collect
(
Collectors
.
toMap
(
GoblinGoods:
:
getSpuId
,
Function
.
identity
(),
(
a
,
b
)
->
a
));
Map
<
String
,
GoblinGoodsSku
>
skuMap
=
goblinGoodsSkuMapper
.
selectList
(
skuQuery
)
.
stream
().
collect
(
Collectors
.
toMap
(
GoblinGoodsSku:
:
getSkuId
,
Function
.
identity
(),
(
a
,
b
)
->
a
));
// 组装 VO
List
<
GoblinSqbPerfGoodsVo
>
result
=
new
ArrayList
<>();
for
(
GoblinSqbPerformanceGoods
rel
:
relations
)
{
GoblinSqbPerfGoodsVo
vo
=
new
GoblinSqbPerfGoodsVo
();
vo
.
setSkuId
(
rel
.
getSkuId
());
vo
.
setSpuId
(
rel
.
getSpuId
());
vo
.
setSort
(
rel
.
getSort
());
vo
.
setSettlementPrice
(
rel
.
getSettlementPrice
());
vo
.
setAutoOffline
(
rel
.
getAutoOffline
());
vo
.
setStatus
(
rel
.
getStatus
());
GoblinGoodsSku
sku
=
skuMap
.
get
(
rel
.
getSkuId
());
if
(
sku
!=
null
)
{
vo
.
setSkuName
(
sku
.
getName
());
vo
.
setSpuName
(
sku
.
getName
());
// 取代原本从 SPU 获取名称,直接用 SKU 名称
vo
.
setCoverPic
(
sku
.
getSkuPic
());
// 统一使用 SKU 上的默认图片(即原 SPU coverPic)
vo
.
setPrice
(
sku
.
getPrice
()
!=
null
?
sku
.
getPrice
().
longValue
()
:
null
);
}
GoblinGoods
spu
=
spuMap
.
get
(
rel
.
getSpuId
());
if
(
spu
!=
null
)
{
vo
.
setSpuName
(
spu
.
getName
());
vo
.
setCoverPic
(
spu
.
getCoverPic
());
vo
.
setStock
(
sku
.
getSkuStock
());
}
result
.
add
(
vo
);
...
...
@@ -218,16 +211,39 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
}
}
/**
* 删除演出关联商品的 Redis 缓存
*/
private
void
delPerfGoodsCache
(
String
performancesId
)
{
@Override
public
ResponseDto
<
List
<
GoblinSqbPerfGoodsVo
>>
searchGoods
(
String
keyword
)
{
try
{
String
cacheKey
=
PERF_GOODS_CACHE_KEY_PREFIX
+
performancesId
;
redisDataSourceUtil
.
getRedisGoblinUtil
().
del
(
cacheKey
);
log
.
info
(
"[演出商品关联] 已删除 Redis 缓存,key={}"
,
cacheKey
);
// 收钱吧商品的所有核心展示信息均已同步到 SKU(Type=33)表中,直接一次查询避免二次查 SPU
LambdaQueryWrapper
<
GoblinGoodsSku
>
skuQuery
=
new
LambdaQueryWrapper
<>();
skuQuery
.
eq
(
GoblinGoodsSku:
:
getSkuType
,
SQB_SKU_TYPE
);
if
(
StringUtils
.
hasText
(
keyword
))
{
skuQuery
.
like
(
GoblinGoodsSku:
:
getName
,
keyword
);
}
skuQuery
.
last
(
"LIMIT 50"
);
List
<
GoblinGoodsSku
>
skuList
=
goblinGoodsSkuMapper
.
selectList
(
skuQuery
);
if
(
skuList
.
isEmpty
())
{
return
ResponseDto
.
success
(
new
ArrayList
<>());
}
List
<
GoblinSqbPerfGoodsVo
>
result
=
new
ArrayList
<>();
for
(
GoblinGoodsSku
sku
:
skuList
)
{
GoblinSqbPerfGoodsVo
vo
=
new
GoblinSqbPerfGoodsVo
();
vo
.
setSkuId
(
sku
.
getSkuId
());
vo
.
setSpuId
(
sku
.
getSpuId
());
vo
.
setSkuName
(
sku
.
getName
());
vo
.
setSpuName
(
sku
.
getName
());
// 前端显示需要,统一赋值为 sku 名称
vo
.
setCoverPic
(
sku
.
getSkuPic
());
// 同步阶段已将图片存入了 skuPic
vo
.
setPrice
(
sku
.
getPrice
()
!=
null
?
sku
.
getPrice
().
longValue
()
:
null
);
vo
.
setStock
(
sku
.
getSkuStock
());
result
.
add
(
vo
);
}
return
ResponseDto
.
success
(
result
);
}
catch
(
Exception
e
)
{
log
.
warn
(
"[演出商品关联] 删除 Redis 缓存失败,performancesId={}"
,
performancesId
,
e
);
log
.
error
(
"[演出商品关联] searchGoods 异常,keyword={}"
,
keyword
,
e
);
return
ResponseDto
.
failure
(
"搜索失败:"
+
e
.
getMessage
());
}
}
}
liquidnet-bus-client/liquidnet-client-admin/liquidnet-client-admin-zhengzai/src/main/java/com/liquidnet/client/admin/zhengzai/goblin/utils/GoblinRedisUtils.java
View file @
583f5927
...
...
@@ -249,4 +249,14 @@ public class GoblinRedisUtils {
rk
=
rk
.
concat
(
skuId
);
return
(
int
)
redisDataSourceUtil
.
getRedisGoblinUtil
().
incr
(
rk
,
stock
);
}
/**
* 清除演出关联收钱吧商品缓存
*
* @param performancesId 演出ID
*/
public
void
delPerformanceGoodsCache
(
String
performancesId
)
{
String
redisKey
=
GoblinRedisConst
.
SQB_PERFORMANCE_GOODS
.
concat
(
performancesId
);
redisDataSourceUtil
.
getRedisGoblinUtil
().
del
(
redisKey
);
}
}
liquidnet-bus-common/liquidnet-common-service-base/src/main/java/com/liquidnet/service/base/constant/RedisKeyExpireConst.java
View file @
583f5927
...
...
@@ -56,4 +56,19 @@ public class RedisKeyExpireConst {
// 演出关联阵容缓存过期时间
public
static
final
long
PERFORMANCES_ARTISTS_EXPIRE
=
30
*
24
*
60
*
60
;
/**
* 演出关联收钱吧商品缓存过期时间 (5分钟)
*/
public
static
final
long
SQB_PERFORMANCE_GOODS_EXPIRE
=
5
*
60
;
/**
* 收钱吧订单详情过期时间 (2小时)
*/
public
static
final
long
SQB_ORDER_EXPIRE
=
2
*
60
*
60
;
/**
* 收钱吧下单防重锁过期时间 (10秒)
*/
public
static
final
long
SQB_ORDER_LOCK_EXPIRE
=
10
;
}
liquidnet-bus-do/liquidnet-service-goblin-do/src/main/java/com/liquidnet/service/goblin/entity/GoblinSqbPerformanceGoods.java
View file @
583f5927
...
...
@@ -7,6 +7,7 @@ import lombok.Data;
import
lombok.EqualsAndHashCode
;
import
java.io.Serializable
;
import
java.math.BigDecimal
;
/**
* <p>
...
...
@@ -46,6 +47,16 @@ public class GoblinSqbPerformanceGoods implements Serializable {
*/
private
Integer
sort
;
/**
* 换购价格(不设置则按商品售价售卖)
*/
private
BigDecimal
settlementPrice
;
/**
* 演出结束自动下架 0-否 1-是
*/
private
Integer
autoOffline
;
/**
* 状态 0-禁用 1-启用
*/
...
...
liquidnet-bus-service/liquidnet-service-goblin/liquidnet-service-goblin-impl/src/main/java/com/liquidnet/service/goblin/util/GoblinSqbRedisUtils.java
View file @
583f5927
package
com
.
liquidnet
.
service
.
goblin
.
util
;
import
com.fasterxml.jackson.core.type.TypeReference
;
import
com.liquidnet.service.goblin.constant.GoblinRedisConst
;
import
com.liquidnet.service.base.constant.RedisKeyExpireConst
;
import
com.liquidnet.common.cache.redis.util.RedisUtil
;
import
com.liquidnet.commons.lang.util.JsonUtils
;
import
com.liquidnet.service.goblin.dto.vo.GoblinSqbOrderVo
;
import
com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfGoodsVo
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.StringUtils
;
import
java.util.List
;
...
...
@@ -19,53 +18,35 @@ import java.util.List;
@Component
public
class
GoblinSqbRedisUtils
{
// Redis Key 前缀
private
static
final
String
KEY_SQB_ORDER
=
"goblin:sqb:order:"
;
private
static
final
String
KEY_SQB_PERF_GOODS
=
"goblin:sqb:perf:goods:"
;
private
static
final
String
KEY_SQB_ORDER_LOCK
=
"goblin:sqb:order:lock:"
;
// TTL 常量(秒)
private
static
final
long
TTL_ORDER
=
2
*
60
*
60
;
// 2h
private
static
final
long
TTL_PERF_GOODS
=
5
*
60
;
// 5min
private
static
final
long
TTL_ORDER_LOCK
=
10
;
// 10s
@Autowired
private
RedisUtil
redisUtil
;
/* ---------------------------------------- 订单操作(TTL 2h) ---------------------------------------- */
public
void
setSqbOrder
(
String
orderId
,
GoblinSqbOrderVo
vo
)
{
redisUtil
.
set
(
KEY_SQB_ORDER
.
concat
(
orderId
),
JsonUtils
.
toJson
(
vo
),
TTL_ORDER
);
redisUtil
.
set
(
GoblinRedisConst
.
SQB_ORDER
.
concat
(
orderId
),
vo
,
RedisKeyExpireConst
.
SQB_ORDER_EXPIRE
);
}
public
GoblinSqbOrderVo
getSqbOrder
(
String
orderId
)
{
String
valStr
=
(
String
)
redisUtil
.
get
(
KEY_SQB_ORDER
.
concat
(
orderId
));
if
(
StringUtils
.
isEmpty
(
valStr
))
{
return
null
;
}
return
JsonUtils
.
fromJson
(
valStr
,
GoblinSqbOrderVo
.
class
);
return
(
GoblinSqbOrderVo
)
redisUtil
.
get
(
GoblinRedisConst
.
SQB_ORDER
.
concat
(
orderId
));
}
public
void
delSqbOrder
(
String
orderId
)
{
redisUtil
.
del
(
KEY_
SQB_ORDER
.
concat
(
orderId
));
redisUtil
.
del
(
GoblinRedisConst
.
SQB_ORDER
.
concat
(
orderId
));
}
/* ---------------------------------------- 演出关联商品缓存(TTL 5min) ---------------------------------------- */
public
void
setPerfGoods
(
String
performancesId
,
List
<
GoblinSqbPerfGoodsVo
>
list
)
{
redisUtil
.
set
(
KEY_SQB_PERF_GOODS
.
concat
(
performancesId
),
JsonUtils
.
toJson
(
list
),
TTL_PERF_GOODS
);
redisUtil
.
set
(
GoblinRedisConst
.
SQB_PERFORMANCE_GOODS
.
concat
(
performancesId
),
list
,
RedisKeyExpireConst
.
SQB_PERFORMANCE_GOODS_EXPIRE
);
}
public
List
<
GoblinSqbPerfGoodsVo
>
getPerfGoods
(
String
performancesId
)
{
String
valStr
=
(
String
)
redisUtil
.
get
(
KEY_SQB_PERF_GOODS
.
concat
(
performancesId
));
if
(
StringUtils
.
isEmpty
(
valStr
))
{
return
null
;
}
return
JsonUtils
.
fromJson
(
valStr
,
new
TypeReference
<
List
<
GoblinSqbPerfGoodsVo
>>()
{});
return
(
List
<
GoblinSqbPerfGoodsVo
>)
redisUtil
.
get
(
GoblinRedisConst
.
SQB_PERFORMANCE_GOODS
.
concat
(
performancesId
));
}
public
void
delPerfGoods
(
String
performancesId
)
{
redisUtil
.
del
(
KEY_SQB_PERF
_GOODS
.
concat
(
performancesId
));
redisUtil
.
del
(
GoblinRedisConst
.
SQB_PERFORMANCE
_GOODS
.
concat
(
performancesId
));
}
/* ---------------------------------------- 下单防重锁(TTL 10s) ---------------------------------------- */
...
...
@@ -78,8 +59,8 @@ public class GoblinSqbRedisUtils {
* @return true 获取成功,false 已被锁定
*/
public
boolean
tryOrderLock
(
String
userId
,
String
skuId
)
{
String
key
=
KEY_
SQB_ORDER_LOCK
.
concat
(
userId
).
concat
(
":"
).
concat
(
skuId
);
return
redisUtil
.
lock
(
key
,
1
,
TTL_ORDER_LOCK
);
String
key
=
GoblinRedisConst
.
SQB_ORDER_LOCK
.
concat
(
userId
).
concat
(
":"
).
concat
(
skuId
);
return
redisUtil
.
lock
(
key
,
1
,
RedisKeyExpireConst
.
SQB_ORDER_LOCK_EXPIRE
);
}
/**
...
...
@@ -89,7 +70,7 @@ public class GoblinSqbRedisUtils {
* @param skuId SKU ID
*/
public
void
releaseOrderLock
(
String
userId
,
String
skuId
)
{
String
key
=
KEY_
SQB_ORDER_LOCK
.
concat
(
userId
).
concat
(
":"
).
concat
(
skuId
);
String
key
=
GoblinRedisConst
.
SQB_ORDER_LOCK
.
concat
(
userId
).
concat
(
":"
).
concat
(
skuId
);
redisUtil
.
uLock
(
key
);
}
}
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