记得上下班打卡 | git大法好,push需谨慎

Commit 6b169488 authored by 姜秀龙's avatar 姜秀龙

Merge remote-tracking branch 'refs/remotes/origin/master' into jxl_20240313_prod

# Conflicts:
#	liquidnet-bus-support/liquidnet-support-config/src/main/resources/application-dev.yml
parents e79e4e23 8836e7cf
......@@ -62,6 +62,7 @@ public class KylinRedisConst {
public static final String IDCARD_BUY_INFO = "kylin:buy:idCard:";
public static final String PERFORMANCE_ID = "performanceId";
public static final String TICKET_ID = "ticketId";
public static final String TIME_ID = "timeId";
public static final String USE_TIME = "useTime";
public static final String BUY_COUNT = "buyCount";
......
package com.liquidnet.service.kylin.constant;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* 限购对象枚举
*/
@ApiModel("限购对象枚举")
public enum LimitTargetEnum {
@ApiModelProperty("账户")
ACCOUNT(1, "账户"),
@ApiModelProperty("实名")
IDCARD(2, "实名");
private final int code;
private final String desc;
LimitTargetEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
public static LimitTargetEnum valueOf(int code) {
for (LimitTargetEnum target : values()) {
if (target.code == code) {
return target;
}
}
return null;
}
}
\ No newline at end of file
package com.liquidnet.service.kylin.constant;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* 限购类型枚举
*/
@ApiModel("限购类型枚举")
public enum LimitTypeEnum {
@ApiModelProperty("演出")
PERFORMANCE(1, "演出"),
@ApiModelProperty("票种")
TICKET(2, "票种"),
@ApiModelProperty("场次")
TIME(3, "场次");
private final int code;
private final String desc;
LimitTypeEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
public static LimitTypeEnum valueOf(int code) {
for (LimitTypeEnum type : values()) {
if (type.code == code) {
return type;
}
}
return null;
}
}
\ No newline at end of file
......@@ -33,6 +33,10 @@ public class CreateTicketTimesParam implements Serializable {
@NotNull(message = "不能为空")
private Integer type;
@ApiModelProperty(value = "是否开启实名认证限购 0关闭 1开启", example = "0")
@NotNull(message = "实名认证限购不能为空")
private Integer realNameLimit;
@ApiModelProperty(value = "", example = "")
@JsonIgnore
private String createdAt;
......
......@@ -44,6 +44,9 @@ public class PerformanceStep2Param implements Serializable,Cloneable {
@ApiModelProperty(hidden = true)
private String merchantId;
@ApiModelProperty(value = "演出类型 1音乐节 2演唱会 3小型演出 4展览 6舞台剧", example = "3")
private Integer type;
@ApiModelProperty(value = "场次数据",hidden = true)
private List<TicketTimesTicketCreatePartnerVo> ticketTimes;
......
package com.liquidnet.service.kylin.dto.vo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinOrderTicketEntitiesForOrderVo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 限购错误结果VO
*/
@ApiModel("限购错误结果VO")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class LimitErrorResultVo {
/**
* 限购类型
*/
@ApiModelProperty("限购类型:1-演出,2-票种,3-场次")
private Integer limitType;
/**
* 限购对象
*/
@ApiModelProperty("限购对象:1-账户,2-实名")
private Integer limitTarget;
/**
* 限购数量
*/
@ApiModelProperty("限购数量")
private Integer limitCount;
/**
* 当前已购买数量
*/
@ApiModelProperty("当前已购买数量")
private Integer currentCount;
/**
* 会员逻辑
*/
@ApiModelProperty("0全员 2会员专属 1会员时间段")
private Integer memberType;
/**
* 演出 id
*/
@ApiModelProperty("演出 id")
private String performancesId;
/**
* 票种 id
*/
@ApiModelProperty("票种 id")
private String ticketsId;
/**
* 场次 id
*/
@ApiModelProperty("场次 id")
private String timeId;
/**
* 身份证
*/
@ApiModelProperty("身份证")
private String idCard;
/**
* 姓名
*/
@ApiModelProperty("姓名")
private String idName;
/**
* 入场人 id
*/
@ApiModelProperty("入场人 id")
private String entersId;
/**
* 错误信息
*/
@ApiModelProperty("错误信息")
private String errorMessage;
/**
* 已购买的票信息
*/
@ApiModelProperty("已购买的票信息")
private List<KylinOrderTicketEntitiesForOrderVo> entities;
}
\ No newline at end of file
......@@ -30,6 +30,8 @@ public class KylinTicketTimesVo implements Serializable,Cloneable{
private String useStart;
@ApiModelProperty(value = "适用结束时间")
private String useEnd;
@ApiModelProperty(value = "是否开启实名认证限购 0关闭 1开启")
private Integer realNameLimit;
@ApiModelProperty(value = "票种")
private List<KylinTicketVo> ticketList;
......@@ -47,6 +49,7 @@ public class KylinTicketTimesVo implements Serializable,Cloneable{
this.ticketTimesId = ticketTimes.getTicketTimesId();
this.title = ticketTimes.getTitle();
this.type = ticketTimes.getType();
this.realNameLimit = ticketTimes.getRealNameLimit();
this.useStart = DateUtil.Formatter.yyyyMMddHHmmss.format(ticketTimes.getUseStart());
this.useEnd = DateUtil.Formatter.yyyyMMddHHmmss.format(ticketTimes.getUseEnd());
}
......@@ -57,5 +60,6 @@ public class KylinTicketTimesVo implements Serializable,Cloneable{
this.type = ticketTimes.getType();
this.useStart = ticketTimes.getUseStart();
this.useEnd = ticketTimes.getUseEnd();
this.realNameLimit = ticketTimes.getRealNameLimit();
}
}
package com.liquidnet.service.kylin.dto.vo.mongo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class KylinOrderTicketEntitiesForOrderVo implements Serializable, Cloneable {
private String orderId;
private String timeId;
@ApiModelProperty("演出名称")
private String performanceTitle;
@ApiModelProperty("票种名称")
private String ticketTitle;
@ApiModelProperty("场次开始")
private String useStart;
@ApiModelProperty("场次开始结束")
private String useEnd;
@ApiModelProperty("isPayment")
private Integer isPayment;
private static final KylinOrderTicketEntitiesForOrderVo obj = new KylinOrderTicketEntitiesForOrderVo();
public static KylinOrderTicketEntitiesForOrderVo getNew() {
try {
return (KylinOrderTicketEntitiesForOrderVo) obj.clone();
} catch (CloneNotSupportedException e) {
return new KylinOrderTicketEntitiesForOrderVo();
}
}
}
......@@ -37,6 +37,8 @@ public class KylinTicketTimesPartnerVo implements Serializable ,Cloneable{
@ApiModelProperty(value = "是否开启缺票登记")
private Integer isLackRegister;
@ApiModelProperty(value = "是否开启实名认证限购 0关闭 1开启")
private Integer realNameLimit;
@ApiModelProperty(value = "创建时间")
private String createdAt;
......@@ -61,6 +63,7 @@ public class KylinTicketTimesPartnerVo implements Serializable ,Cloneable{
this.setUseEnd(DateUtil.Formatter.yyyyMMddHHmmss.format(ticketTimes.getUseEnd()));
this.setStatus(ticketTimes.getStatus());
this.setType(ticketTimes.getType());
this.setRealNameLimit(ticketTimes.getRealNameLimit());
this.setCreatedAt(DateUtil.Formatter.yyyyMMddHHmmss.format(ticketTimes.getCreatedAt()));
this.setUpdatedAt(DateUtil.Formatter.yyyyMMddHHmmss.format(ticketTimes.getUpdatedAt()));
return this;
......
......@@ -31,6 +31,9 @@ public class TicketTimesTicketCreatePartnerVo implements Serializable ,Cloneable
@ApiModelProperty(value = "状态 1单日票 2通票")
private Integer type;
@ApiModelProperty(value = "是否开启实名认证限购 0关闭 1开启")
private Integer realNameLimit;
@ApiModelProperty(value = "创建时间")
private String createdAt;
......
package com.liquidnet.service.kylin.dto.vo.returns;
import com.liquidnet.service.kylin.dto.vo.LimitErrorResultVo;
import com.liquidnet.service.kylin.dto.vo.middle.PayDataVo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
@Data
public class PayInnerResultVo implements Serializable,Cloneable {
......@@ -18,6 +20,7 @@ public class PayInnerResultVo implements Serializable,Cloneable {
private String returnUrl;
private BigDecimal price;
private PayDataVo payData;
private List<LimitErrorResultVo> limitResult;
private static final PayInnerResultVo obj = new PayInnerResultVo();
public static PayInnerResultVo getNew() {
......
......@@ -6,6 +6,7 @@ import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.dto.param.PayAgainParam;
import com.liquidnet.service.kylin.dto.param.PayOrderParam;
import com.liquidnet.service.kylin.dto.param.SyncOrderParam;
import com.liquidnet.service.kylin.dto.vo.LimitErrorResultVo;
import com.liquidnet.service.kylin.dto.vo.returns.*;
import com.liquidnet.service.kylin.entity.KylinOrderTickets;
......@@ -73,4 +74,6 @@ public interface IKylinOrderTicketsService {
//获取 订单Ar激活码
ResponseDto<List<String>> getOrderArCode(String orderId);
ResponseDto<List<LimitErrorResultVo>> limitInfo(List<LimitErrorResultVo> param);
}
package com.liquidnet.service.sweet.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 失物招领管理员查询参数
*
* @author liquidnet
* @since 2025-01-18
*/
@Data
@ApiModel("失物招领管理员查询参数")
public class SweetLostFoundAdminParam implements Serializable {
@ApiModelProperty("主键ID 编辑填写")
@NotNull(message = "ID不能为空", groups = ValidationGroups.Update.class)
private Long id;
@ApiModelProperty("手机号")
@NotBlank(message = "手机号不能为空")
private String phone;
@ApiModelProperty("备注姓名")
private String name;
@ApiModelProperty("权限类型:1-发帖员(仅发帖,发布后不可编辑) 2-管理员(发帖、编辑、删除)")
@NotNull(message = "权限类型不能为空")
private Integer permissionType;
@ApiModelProperty("授权范围:1-本站次 2-全站")
@NotNull(message = "授权范围不能为空")
private Integer authScope;
@ApiModelProperty("演出ID")
@NotBlank(message = "演出ID不能为空")
private String performanceId;
}
\ No newline at end of file
package com.liquidnet.service.sweet.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 失物招领信息查询参数
*
* @author liquidnet
* @since 2025-01-18
*/
@Data
@ApiModel("失物招领信息查询参数")
public class SweetLostFoundItemParam implements Serializable {
@ApiModelProperty("主键ID 编辑填写")
@NotNull(message = "ID不能为空", groups = ValidationGroups.Update.class)
private Long id;
@ApiModelProperty("演出ID")
@NotBlank(message = "演出ID不能为空")
private String performanceId;
@ApiModelProperty("物品类型:1-证件卡类 2-3C数码类 3-服饰类 4-其他")
@NotNull(message = "物品类型不能为空")
private Integer itemType;
@ApiModelProperty("拾捡地:1-音乐节现场 2-其他")
@NotNull(message = "拾捡地不能为空")
private Integer pickupLocation;
@ApiModelProperty("捡拾日期")
@NotBlank(message = "捡拾日期不能为空")
private String pickupDate;
@ApiModelProperty("物品描述,最多120字")
@NotBlank(message = "物品描述不能为空")
private String description;
@ApiModelProperty("物品图片URL")
@NotBlank(message = "物品图片URL不能为空")
private String itemImage;
@ApiModelProperty("发布人uid")
@NotBlank(message = "发布人uid不能为空")
private String publisherUid;
}
\ No newline at end of file
package com.liquidnet.service.sweet.param;
import javax.validation.groups.Default;
/**
* <p>
* xx 服务实现类
* </p>
*
* @author jiangxiulong
* @since 2025-08-20 13:13
*/
public class ValidationGroups {
public interface Create extends Default {}
public interface Update extends Default {}
public interface Delete extends Default {}
public interface Query extends Default {}
}
package com.liquidnet.service.sweet.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.sweet.entity.SweetLostFoundAdmin;
import com.liquidnet.service.sweet.param.SweetLostFoundAdminParam;
import com.liquidnet.service.sweet.vo.SweetLostFoundAdminVo;
import java.util.List;
/**
* 失物招领管理员服务接口
*
* @author liquidnet
* @since 2025-01-18
*/
public interface ISweetLostFoundAdminService extends IService<SweetLostFoundAdmin> {
/**
* 添加管理员
*
* @param admin 管理员信息
* @return 是否成功
*/
ResponseDto<Boolean> addAdmin(SweetLostFoundAdminParam admin);
/**
* 编辑管理员
*
* @param admin 管理员信息
* @return 是否成功
*/
ResponseDto<Boolean> editAdmin(SweetLostFoundAdminParam admin);
/**
* 删除管理员
*
* @param id 管理员ID
* @return 是否成功
*/
boolean deleteAdmin(Long id);
/**
* 获取管理员详情
*
* @param id 管理员ID
* @return 管理员详情
*/
SweetLostFoundAdminVo getAdminDetail(Long id);
/**
* 分页查询管理员列表
*
* @param performanceId 查询参数
* @return 分页结果
*/
List<SweetLostFoundAdminVo> getAdminList(String performanceId);
/**
* 检查是否有管理员权限
*
* @param phone 手机号
* @param performanceId 演出ID
* @return 权限详情信息
*/
SweetLostFoundAdminVo hasPermission(String phone, String performanceId);
}
\ No newline at end of file
package com.liquidnet.service.sweet.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.liquidnet.service.sweet.entity.SweetLostFoundItem;
import com.liquidnet.service.sweet.param.SweetLostFoundItemParam;
import com.liquidnet.service.sweet.vo.SweetLostFoundItemVo;
import java.util.List;
/**
* 失物招领信息服务接口
*
* @author liquidnet
* @since 2025-01-18
*/
public interface ISweetLostFoundItemService extends IService<SweetLostFoundItem> {
/**
* 发布失物信息
*
* @param item 失物信息
* @return 是否成功
*/
boolean publishItem(SweetLostFoundItemParam item);
/**
* 编辑失物信息
*
* @param item 失物信息
* @return 是否成功
*/
boolean editItem(SweetLostFoundItemParam item);
/**
* 删除失物信息
*
* @param id 物品ID
* @return 是否成功
*/
boolean deleteItem(Long id);
/**
* 获取失物信息详情
*
* @param id 物品ID
* @return 失物信息详情
*/
SweetLostFoundItemVo getItemDetail(Long id);
/**
* 根据演出ID查询失物信息列表
*
* @param itemType 演出ID
* @param performanceId 演出ID
* @return 失物信息列表
*/
List<SweetLostFoundItemVo> getItemList(Integer itemType, String performanceId);
}
\ No newline at end of file
package com.liquidnet.service.sweet.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 失物招领信息返回VO
*
* @author liquidnet
* @since 2025-01-18
*/
@Data
@ApiModel("失物招领信息返回")
public class SweetLostFoundItemVo {
@ApiModelProperty("主键ID")
private Long id;
@ApiModelProperty("失物信息ID")
private String itemId;
@ApiModelProperty("物品图片URL")
private String itemImage;
@ApiModelProperty("物品描述,最多120字")
private String description;
@ApiModelProperty("拾捡地:1-音乐节现场 2-其他")
private Integer pickupLocation;
@ApiModelProperty("捡拾日期")
private String pickupDate;
@ApiModelProperty("物品类型:1-证件卡类 2-3C数码类 3-服饰类 4-其他")
private Integer itemType;
@ApiModelProperty("演出ID")
private String performanceId;
@ApiModelProperty("发布人uid")
private String publisherUid;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}
\ No newline at end of file
......@@ -47,6 +47,10 @@
<div class="tab-content">
<div id="tab-1" class="tab-pane">
<div class="panel-body">
<!-- 导出按钮 -->
<div class="m-t-md" style="text-align: left; margin-bottom: 2px">
<button type="button" class="btn btn-primary" onclick="exportTableData()">导出数据</button>
</div>
<div id="tab-1" class="tab-pane">
<iframe id="tab_iframe_1" name="tab_iframe_1" marginwidth=0 marginheight=0 width=100%
height=800px frameborder=0></iframe>
......@@ -113,6 +117,14 @@
<label>演出实名限购:</label>
<span th:text="*{idCount}"></span>
</div>
<div class="panel-footer">
<label>场次实名限购:</label>
<span th:each="dict, iterStat : ${kylinPerformanceMisVo.ticketTimes}"
th:if="${dict.realNameLimit == 1}"
th:text="${#strings.replace(#strings.replace(dict.title, ' 00:00', ''), ' 00:00', '')} + ${iterStat.last ? '' : '; '}">
</span>
<span th:if="${#lists.isEmpty(kylinPerformanceMisVo.ticketTimes.?[realNameLimit == 1])}"></span>
</div>
<div class="panel-footer">
<label>时间:</label>
<span th:text="*{timeStart}"></span>
......@@ -575,6 +587,15 @@
anim: 5 //0-6的选择,指定弹出图片动画类型,默认随机(请注意,3.0之前的版本用shift参数)
});
}
/**
* 导出文件
*/
function exportTableData() {
var performancesId = '[[${kylinPerformanceMisVo.performancesId}]]'.replaceAll("\"", "")
var url = prefix + '/performance/export?performanceId=' + performancesId;
window.location.href = url; // 直接触发下载
}
</script>
</body>
</html>
......@@ -53,12 +53,12 @@
<div th:text="*{totalBuyUsers}">39</div>
</div>
</div>
<div class="col-lg-1">
<div>
<div>小家伙分销(元)</div>
<div th:text="*{totalDisPrice}">0</div>
</div>
</div>
<!-- <div class="col-lg-1">-->
<!-- <div>-->
<!-- <div>小家伙分销(元)</div>-->
<!-- <div th:text="*{totalDisPrice}">0</div>-->
<!-- </div>-->
<!-- </div>-->
<div class="col-lg-1">
<div>
<div>退票数量(张)</div>
......@@ -71,66 +71,75 @@
<thead>
<tr>
<th>
<div class="cell">票种名</div>
<div class="cell">场次</div>
</th>
<th>
<div class="cell">单价</div>
<div class="cell">票种类型</div>
</th>
<th>
<div class="cell">类型</div>
<div class="cell">票种名称</div>
</th>
<th>
<div class="cell">适用时间</div>
<div class="cell">票种价格</div>
</th>
<th>
<div class="cell">销售总数量</div>
<div class="cell">库存数量</div>
</th>
<th>
<div class="cell">会员销售数量</div>
<div class="cell">销售数量</div>
</th>
<th>
<div class="cell">库存数量</div>
<div class="cell">余票数量</div>
</th>
<th>
<div class="cell">登登登VIP购票数量</div>
</th>
<th>
<div class="cell">正在支付数量</div>
</th>
<th>
<div class="cell">退票数量</div>
<div class="cell">退票总数量</div>
</th>
<th>
<div class="cell">全额退票数量</div>
</th>
<th>
<div class="cell">手续费退票数量</div>
</th>
<th>
<div class="cell">羊毛券数量</div>
<div class="cell">退票手续费收益</div>
</th>
<th>
<div class="cell">销售额(元)</div>
<div class="cell">票面销售金额</div>
</th>
<!-- <th>-->
<!-- <div class="cell">兑换数量</div>-->
<!-- </th>-->
</tr>
</thead>
<tbody>
<tr th:each="respBean,respBeanStat:${perOrderStaticList}">
<td>
<div class="cell" th:text="${respBean.title}">180元区</div>
<div class="cell" th:text="${respBean.timeTitle}">180元区</div>
</td>
<td>
<div class="cell" th:text="${respBean.price}">180.00</div>
<div class="cell" th:text="${@dict.getLabel('zhengzai_ticket_type',respBean.type)}">0</div>
</td>
<td>
<div class="cell" th:text="${@dict.getLabel('zhengzai_ticket_type',respBean.type)}">0</div>
<div class="cell" th:text="${respBean.title}">0</div>
</td>
<td>
<div class="cell" >[[${respBean.useStart}]] - [[${respBean.useEnd}]]</div>
<div class="cell" th:text="${respBean.price}">0</div>
</td>
<td>
<div class="cell" th:text="${respBean.saleGeneral}">0</div>
<div class="cell" th:text="${respBean.totalGeneral}">0</div>
</td>
<td>
<div class="cell" th:text="${respBean.totalMemberNumber}">0</div>
<div class="cell" th:text="${respBean.saleGeneral}">0</div>
</td>
<td>
<div class="cell" th:text="${respBean.surplusGeneral}">0</div>
</td>
<td>
<div class="cell" th:text="${respBean.vipBuyTotal}">0</div>
</td>
<td>
<div class="cell" th:text="${respBean.totalPayingNumber}">0</div>
</td>
......@@ -138,16 +147,40 @@
<div class="cell" th:text="${respBean.totalRefundGeneral}">0</div>
</td>
<td>
<div class="cell" th:text="${respBean.totalVoucherCount}">0</div>
<div class="cell" th:text="${respBean.fullRefundTicketTotal}">0</div>
</td>
<td>
<div class="cell" th:text="${respBean.handlingFeeRefundTicketTotal}">0</div>
</td>
<td>
<div class="cell" th:text="${respBean.refundFeeRevenueTotal}">0</div>
</td>
<td>
<div class="cell" th:text="${respBean.totalSalePrice}">0</div>
<div class="cell" th:text="${respBean.audienceSalesAmountTotal}">0</div>
</td>
<!-- <td>-->
<!-- <div class="cell" th:text="${respBean.totalExchange}">0</div>-->
<!-- </td>-->
</tr>
</tbody>
<tfoot>
<tr th:object="${sumResp}">
<td><div class="cell">总计</div></td>
<td><div class="cell"></div></td>
<td><div class="cell"></div></td>
<td><div class="cell"></div></td>
<td><div class="cell" th:text="*{totalGeneralSum}">0</div></td>
<td><div class="cell" th:text="*{saleGeneralSum}">0</div></td>
<td><div class="cell" th:text="*{surplusGeneralSum}">0</div></td>
<td><div class="cell" th:text="*{vipBuyTotalSum}">0</div></td>
<td><div class="cell" th:text="*{totalPayingNumberSum}">0</div></td>
<td><div class="cell" th:text="*{totalRefundGeneralSum}">0</div></td>
<td><div class="cell" th:text="*{fullRefundTicketTotalSum}">0</div></td>
<td><div class="cell" th:text="*{handlingFeeRefundTicketTotalSum}">0</div></td>
<td><div class="cell" th:text="*{refundFeeRevenueTotalSum}">0</div></td>
<td><div class="cell" th:text="*{audienceSalesAmountTotalSum}">0</div></td>
</tr>
</tfoot>
</table>
<div style="display: none;">
<button type="button" class="el-button main el-button--primary el-button--medium"><!---->
......
package com.liquidnet.client.admin.zhengzai.kylin.dto;
import lombok.Data;
@Data
public class OpenDataBaseResponse<T> {
private Integer code;
private String msg;
private T data;
public boolean isSucc(){
return this.code != null && this.code == 0;
}
}
package com.liquidnet.client.admin.zhengzai.kylin.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
public class OpenDataSalesResponse extends OpenDataBaseResponse<List<PerformanceSalesDto>>{
}
package com.liquidnet.client.admin.zhengzai.kylin.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
public class OpenDataTicketSalesResponse extends OpenDataBaseResponse<PerformanceTicketSalesDto>{
}
package com.liquidnet.client.admin.zhengzai.kylin.dto;
import lombok.Data;
@Data
public class PerformanceSalesDto {
/**
* 演出ID
*/
private String performanceId;
/**
* 总库存
*/
private Integer totalGeneral;
/**
* 观众购票数
*/
private Integer audienceTicketTotal;
/**
* 剩余库存
*/
private Integer surplusGeneral;
/**
* 总销售额
*/
private String salesAmountTotal;
}
package com.liquidnet.client.admin.zhengzai.kylin.dto;
import lombok.Data;
import java.util.List;
@Data
public class PerformanceTicketSalesDto {
/**
* 演出ID
*/
private String performanceId;
/**
* 演出名称
*/
private String performanceTitle;
/**
* 总销售票款(元)
*/
private String fullSalesAmountTotal;
/**
* 观众购票数
*/
private String fullAudienceTicketTotal;
/**
* 总库存
*/
private String fullTotalGeneral;
/**
* 退票数量(张)
*/
private String fullRefundTicketTotal;
/**
* 购买人数
*/
private String fullBuyTotal;
/**
* 票种销售数据
*/
private List<TicketSales> fullTicketDataList;
@Data
public static class TicketSales {
// 票ID
private String ticketId;
// 场次ID
private String timeId;
// 场次名称
private String timeTitle;
// 票种名称
private String ticketTitle;
// 票种金额
private String ticketPrice;
// 销售总金额
private String salesAmountTotal;
// 退票手续费总收益
private String refundFeeRevenueTotal;
// 观众购票总数[销售总票量-兑换码票总数] 销售数量
private String audienceTicketTotal;
// 观众购票销售总金额[票种金额* 观众购票总数] 票面销售金额
private String audienceSalesAmountTotal;
// 全额退票总数
private Integer fullRefundTicketTotal;
// 手续费退票总数
private Integer handlingFeeRefundTicketTotal;
// 退票总数量
private String refundTicketTotal;
// 票种类型 1:单日票 2:通票
private Integer ticketType;
// 库存数量
private String totalGeneral;
// 登登登VIP购买数量
private Integer vipBuyTotal;
// 正在支付数量
private String payingTotal;
// 剩余库存
private String surplusGeneral;
}
}
package com.liquidnet.client.admin.zhengzai.kylin.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class PerformanceTicketSumDto {
// 库存数量
private BigDecimal totalGeneralSum = BigDecimal.ZERO;
// 销售数量
private BigDecimal saleGeneralSum = BigDecimal.ZERO;
// 余票数量
private BigDecimal surplusGeneralSum = BigDecimal.ZERO;
//VIP购票数量
private BigDecimal vipBuyTotalSum = BigDecimal.ZERO;
//正在支付数量
private BigDecimal totalPayingNumberSum = BigDecimal.ZERO;
//退票总数量
private BigDecimal totalRefundGeneralSum = BigDecimal.ZERO;
//全额退票数量
private BigDecimal fullRefundTicketTotalSum = BigDecimal.ZERO;
//手续费退票数量
private BigDecimal handlingFeeRefundTicketTotalSum = BigDecimal.ZERO;
//退票手续费收益
private BigDecimal refundFeeRevenueTotalSum = BigDecimal.ZERO;
//票面销售金额
private BigDecimal audienceSalesAmountTotalSum = BigDecimal.ZERO;
}
package com.liquidnet.client.admin.zhengzai.kylin.service;
import com.liquidnet.client.admin.zhengzai.kylin.dto.PerformanceSalesDto;
import com.liquidnet.client.admin.zhengzai.kylin.dto.PerformanceTicketSalesDto;
import java.util.List;
/**
* 数据查询服务
*/
public interface IOpenDataService {
/**
* 获取演出销售数据
* @param performanceIdList
* @return
*/
List<PerformanceSalesDto> getPerformanceSalesInfo(List<String> performanceIdList);
/**
* 获取演出票销售数据
* @param performanceId
* @return
*/
PerformanceTicketSalesDto getPerformanceTicketSalesInfo(String performanceId);
}
......@@ -7,14 +7,14 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.liquidnet.client.admin.common.utils.StringUtils;
import com.liquidnet.client.admin.zhengzai.kylin.dto.PerformanceSalesDto;
import com.liquidnet.client.admin.zhengzai.kylin.service.IOpenDataService;
import com.liquidnet.client.admin.zhengzai.kylin.service.InnerService;
import com.liquidnet.client.admin.zhengzai.kylin.utils.DataUtils;
import com.liquidnet.client.admin.zhengzai.kylin.utils.PerformanceVoUtils;
import com.liquidnet.client.admin.zhengzai.slime.service.ISlimeAuthorizationRecordsAdminService;
import com.liquidnet.client.admin.zhengzai.smile.utils.SmileRedisUtils;
import com.liquidnet.commons.lang.util.BeanUtil;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.goblin.dto.vo.SmileAgentVo;
import com.liquidnet.service.kylin.constant.KylinRedisConst;
......@@ -104,6 +104,10 @@ public class KylinPerformancesAdminServiceImpl extends ServiceImpl<KylinPerforma
@Autowired
KylinPerformancesMapper kylinPerformancesMapper;
@Autowired
private IOpenDataService openDataService;
@Override
public void test() {
// //同步演出
......@@ -293,8 +297,31 @@ public class KylinPerformancesAdminServiceImpl extends ServiceImpl<KylinPerforma
List<PerformanceAdminListDao> newList = new ArrayList();
try {
Map<String, Object> map = BeanUtil.convertBeanToMap(performanceAdminListParam);
List<PerformanceAdminListDao> voList = performancesMapper.misPerformanceList(map);
List<PerformanceAdminListDao> voList = performancesMapper.misPerformanceListV2(map);
List<String> performanceIdList = voList.stream().map(PerformanceAdminListDao::getPerformancesId)
.collect(Collectors.toList());
Map<String, PerformanceSalesDto> salesDtoMap = new HashMap<>();
if (!performanceIdList.isEmpty()) {
// 获取演出销售数据
List<PerformanceSalesDto> performanceSalesInfoList = openDataService.getPerformanceSalesInfo(performanceIdList);
if (!performanceSalesInfoList.isEmpty()) {
salesDtoMap = performanceSalesInfoList.stream()
.collect(Collectors.toMap(
PerformanceSalesDto::getPerformanceId,
performanceSalesDto -> performanceSalesDto
));
}
}
for (PerformanceAdminListDao item : voList) {
// 修改售卖数据
PerformanceSalesDto performanceSalesDto = salesDtoMap.get(item.getPerformancesId());
if (performanceSalesDto != null) {
item.setTotalGeneral(performanceSalesDto.getTotalGeneral());
item.setTotalSalePrice(new BigDecimal(performanceSalesDto.getSalesAmountTotal()));
item.setSaleGeneral(performanceSalesDto.getAudienceTicketTotal());
item.setSurplusGeneral(performanceSalesDto.getSurplusGeneral());
}
if (item.getTimeSell() == null || item.getTimeStop() == null) {
continue;
}
......
......@@ -484,23 +484,6 @@ public class KylinRefundsStatusServiceImpl {
continue;
} else {
//未退款入场人数量为0才退优先卷
List<KylinOrderTicketEntities> kylinOrderTicketEntities = kylinOrderTicketEntitiesMapper.selectList(
Wrappers.lambdaQuery(KylinOrderTicketEntities.class).eq(KylinOrderTicketEntities::getOrderId, refund.getOrderTicketsId()).eq(KylinOrderTicketEntities::getIsPayment, 1));
log.info("admin退款请求未退款入场人数量number={}",kylinOrderTicketEntities.size());
if(kylinOrderTicketEntities.size()==0){
//获取订单详情
KylinOrderTicketVo orderTicketVo = dataUtils.getOrderTicketVo(refund.getOrderTicketsId());
//退优先卷
ArrayList<KylinOrderCoupons> orderCoupons = dataUtils.getOrderCoupon(refund.getOrderTicketsId());
if (orderCoupons.size() > 0) {
for (KylinOrderCoupons item : orderCoupons) {
if (item.getCouponType() == 101) {
dataUtils.backCoupon(item.getCouponCode(), orderTicketVo.getUserId());
}
}
}
}
// 同步大麦 票务平台
KylinOrderTicketVo orderData = dataUtils.getOrderTicketVo(refund.getOrderTicketsId());
KylinPerformanceVo vo = dataUtils.getPerformanceVo(orderData.getPerformanceId());
......
package com.liquidnet.client.admin.zhengzai.kylin.service.impl;
import com.liquidnet.client.admin.zhengzai.kylin.dto.OpenDataSalesResponse;
import com.liquidnet.client.admin.zhengzai.kylin.dto.OpenDataTicketSalesResponse;
import com.liquidnet.client.admin.zhengzai.kylin.dto.PerformanceSalesDto;
import com.liquidnet.client.admin.zhengzai.kylin.dto.PerformanceTicketSalesDto;
import com.liquidnet.client.admin.zhengzai.kylin.service.IOpenDataService;
import com.liquidnet.commons.lang.util.HttpUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.commons.lang.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@Slf4j
@Service
public class OpenDataServiceImpl implements IOpenDataService {
@Value("${liquidnet.openData.host}")
private String openDataHost;
@Value("${liquidnet.openData.auth}")
private String openDataAuth;
@Override
public List<PerformanceSalesDto> getPerformanceSalesInfo(List<String> performanceIdList) {
HashMap<String, List<String>> map = new HashMap<>();
map.put("performanceIds", performanceIdList);
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, openDataAuth);
try {
String postJson = HttpUtil.postJson(openDataHost + "/api/performance/sales", JsonUtils.toJson(map), headers);
log.info("response: {}", postJson);
if (StringUtil.isBlank(postJson)) {
return Collections.emptyList();
}
OpenDataSalesResponse openDataSalesResponse = JsonUtils.fromJson(postJson, OpenDataSalesResponse.class);
if (!openDataSalesResponse.isSucc()) {
return Collections.emptyList();
}
return openDataSalesResponse.getData();
} catch (Exception e) {
log.error("error", e);
}
return Collections.emptyList();
}
@Override
public PerformanceTicketSalesDto getPerformanceTicketSalesInfo(String performanceId) {
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, openDataAuth);
try {
String responseStr = HttpUtil.getByUri(openDataHost + "/api/performance/ticket/sales?performanceId=" + performanceId, headers);
log.info("response: {}", responseStr);
if (StringUtil.isBlank(responseStr)) {
return null;
}
OpenDataTicketSalesResponse openDataSalesResponse = JsonUtils.fromJson(responseStr, OpenDataTicketSalesResponse.class);
if (!openDataSalesResponse.isSucc()) {
return null;
}
return openDataSalesResponse.getData();
} catch (Exception e) {
log.error("error", e);
}
return null;
}
}
package com.liquidnet.client.admin.zhengzai.kylin.utils;
import com.liquidnet.client.admin.zhengzai.kylin.dto.PerformanceTicketSumDto;
import com.liquidnet.service.kylin.dao.PerformanceOrderStatisticalDao;
import java.math.BigDecimal;
import java.util.List;
public class DataSumUtils {
public static PerformanceTicketSumDto sumStatistics(List<PerformanceOrderStatisticalDao> list) {
// 初始化所有需要统计的字段(BigDecimal类型)
BigDecimal totalGeneralSum = BigDecimal.ZERO;
BigDecimal saleGeneralSum = BigDecimal.ZERO;
BigDecimal surplusGeneralSum = BigDecimal.ZERO;
BigDecimal vipBuyTotalSum = BigDecimal.ZERO;
BigDecimal totalPayingNumberSum = BigDecimal.ZERO;
BigDecimal totalRefundGeneralSum = BigDecimal.ZERO;
BigDecimal fullRefundTicketTotalSum = BigDecimal.ZERO;
BigDecimal handlingFeeRefundTicketTotalSum = BigDecimal.ZERO;
BigDecimal refundFeeRevenueTotalSum = BigDecimal.ZERO;
BigDecimal audienceSalesAmountTotalSum = BigDecimal.ZERO;
// 遍历列表进行累加
for (PerformanceOrderStatisticalDao item : list) {
// BigDecimal类型字段
totalGeneralSum = safeAdd(totalGeneralSum, item.getTotalGeneral());
saleGeneralSum = safeAdd(saleGeneralSum, item.getSaleGeneral());
surplusGeneralSum = safeAdd(surplusGeneralSum, item.getSurplusGeneral());
totalPayingNumberSum = safeAdd(totalPayingNumberSum, item.getTotalPayingNumber());
totalRefundGeneralSum = safeAdd(totalRefundGeneralSum, item.getTotalRefundGeneral());
refundFeeRevenueTotalSum = safeAdd(refundFeeRevenueTotalSum, item.getRefundFeeRevenueTotal());
audienceSalesAmountTotalSum = safeAdd(audienceSalesAmountTotalSum, item.getAudienceSalesAmountTotal());
// Integer类型字段转换
vipBuyTotalSum = safeAdd(vipBuyTotalSum, BigDecimal.valueOf(item.getVipBuyTotal()));
fullRefundTicketTotalSum = safeAdd(fullRefundTicketTotalSum, BigDecimal.valueOf(item.getFullRefundTicketTotal()));
handlingFeeRefundTicketTotalSum = safeAdd(handlingFeeRefundTicketTotalSum,
BigDecimal.valueOf(item.getHandlingFeeRefundTicketTotal()));
}
PerformanceTicketSumDto sumDto = new PerformanceTicketSumDto();
sumDto.setTotalGeneralSum(totalGeneralSum); // 库存数量
sumDto.setSaleGeneralSum(saleGeneralSum); // 销售数量
sumDto.setSurplusGeneralSum(surplusGeneralSum); // 余票数量
sumDto.setVipBuyTotalSum(vipBuyTotalSum);//VIP购票数量
sumDto.setTotalPayingNumberSum(totalPayingNumberSum);//正在支付数量
sumDto.setTotalRefundGeneralSum(totalRefundGeneralSum);//退票总数量
sumDto.setFullRefundTicketTotalSum(fullRefundTicketTotalSum);//全额退票数量
sumDto.setHandlingFeeRefundTicketTotalSum(handlingFeeRefundTicketTotalSum);//手续费退票数量
sumDto.setRefundFeeRevenueTotalSum(refundFeeRevenueTotalSum);//退票手续费收益
sumDto.setAudienceSalesAmountTotalSum(audienceSalesAmountTotalSum);//票面销售金额
return sumDto;
}
// 安全的BigDecimal加法(处理null值)
private static BigDecimal safeAdd(BigDecimal sum, BigDecimal value) {
if (value == null) {
return sum;
}
return sum.add(value);
}
}
......@@ -245,5 +245,10 @@ liquidnet:
erp:
wdt:
url: https://sandbox.wangdian.cn/openapi2/
alipay:
applet:
appId: appId
pubKey: pubKey
privateKey: xxxx
#application-dev-end
\ No newline at end of file
......@@ -22,5 +22,8 @@ liquidnet:
mongodb:
sslEnabled: false
database: dev_ln_scene
openData:
host: http://localhost:8091
auth: t-gI1wT4kM4qF2bB4mJ4zQ1gM6cU6dC9uB
# end-dev-这里是配置信息基本值
\ No newline at end of file
......@@ -22,5 +22,8 @@ liquidnet:
mongodb:
sslEnabled: false
database: test_ln_scene
openData:
host: https://testopen.zhengzai.tv
auth: t-gI1wT4kM4qF2bB4mJ4zQ1gM6cU6dC9uB
# end-test-这里是配置信息基本值
\ No newline at end of file
......@@ -3,7 +3,6 @@ package com.liquidnet.service.kylin.dao;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
......@@ -18,23 +17,46 @@ import java.time.LocalDateTime;
public class PerformanceOrderStatisticalDao implements Cloneable{
private String performancesId;
private String ticketsId;
private String title;
private BigDecimal price;
private Integer type;
private String title;// 票种名称
private BigDecimal price;// 票种价格
private Integer type;// 票种类型
private String useStart;
private String useEnd;
private BigDecimal totalGeneral = BigDecimal.ZERO;
private BigDecimal saleGeneral = BigDecimal.ZERO;
private BigDecimal surplusGeneral = BigDecimal.ZERO;
private BigDecimal totalGeneral = BigDecimal.ZERO;// 库存数量
private BigDecimal saleGeneral = BigDecimal.ZERO;// 销售数量
private BigDecimal surplusGeneral = BigDecimal.ZERO; // 余票数量
private BigDecimal totalSalePrice = BigDecimal.ZERO;
private BigDecimal totalExchange = BigDecimal.ZERO;
private BigDecimal totalRefundGeneral = BigDecimal.ZERO;
private BigDecimal totalRefundGeneral = BigDecimal.ZERO; // 退票总数量
private BigDecimal totalRefundPrice = BigDecimal.ZERO;
private BigDecimal totalMemberNumber = BigDecimal.ZERO;
private BigDecimal totalPayingNumber = BigDecimal.ZERO;
private BigDecimal totalPayingNumber = BigDecimal.ZERO;// 正在支付数量
private BigDecimal totalBuyUsers = BigDecimal.ZERO;
private BigDecimal totalVoucherCount = BigDecimal.ZERO;
// 场次ID
private String timeId;
// 场次名称
private String timeTitle;
// vip购票数量
private Integer vipBuyTotal = 0;
// 全额退票总数
private Integer fullRefundTicketTotal = 0;
// 手续费退票总数
private Integer handlingFeeRefundTicketTotal = 0;
// 退票手续费总收益
private BigDecimal refundFeeRevenueTotal = BigDecimal.ZERO;
// 票面销售金额
private BigDecimal audienceSalesAmountTotal = BigDecimal.ZERO;
private static final PerformanceOrderStatisticalDao obj = new PerformanceOrderStatisticalDao();
public static PerformanceOrderStatisticalDao getNew() {
try {
......
......@@ -69,6 +69,11 @@ public class KylinTicketTimes implements Serializable ,Cloneable {
*/
private LocalDateTime updatedAt;
/**
* 是否开启实名认证限购 0关闭 1开启
*/
private Integer realNameLimit;
private static final KylinTicketTimes obj = new KylinTicketTimes();
public static KylinTicketTimes getNew() {
try {
......@@ -82,7 +87,8 @@ public class KylinTicketTimes implements Serializable ,Cloneable {
return new Object[]{
vo.getTicketTimesId(),vo.getTitle(),vo.getStatus(),
vo.getType(),vo.getUseStart(),vo.getUseEnd(),
vo.getComment(),vo.getCreatedAt(),vo.getUpdatedAt()
vo.getComment(),vo.getCreatedAt(),vo.getUpdatedAt(),
vo.getRealNameLimit()
};
}
}
......@@ -28,6 +28,8 @@ public interface KylinPerformancesMapper extends BaseMapper<KylinPerformances> {
//列表
List<PerformanceAdminListDao> misPerformanceList(Map<String,Object> map);
List<PerformanceAdminListDao> misPerformanceListV2(Map<String,Object> map);
//根据巡演查询 通过审核演出列表
List<PerformanceTitleDao> misTitleByRoadShowIdList(String roadShowId);
......
......@@ -376,6 +376,74 @@
ORDER BY ${orderItem} ${orderSc}
</if>
</select>
<select id="misPerformanceListV2" parameterType="java.util.Map" resultMap="misPerformanceListResult">
SELECT
p.performances_id ,
p.sponsor,
p.audit_time,
p.sort,
p.title ,
p.type,
p.time_start ,
p.time_end ,
ps.sync_damai ,
t.time_sell,
t.time_stop,
ps.`status` ,
ps.audit_status ,
ps.field_audit_status,
p.reject_txt ,
p.created_at
FROM
kylin_performances AS p
LEFT JOIN kylin_performance_status AS ps ON p.performances_id = ps.performance_id
LEFT JOIN(
SELECT
ttr.performance_id ,
MIN(
DATE_SUB(
t.time_start ,
INTERVAL pay_countdown_minute MINUTE
)
) AS 'time_sell' ,
MAX(t.time_end) AS 'time_stop'
FROM
kylin_ticket_status AS ts
LEFT JOIN kylin_ticket_relations AS tr ON tr.ticket_id = ts.ticket_id
LEFT JOIN kylin_tickets AS t ON t.tickets_id = ts.ticket_id
LEFT JOIN kylin_ticket_time_relation AS ttr ON tr.times_id = ttr.times_id
GROUP BY
ttr.performance_id
) AS t ON p.performances_id = t.performance_id
<where>
<if test="title!=''">
AND title LIKE concat('%', #{title}, '%')
</if>
<if test="cityName!=''">
AND city_name LIKE concat('%', #{cityName}, '%')
</if>
<if test="status!='-2'">
AND ps.STATUS = #{status}
</if>
<if test="status=='-2'">
AND (ps.STATUS >= 3 or ps.STATUS = 1)
</if>
<if test="auditStatus!='-2'">
AND ps.audit_status = #{auditStatus}
</if>
<!-- <if test="auditStatus=='-2'">-->
<!-- AND (ps.audit_status = 0 or ps.audit_status = 1 or ps.audit_status = 2)-->
<!-- </if>-->
<if test="stopSellDay!=-2">
AND p.time_end BETWEEN #{stopSellTime} AND NOW()
</if>
</where>
<if test="orderItem!=''">
ORDER BY ${orderItem} ${orderSc}
</if>
</select>
<!-- Mis 根据巡演查询演出列表 -->
<select id="misTitleByRoadShowIdList" parameterType="java.lang.String" resultMap="performanceTitleDaoResult">
SELECT performances_id,
......
package com.liquidnet.service.sweet.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* 失物招领管理员实体类
*
* @author liquidnet
* @since 2025-01-18
*/
@ApiModel("失物招领管理员")
@Data
@EqualsAndHashCode(callSuper = false)
public class SweetLostFoundAdmin implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("管理员ID")
private String adminId;
@ApiModelProperty("手机号")
private String phone;
@ApiModelProperty("备注姓名")
private String name;
@ApiModelProperty("权限类型:1-发帖员(仅发帖,发布后不可编辑) 2-管理员(发帖、编辑、删除)")
private Integer permissionType;
@ApiModelProperty("授权范围:1-本站次 2-全站")
private Integer authScope;
@ApiModelProperty("演出ID")
private String performanceId;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("更新时间")
private Date updateTime;
@ApiModelProperty("是否删除:0-未删除 1-已删除")
private Integer isDeleted;
private static final SweetLostFoundAdmin obj = new SweetLostFoundAdmin();
public static SweetLostFoundAdmin getNew() {
try {
return (SweetLostFoundAdmin) obj.clone();
} catch (CloneNotSupportedException e) {
return new SweetLostFoundAdmin();
}
}
// 权限类型枚举
public enum PermissionType {
POSTER(1, "发帖员"),
ADMIN(2, "管理员");
private final int code;
private final String desc;
PermissionType(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
// 授权范围枚举
public enum AuthScope {
CURRENT_EVENT(1, "本站次"),
ALL_EVENTS(2, "全站");
private final int code;
private final String desc;
AuthScope(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
}
\ No newline at end of file
package com.liquidnet.service.sweet.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* 失物招领信息实体类
*
* @author liquidnet
* @since 2025-01-18
*/
@ApiModel("失物招领信息")
@Data
@EqualsAndHashCode(callSuper = false)
public class SweetLostFoundItem implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("失物信息ID")
private String itemId;
@ApiModelProperty("物品图片URL")
private String itemImage;
@ApiModelProperty("物品描述,最多120字")
private String description;
@ApiModelProperty("拾捡地:1-音乐节现场 2-其他")
private Integer pickupLocation;
@ApiModelProperty("捡拾日期")
private String pickupDate;
@ApiModelProperty("物品类型:1-证件卡类 2-3C数码类 3-服饰类 4-其他")
private Integer itemType;
@ApiModelProperty("演出ID")
private String performanceId;
@ApiModelProperty("发布人uid")
private String publisherUid;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("更新时间")
private Date updateTime;
@ApiModelProperty("是否删除:0-未删除 1-已删除")
private Integer isDeleted;
private static final SweetLostFoundItem obj = new SweetLostFoundItem();
public static SweetLostFoundItem getNew() {
try {
return (SweetLostFoundItem) obj.clone();
} catch (CloneNotSupportedException e) {
return new SweetLostFoundItem();
}
}
// 拾捡地枚举
public enum PickupLocation {
FESTIVAL_SITE(1, "音乐节现场"),
OTHER_PLACE(2, "其他");
private final int code;
private final String desc;
PickupLocation(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
// 物品类型枚举
public enum ItemType {
DOCUMENT_CARD(1, "证件卡类"),
DIGITAL_DEVICE(2, "3C数码类"),
CLOTHING(3, "服饰类"),
OTHER(4, "其他");
private final int code;
private final String desc;
ItemType(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
}
\ No newline at end of file
package com.liquidnet.service.sweet.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.liquidnet.service.sweet.entity.SweetLostFoundAdmin;
/**
* 失物招领管理员Mapper接口
*
* @author liquidnet
* @since 2025-01-18
*/
public interface SweetLostFoundAdminMapper extends BaseMapper<SweetLostFoundAdmin> {
}
\ No newline at end of file
package com.liquidnet.service.sweet.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.liquidnet.service.sweet.entity.SweetLostFoundItem;
/**
* 失物招领信息Mapper接口
*
* @author liquidnet
* @since 2025-01-18
*/
public interface SweetLostFoundItemMapper extends BaseMapper<SweetLostFoundItem> {
}
\ No newline at end of file
package com.liquidnet.service.sweet.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* 失物招领管理员返回VO
*
* @author liquidnet
* @since 2025-01-18
*/
@ApiModel("失物招领管理员返回")
@Data
@EqualsAndHashCode(callSuper = false)
public class SweetLostFoundAdminVo implements Serializable, Cloneable {
@ApiModelProperty("主键ID")
private Long id;
@ApiModelProperty("手机号")
private String phone;
@ApiModelProperty("备注姓名")
private String name;
@ApiModelProperty("权限类型:1-发帖员 2-管理员")
private Integer permissionType;
@ApiModelProperty("授权范围:1-本站次 2-全站")
private Integer authScope;
@ApiModelProperty("演出ID")
private String performanceId;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liquidnet.service.sweet.mapper.SweetLostFoundAdminMapper">
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id
, phone, name, permission_type, auth_scope, performance_id,
create_time, update_time, is_deleted, create_user_id, update_user_id
</sql>
<!-- 分页查询管理员列表 -->
<select id="selectAdminPage" resultType="com.liquidnet.service.sweet.vo.SweetLostFoundAdminVo">
SELECT
a.id,
a.phone,
a.name,
a.permission_type,
a.auth_scope,
a.performance_id,
a.create_time,
a.update_time,
a.create_user_id,
a.update_user_id
FROM sweet_lost_found_admin a
WHERE a.is_deleted = 0
<if test="param.phone != null and param.phone != ''">
AND a.phone LIKE CONCAT('%', #{param.phone}, '%')
</if>
<if test="param.name != null and param.name != ''">
AND a.name LIKE CONCAT('%', #{param.name}, '%')
</if>
<if test="param.permissionType != null">
AND a.permission_type = #{param.permissionType}
</if>
<if test="param.authScope != null">
AND a.auth_scope = #{param.authScope}
</if>
<if test="param.performanceId != null">
AND a.performance_id = #{param.performanceId}
</if>
ORDER BY a.create_time DESC
</select>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liquidnet.service.sweet.mapper.SweetLostFoundItemMapper">
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id
, item_image, description, pickup_location, pickup_date, item_type,
performance_id, create_time, update_time, is_deleted, create_user_id, update_user_id
</sql>
<!-- 查询失物信息列表 -->
<select id="selectItemPage" resultType="com.liquidnet.service.sweet.vo.SweetLostFoundItemVo">
SELECT
i.id,
i.item_image,
i.description,
i.pickup_location,
i.pickup_date,
i.item_type,
i.performance_id,
i.create_time,
i.update_time,
i.create_user_id
FROM sweet_lost_found_item i
WHERE i.is_deleted = 0
<if test="param.performanceId != null">
AND i.performance_id = #{param.performanceId}
</if>
<if test="param.itemType != null">
AND i.item_type = #{param.itemType}
</if>
<if test="param.startDate != null">
AND i.pickup_date >= #{param.startDate}
</if>
<if test="param.endDate != null">
AND i.pickup_date &lt;= #{param.endDate}
</if>
ORDER BY i.create_time DESC
</select>
</mapper>
\ No newline at end of file
......@@ -40,4 +40,14 @@ public interface FeignPlatformTaskClient {
*/
@GetMapping("platform/performance/subscribePush")
ResponseDto<Boolean> performanceSubscribePush();
/*
* @description: 自动处理退款失败
* @author: zjp
* @date: 2025/4/27 14:28
* @param: []
* @return: com.liquidnet.service.base.ResponseDto<java.lang.Boolean>
**/
@GetMapping("platform/refund/failRefund")
ResponseDto<Boolean> failRefund();
}
......@@ -341,7 +341,7 @@ public abstract class AbstractOrderCloseReceiver implements StreamListener<Strin
// redis 改限购
for (int i = 0; i < kylinOrderTicketVo.getEntitiesVoList().size(); i++) {
KylinOrderTicketEntitiesVo items = kylinOrderTicketVo.getEntitiesVoList().get(i);
kylinOrderUtils.changeBuyInfo(items.getUserId(), items.getEnterIdCode(), items.getPerformanceId(), items.getTicketId(), -1);
kylinOrderUtils.changeBuyInfo(items.getUserId(), items.getEnterIdCode(), items.getPerformanceId(), items.getTicketId(), items.getTimeId(), -1);
}
//改库存
kylinOrderUtils.changeSurplusGeneral(kylinOrderTicketVo.getTicketId(), kylinOrderTicketVo.getNumber());
......
......@@ -135,11 +135,12 @@ public class KylinOrderUtils {
* @param ticketId
* @param buyCount
*/
public void changeBuyInfo(String userId, String idCard, String performanceId, String ticketId, int buyCount) {
public void changeBuyInfo(String userId, String idCard, String performanceId, String ticketId, String timeId, int buyCount) {
String redisKeyUid;
String redisKeyIdCard;
String performanceIdKeyIdCard="";
String ticketIdKeyIdCard="";
String timeIdKeyIdCard = "";
int isTrueName = getPerformanceIsTrueName(performanceId);
......@@ -150,6 +151,7 @@ public class KylinOrderUtils {
if (isTrueName != 0) {
performanceIdKeyIdCard = redisKeyIdCard + ":" + KylinRedisConst.PERFORMANCE_ID + ":" + performanceId;
ticketIdKeyIdCard = redisKeyIdCard + ":" + KylinRedisConst.TICKET_ID + ":" + ticketId;
timeIdKeyIdCard = redisKeyIdCard + ":" + KylinRedisConst.TIME_ID + ":" + timeId;
}
if (buyCount > 0) {
......@@ -158,11 +160,13 @@ public class KylinOrderUtils {
if (isTrueName != 0) {
redisDataSourceUtil.getRedisKylinUtil().incr(ticketIdKeyIdCard, buyCount);
redisDataSourceUtil.getRedisKylinUtil().incr(performanceIdKeyIdCard, buyCount);
redisDataSourceUtil.getRedisKylinUtil().incr(timeIdKeyIdCard, buyCount);
}
} else {
if (isTrueName != 0) {
redisDataSourceUtil.getRedisKylinUtil().decr(ticketIdKeyIdCard, Math.abs(buyCount));
redisDataSourceUtil.getRedisKylinUtil().decr(performanceIdKeyIdCard, Math.abs(buyCount));
redisDataSourceUtil.getRedisKylinUtil().decr(timeIdKeyIdCard, Math.abs(buyCount));
}
redisDataSourceUtil.getRedisKylinUtil().decr(ticketIdKeyUid, Math.abs(buyCount));
redisDataSourceUtil.getRedisKylinUtil().decr(performanceIdKeyUid, Math.abs(buyCount));
......
......@@ -99,4 +99,21 @@ public class KylinTaskHandler {
XxlJobHelper.handleFail();
}
}
/**
* 退款失败自动处理
* @author zjp
* @param null
* @return: null
* @date 2024/3/21 15:32
*/
@XxlJob(value = "sev-platform:failRefund")
public void failRefund() {
try {
XxlJobHelper.handleSuccess("结果:" + feignPlatformTaskClient.failRefund().getData());
} catch (Exception e) {
XxlJobHelper.log(e);
XxlJobHelper.handleFail();
}
}
}
-- 添加实名认证限购字段到场次表
USE ln_scene;
-- 在kylin_ticket_times表中添加real_name_limit字段
ALTER TABLE kylin_ticket_times
ADD COLUMN real_name_limit tinyint NOT NULL DEFAULT 0 COMMENT '是否开启实名认证限购 0关闭 1开启' AFTER comment;
\ No newline at end of file
......@@ -8,6 +8,7 @@ import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.dto.param.PayAgainParam;
import com.liquidnet.service.kylin.dto.param.PayOrderParam;
import com.liquidnet.service.kylin.dto.param.SyncOrderParam;
import com.liquidnet.service.kylin.dto.vo.LimitErrorResultVo;
import com.liquidnet.service.kylin.dto.vo.returns.*;
import com.liquidnet.service.kylin.service.IKylinOrderTicketsService;
import io.swagger.annotations.*;
......@@ -167,6 +168,13 @@ public class KylinOrderTicketsController {
return orderTicketsService.getOrderArCode(orderId);
}
@PostMapping("limitInfo")
@ApiOperation("获取用户限购详细信息")
@ApiResponse(code = 200, message = "接口返回对象参数")
public ResponseDto<List<LimitErrorResultVo>> limitInfo(@RequestBody List<LimitErrorResultVo> param) {
return orderTicketsService.limitInfo(param);
}
/*@GetMapping("toOrderRefundDetails")
@ApiOperation("想要退款订单详情")
@ApiResponse(code = 200, message = "接口返回对象参数")
......
......@@ -34,6 +34,8 @@ import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import java.math.BigDecimal;
import java.time.LocalDateTime;
......@@ -69,7 +71,8 @@ public class KylinOrderTicketsRefundServiceImpl {
private Integer expressType;
@Value("${liquidnet.express.shunfeng.depositumInfo}")
private String depositumInfo;
@Value("${liquidnet.client.admin.platformUrl}")
private String platformUrl;
@Autowired
private ShunfengSignUtils shunfengSignUtils;
......@@ -270,7 +273,20 @@ public class KylinOrderTicketsRefundServiceImpl {
if (orderTicketVo.getGetTicketType().equals("express") && sendExpressType > 0) {// 快递票
expressPlace(sendExpressType, expressNumber, expressContacts, expressPhone, sendExpressAddress, appointmentTime, orderTicketVo, performanceVo, orderRefundId);
}
//电子票自动退款
if (orderTicketVo.getGetTicketType().equals("electronic")){
try {
MultiValueMap<String, String> params = new LinkedMultiValueMap();
params.add("orderRefundsId", orderRefundId);
MultiValueMap<String, String> headers = new LinkedMultiValueMap();
headers.add("Accept", "application/json;charset=UTF-8");
log.info("触发自动退款参数" + JsonUtils.toJson(params));
String post = HttpUtil.post(platformUrl + "/platform/refund/automaticRefund", params, headers);
log.info("触发自动退款返参数" + post);
}catch (Exception e){
log.error("触发自动退款接口失败orderRefundId={} Exception",orderRefundId,e);
}
}
HashMap<String, String> map = CollectionUtil.mapStringString();
map.put("orderRefundsId", orderRefundId);
return ResponseDto.success(map);
......
......@@ -10,6 +10,7 @@ import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.UserPathDto;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.kylin.constant.KylinTableStatusConst;
import com.liquidnet.service.kylin.dto.vo.LimitErrorResultVo;
import com.liquidnet.service.kylin.dto.vo.middle.KylinTicketTimesVo;
import com.liquidnet.service.kylin.dto.vo.middle.KylinTicketVo;
import com.liquidnet.service.kylin.dto.vo.mongo.*;
......@@ -383,7 +384,7 @@ public class KylinOrderTicketsServiceImpl implements IKylinOrderTicketsService {
KylinTicketPartnerVo kylinTicketPartnerVo = dataUtils.getKylinTicketPartnerVoByTicketId(ticketsId);
if (null != kylinTicketPartnerVo && null != kylinTicketPartnerVo.getViewersNumber()) {
return kylinTicketPartnerVo.getViewersNumber() == 1;
}else {
} else {
log.info("[isSingleTicket] 票信息为空, ticketsId: {}", ticketsId);
return false;
}
......@@ -1364,4 +1365,36 @@ public class KylinOrderTicketsServiceImpl implements IKylinOrderTicketsService {
return ResponseDto.success(dataUtils.getOrderArCode(orderId));
}
@Override
public ResponseDto<List<LimitErrorResultVo>> limitInfo(List<LimitErrorResultVo> param) {
for (LimitErrorResultVo vo : param) {
Criteria criteria = Criteria.where("performanceId").is(vo.getPerformancesId())
.and("isPayment").in(Arrays.asList(0, 1, 2, 4));
if (vo.getLimitTarget().equals(2)) {
criteria.and("enterIdCode").is(vo.getIdCard());
}
if (vo.getLimitType().equals(2)) {
criteria.and("ticketId").is(vo.getTicketsId());
}
if (vo.getLimitType().equals(3)) {
criteria.and("timeId").is(vo.getTimeId());
}
Query query = Query.query(criteria);
List<KylinOrderTicketEntitiesForOrderVo> list = mongoTemplate.find(query,
KylinOrderTicketEntitiesForOrderVo.class, KylinOrderTicketEntitiesVo.class.getSimpleName());
List<KylinOrderTicketEntitiesForOrderVo> newList = new ArrayList<>();
for (KylinOrderTicketEntitiesForOrderVo entities : list) {
if (entities.getIsPayment().equals(0)) {
KylinOrderTicketVo orderTicketVo = dataUtils.getOrderTicketVo(entities.getOrderId());
if (orderTicketVo.getStatus().equals(2)) {
continue;
}
}
newList.add(entities);
}
vo.setEntities(newList);
}
return ResponseDto.success(param);
}
}
......@@ -26,6 +26,7 @@ import com.liquidnet.service.kylin.dto.vo.returns.PayInnerResultVo;
import com.liquidnet.service.kylin.dto.vo.returns.PayResultVo;
import com.liquidnet.service.kylin.entity.*;
import com.liquidnet.service.kylin.service.IKylinOrderTicketsOrderService;
import com.liquidnet.service.kylin.dto.vo.LimitErrorResultVo;
import com.liquidnet.service.order.utils.*;
import com.taobao.api.TaobaoClient;
import com.taobao.api.request.AlibabaDamaiMevOpenBatchpushticketRequest;
......@@ -255,6 +256,10 @@ public class KylinOrderTicketsServiceImpl implements IKylinOrderTicketsOrderServ
}
// 获取限购 实名
Integer timeRealNameLimit = ticketTimesData.getRealNameLimit();
if (timeRealNameLimit == null) {
timeRealNameLimit = 0;
}
int ticketLimit = 1;
int ticketMemberLimit = ticketData.getLimitCountMember();//会员票种限购
int ticketIdCount = ticketData.getIdCount();//实名票种限购
......@@ -399,25 +404,41 @@ public class KylinOrderTicketsServiceImpl implements IKylinOrderTicketsOrderServ
//限购判断 如果实名 则身份证维度限购 如果不实名则数量限购
if (entersVoList.size() > 0) {
for (int i = 0; i < entersVoList.size(); i++) {
dataUtils.changeBuyInfo(uid, entersVoList.get(i).getIdCard(), performanceData.getPerformancesId(), ticketData.getTicketsId(), 1);
String res1 = orderUtils.judgeOrderLimit(uid, entersVoList.get(i).getIdCard(), payOrderParam.getPerformanceId(), payOrderParam.getTicketId(), performanceLimit, performanceMemberLimit, performanceIdCount, ticketLimit, ticketMemberLimit, ticketIdCount, memberType, isTrueName);
if (!res1.equals("")) {
AdamEntersVo adamEntersVo = entersVoList.get(i);
dataUtils.changeBuyInfo(uid, adamEntersVo.getIdCard(), performanceData.getPerformancesId(), ticketData.getTicketsId(), payOrderParam.getTimeId(), 1);
LimitErrorResultVo limitResult = orderUtils.judgeOrderLimit(uid, entersVoList.get(i).getIdCard(), payOrderParam.getPerformanceId(), payOrderParam.getTicketId(), payOrderParam.getTimeId(), performanceLimit, performanceMemberLimit, performanceIdCount, ticketLimit, ticketMemberLimit, ticketIdCount, timeRealNameLimit, memberType, isTrueName);
if (limitResult != null) {
for (int x = 0; x <= i; x++) {
dataUtils.changeBuyInfo(uid, entersVoList.get(x).getIdCard(), performanceData.getPerformancesId(), ticketData.getTicketsId(), -1);
dataUtils.changeBuyInfo(uid, entersVoList.get(x).getIdCard(), performanceData.getPerformancesId(), ticketData.getTicketsId(), payOrderParam.getTimeId(), -1);
}
orderUtils.changeSurplus(isPay, payOrderParam.getTicketId(), payOrderParam.getNumber());
orderUtils.backAdvanceCoupon(payOrderParam.getAdvanceCode(), uid);
return ResponseDto.failure(res1);//乱七八糟异常
PayInnerResultVo payInnerResultVo = PayInnerResultVo.getNew();
limitResult.setPerformancesId(payOrderParam.getPerformanceId());
limitResult.setTimeId(payOrderParam.getTimeId());
limitResult.setTicketsId(payOrderParam.getTicketId());
limitResult.setIdCard(adamEntersVo.getIdCard());
limitResult.setIdName(adamEntersVo.getName());
limitResult.setEntersId(adamEntersVo.getEntersId());
payInnerResultVo.setLimitResult(Collections.singletonList(limitResult));
return ResponseDto.failure("12345", "购买数量超出限制", payInnerResultVo);//返回完整的限购错误信息
}
}
} else {
dataUtils.changeBuyInfo(uid, "", performanceData.getPerformancesId(), ticketData.getTicketsId(), payOrderParam.getNumber());
String res1 = orderUtils.judgeOrderLimit(uid, "", payOrderParam.getPerformanceId(), payOrderParam.getTicketId(), performanceLimit, performanceMemberLimit, performanceIdCount, ticketLimit, ticketMemberLimit, ticketIdCount, memberType, isTrueName);
if (!res1.equals("")) {
dataUtils.changeBuyInfo(uid, "", performanceData.getPerformancesId(), ticketData.getTicketsId(), -payOrderParam.getNumber());
dataUtils.changeBuyInfo(uid, "", performanceData.getPerformancesId(), ticketData.getTicketsId(), payOrderParam.getTimeId(), payOrderParam.getNumber());
LimitErrorResultVo limitResult = orderUtils.judgeOrderLimit(uid, "", payOrderParam.getPerformanceId(), payOrderParam.getTicketId(), payOrderParam.getTimeId(), performanceLimit, performanceMemberLimit, performanceIdCount, ticketLimit, ticketMemberLimit, ticketIdCount, timeRealNameLimit, memberType, isTrueName);
if (limitResult != null) {
dataUtils.changeBuyInfo(uid, "", performanceData.getPerformancesId(), ticketData.getTicketsId(), payOrderParam.getTimeId(), -payOrderParam.getNumber());
orderUtils.changeSurplus(isPay, payOrderParam.getTicketId(), payOrderParam.getNumber());
orderUtils.backAdvanceCoupon(payOrderParam.getAdvanceCode(), uid);
return ResponseDto.failure(res1);//乱七八糟异常
PayInnerResultVo payInnerResultVo = PayInnerResultVo.getNew();
limitResult.setPerformancesId(payOrderParam.getPerformanceId());
limitResult.setTimeId(payOrderParam.getTimeId());
limitResult.setTicketsId(payOrderParam.getTicketId());
payInnerResultVo.setLimitResult(Collections.singletonList(limitResult)); // 设置为List
return ResponseDto.failure("12345", "购买数量超出限制", payInnerResultVo);//返回完整的限购错误信息
}
}
......@@ -435,11 +456,11 @@ public class KylinOrderTicketsServiceImpl implements IKylinOrderTicketsOrderServ
dataUtils.decrUseCouponCount(uid, performanceId);
}
for (AdamEntersVo enters : entersVoList) {
dataUtils.changeBuyInfo(uid, enters.getIdCard(), payOrderParam.getPerformanceId(), payOrderParam.getTicketId(), -1);
dataUtils.changeBuyInfo(uid, enters.getIdCard(), payOrderParam.getPerformanceId(), payOrderParam.getTicketId(), payOrderParam.getTimeId(), -1);
}
if (entersVoList.size() == 0) {
for (int i = 0; i < payOrderParam.getNumber(); i++) {
dataUtils.changeBuyInfo(uid, "", payOrderParam.getPerformanceId(), payOrderParam.getTicketId(), -1);
dataUtils.changeBuyInfo(uid, "", payOrderParam.getPerformanceId(), payOrderParam.getTicketId(), payOrderParam.getTimeId(), -1);
}
}
}
......
......@@ -130,11 +130,12 @@ public class DataUtils {
* @param ticketId 票种id
* @param buyCount 购买数量 大于 0 增加 小于 0 减少 对应 支付 退款表
*/
public void changeBuyInfo(String userId, String idCard, String performanceId, String ticketId, int buyCount) {
public void changeBuyInfo(String userId, String idCard, String performanceId, String ticketId, String timeId, int buyCount) {
String redisKeyUid;
String redisKeyIdCard;
String performanceIdKeyIdCard = "";
String ticketIdKeyIdCard = "";
String timeIdKeyIdCard = "";
int isTrueName = getPerformanceIsTrueName(performanceId);
......@@ -145,6 +146,7 @@ public class DataUtils {
if (isTrueName != 0) {
performanceIdKeyIdCard = redisKeyIdCard + ":" + KylinRedisConst.PERFORMANCE_ID + ":" + performanceId;
ticketIdKeyIdCard = redisKeyIdCard + ":" + KylinRedisConst.TICKET_ID + ":" + ticketId;
timeIdKeyIdCard = redisKeyIdCard + ":" + KylinRedisConst.TIME_ID + ":" + timeId;
}
if (buyCount > 0) {
......@@ -153,11 +155,13 @@ public class DataUtils {
if (isTrueName != 0) {
redisUtil.incr(ticketIdKeyIdCard, buyCount);
redisUtil.incr(performanceIdKeyIdCard, buyCount);
redisUtil.incr(timeIdKeyIdCard, buyCount);
}
} else {
if (isTrueName != 0) {
redisUtil.decr(ticketIdKeyIdCard, Math.abs(buyCount));
redisUtil.decr(performanceIdKeyIdCard, Math.abs(buyCount));
redisUtil.decr(timeIdKeyIdCard, Math.abs(buyCount));
}
redisUtil.decr(ticketIdKeyUid, Math.abs(buyCount));
redisUtil.decr(performanceIdKeyUid, Math.abs(buyCount));
......@@ -202,6 +206,15 @@ public class DataUtils {
}
}
// 获取 证件维度 场次购买数量
public int getIdCardMBuyCount(String idCard, String timeId) {
try {
return (int) redisUtil.get(KylinRedisConst.IDCARD_BUY_INFO + idCard + ":" + KylinRedisConst.TIME_ID + ":" + timeId);
} catch (Exception e) {
return 0;
}
}
/**
* 删除订单redis
*
......
......@@ -4,12 +4,16 @@ import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.dto.param.RefundCallbackParam;
import com.liquidnet.service.platform.service.refund.OrderRefundsCallbackServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotBlank;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* <p>
......@@ -34,6 +38,31 @@ public class OrderRefundCallbackController {
return result;
}
@PostMapping("automaticRefund")
@ApiOperation("用户自动退款")
@ApiImplicitParams({
@ApiImplicitParam(type = "from", required = true, dataType = "String", name = "orderRefundsId", value = "orderRefundsId", example = "0")
})
public ResponseDto<String> automaticRefund(@RequestParam("orderRefundsId") @NotBlank(message = "退款id不能为空") String orderRefundsId) {
//延迟5秒执行
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.schedule(() -> {
orderRefundsCallbackServiceImpl.automaticRefund(orderRefundsId);
}, 5, TimeUnit.SECONDS);
return ResponseDto.success("success");
}
@GetMapping(value = "failRefund")
@ApiOperation(value = "退款失败定时处理")
public ResponseDto<Boolean> performanceSubscribePush() {
try {
orderRefundsCallbackServiceImpl.failRefund();
return ResponseDto.success(true);
} catch (Exception e) {
return ResponseDto.success(false);
}
}
@GetMapping("alipayActiveCallback")
@ApiOperation("支付宝主动查询退款结果")
public ResponseDto<String> alipayActiveCallback() {
......
......@@ -261,7 +261,7 @@ public class KylinRefundsStatusServiceImpl {
int surplusGeneral = dataUtils.changeSurplusGeneral(entitiesInfo.getTicketId(), 1);
log.info("refundCallback回滚库存res: [surplusGeneral={},ticketId={},orderRefundCode={}]", surplusGeneral, entitiesInfo.getTicketId(), refundCallbackParam.getOrderRefundCode());
log.info(UserPathDto.setData("changeBuyInfo", "UserId=" + orderInfo.getUserId() + "idCard=" + entitiesInfo.getEnterIdCode() + " PerformanceId=" + orderRelations.getPerformanceId() + " TicketId=" + entitiesInfo.getTicketId(), "info"));
dataUtils.changeBuyInfo(orderInfo.getUserId(), entitiesInfo.getEnterIdCode(), orderRelations.getPerformanceId(), entitiesInfo.getTicketId(), -1);
dataUtils.changeBuyInfo(orderInfo.getUserId(), entitiesInfo.getEnterIdCode(), orderRelations.getPerformanceId(), entitiesInfo.getTicketId(), entitiesInfo.getTimeId(), -1);
}
}
if (newStatus == KylinTableStatusConst.ORDER_STATUS4) {
......@@ -309,8 +309,23 @@ public class KylinRefundsStatusServiceImpl {
}
// 退积分
goblinRedisUtils.integral(orderInfo.getUserId(), refundCallbackParam.getRefundPrice(), "演出订单退款:".concat(orderInfo.getPerformanceTitle()).concat(":").concat(orderInfo.getOrderCode().substring(orderInfo.getOrderCode().length() - 10)), 2);
}
//未退款入场人数量为0才退优先卷
List<KylinOrderTicketEntities> kylinOrderTicketEntities = kylinOrderTicketEntitiesMapper.selectList(
Wrappers.lambdaQuery(KylinOrderTicketEntities.class).eq(KylinOrderTicketEntities::getOrderId, refundInfo.getOrderTicketsId()).eq(KylinOrderTicketEntities::getIsPayment, 1));
log.info("订单退款请求未退款入场人数量number={}",kylinOrderTicketEntities.size());
if(kylinOrderTicketEntities.size()==0){
//退优先卷
ArrayList<KylinOrderCoupons> orderCoupons = dataUtils.getOrderCoupon(refundInfo.getOrderTicketsId());
if (!CollectionUtil.isEmpty(orderCoupons)) {
for (KylinOrderCoupons item : orderCoupons) {
if (item.getCouponType() == 101) {
dataUtils.backCoupon(item.getCouponCode(), orderInfo.getUserId());
}
}
}
}
}
return true;
}
......
package com.liquidnet.service.platform.service.refund;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.HttpUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.constant.KylinTableStatusConst;
import com.liquidnet.service.kylin.dto.param.RefundApplyParam;
import com.liquidnet.service.kylin.dto.param.RefundCallbackParam;
import com.liquidnet.service.kylin.dto.param.RefundSearchParam;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinOrderTicketVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinPerformanceVo;
import com.liquidnet.service.kylin.dto.vo.returns.KylinOrderRefundsVo;
import com.liquidnet.service.kylin.entity.KylinOrderRefunds;
import com.liquidnet.service.kylin.entity.KylinOrderTickets;
......@@ -56,6 +63,7 @@ public class OrderRefundsCallbackServiceImpl extends ServiceImpl<KylinOrderRefun
@Value("${liquidnet.service.platform.urls.ticketRefundNotify}")
private String refundNotify;
@Autowired
private KylinRefundsStatusServiceImpl kylinRefundsStatusServiceImpl;
......@@ -134,6 +142,73 @@ public class OrderRefundsCallbackServiceImpl extends ServiceImpl<KylinOrderRefun
return "success";
}
public void automaticRefund(String orderRefundsId) {
try {
KylinOrderRefunds refund = kylinOrderRefundsMapper.selectOne(
Wrappers.lambdaQuery(KylinOrderRefunds.class)
.eq(KylinOrderRefunds::getOrderRefundsId, orderRefundsId)
);
log.info("自动退款refund={}",refund.toString());
KylinOrderTickets oderInfo = kylinOrderTicketsMapper.selectOne(
new QueryWrapper<KylinOrderTickets>()
.eq("order_tickets_id", refund.getOrderTicketsId())
);
BigDecimal refundPrice = refund.getPrice().add(refund.getPriceExpress());
MultiValueMap<String, String> params = new LinkedMultiValueMap();
params.add("code", oderInfo.getPayCode());
params.add("notifyUrl", refundNotify);
params.add("orderCode", oderInfo.getOrderCode());
params.add("orderRefundCode", refund.getOrderRefundCode());
params.add("paymentId", oderInfo.getPaymentId());
params.add("paymentType", oderInfo.getPaymentType());
params.add("price", String.valueOf(refundPrice));
params.add("priceTotal", String.valueOf(oderInfo.getPriceActual()));
params.add("reason", "按需退款");
MultiValueMap<String, String> headers = new LinkedMultiValueMap();
headers.add("Accept", "application/json;charset=UTF-8");
log.info("调用自动退款参数" + JsonUtils.toJson(params));
String postResult = HttpUtil.post(refundApply, params, headers);
log.info("调用自动退款返参res" + postResult);
HashMap hashMapResult = JsonUtils.fromJson(postResult, HashMap.class);
Boolean success = (Boolean) hashMapResult.get("success");
if (!success) {
String message = (String) hashMapResult.get("message");
log.info("自动退款pay返回失败" + message);
KylinOrderRefunds kylinOrderRefundsFail = new KylinOrderRefunds();
kylinOrderRefundsFail.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_ERROR);
kylinOrderRefundsFail.setRefundError(message);
kylinOrderRefundsFail.setUpdatedAt(LocalDateTime.now());
kylinOrderRefundsMapper.update(
kylinOrderRefundsFail,
new UpdateWrapper<KylinOrderRefunds>().eq("order_refunds_id", refund.getOrderRefundsId())
);
// 修改缓存
KylinOrderRefundsVo kylinOrderRefundsVoFail = new KylinOrderRefundsVo();
BeanUtils.copyProperties(kylinOrderRefundsFail, kylinOrderRefundsVoFail);
BasicDBObject objectFail = new BasicDBObject("$set", mongoConverter.convertToMongoType(kylinOrderRefundsVoFail));
UpdateResult updateFailResult = mongoTemplate.getCollection(KylinOrderRefundsVo.class.getSimpleName()).updateOne(
Query.query(Criteria.where("orderRefundsId").is(refund.getOrderRefundsId())).getQueryObject(),
objectFail
);
}
} catch (Exception e) {
log.error("自动退款请求pay失败e" + e.getMessage());
}
}
public void failRefund(){
List<KylinOrderRefunds> kylinOrderRefunds = kylinOrderRefundsMapper.selectList(
Wrappers.lambdaQuery(KylinOrderRefunds.class)
.eq(KylinOrderRefunds::getStatus, KylinTableStatusConst.ORDER_REFUND_STATUS_ERROR));
log.info("自动处理退款失败开始");
if(!CollectionUtil.isEmpty(kylinOrderRefunds)){
for (KylinOrderRefunds kylinOrderRefund : kylinOrderRefunds) {
String refundId = kylinOrderRefund.getOrderRefundsId();
log.info("自动处理退款失败RefundId={}",refundId);
this.automaticRefund(refundId);
}
}
}
@Override
public String getOrderRefundCode(String orderRefundCode, int type) {
return null;
......
package com.liquidnet.service.platform.utils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.liquidnet.common.cache.redis.util.RedisDataSourceUtil;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.HttpUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.constant.RedisKeyExpireConst;
import com.liquidnet.service.candy.param.BackCouponParam;
import com.liquidnet.service.kylin.constant.KylinRedisConst;
import com.liquidnet.service.kylin.dto.vo.KylinApiCameraDevicesVo;
import com.liquidnet.service.kylin.dto.vo.KylinTimePerformanceVo;
......@@ -21,18 +25,22 @@ import com.liquidnet.service.slime.constant.SlimeRedisConst;
import com.liquidnet.service.slime.dto.vo.SlimeFieldsVo;
import com.liquidnet.service.sweet.constant.SweetConstant;
import com.liquidnet.service.sweet.vo.SweetAppletUsersVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@Component
@Slf4j
public class DataUtils {
@Autowired
......@@ -44,6 +52,9 @@ public class DataUtils {
@Autowired
private MongoVoUtils mongoVoUtils;
@Value("${liquidnet.service.candy.url}")
private String candyUrl;
/**
* 根据 购票须知 id 获取 购票须知文案
*
......@@ -272,11 +283,12 @@ public class DataUtils {
* @param ticketId 票种id
* @param buyCount 购买数量 大于 0 增加 小于 0 减少 对应 支付 退款表
*/
public void changeBuyInfo(String userId, String idCard, String performanceId, String ticketId, int buyCount) {
public void changeBuyInfo(String userId, String idCard, String performanceId, String ticketId, String timeId, int buyCount) {
String redisKeyUid;
String redisKeyIdCard;
String performanceIdKeyIdCard="";
String ticketIdKeyIdCard="";
String timeIdKeyIdCard = "";
int isTrueName = getPerformanceIsTrueName(performanceId);
......@@ -287,6 +299,7 @@ public class DataUtils {
if (isTrueName != 0) {
performanceIdKeyIdCard = redisKeyIdCard + ":" + KylinRedisConst.PERFORMANCE_ID + ":" + performanceId;
ticketIdKeyIdCard = redisKeyIdCard + ":" + KylinRedisConst.TICKET_ID + ":" + ticketId;
timeIdKeyIdCard = redisKeyIdCard + ":" + KylinRedisConst.TIME_ID + ":" + timeId;
}
if (buyCount > 0) {
......@@ -295,11 +308,13 @@ public class DataUtils {
if (isTrueName != 0) {
redisDataSourceUtil.getRedisKylinUtil().incr(ticketIdKeyIdCard, buyCount);
redisDataSourceUtil.getRedisKylinUtil().incr(performanceIdKeyIdCard, buyCount);
redisDataSourceUtil.getRedisKylinUtil().incr(timeIdKeyIdCard, buyCount);
}
} else {
if (isTrueName != 0) {
redisDataSourceUtil.getRedisKylinUtil().decr(ticketIdKeyIdCard, Math.abs(buyCount));
redisDataSourceUtil.getRedisKylinUtil().decr(performanceIdKeyIdCard, Math.abs(buyCount));
redisDataSourceUtil.getRedisKylinUtil().decr(timeIdKeyIdCard, Math.abs(buyCount));
}
redisDataSourceUtil.getRedisKylinUtil().decr(ticketIdKeyUid, Math.abs(buyCount));
redisDataSourceUtil.getRedisKylinUtil().decr(performanceIdKeyUid, Math.abs(buyCount));
......@@ -494,4 +509,19 @@ public class DataUtils {
return (KylinCamera) obj;
}
}
public void backCoupon(String uCouponId, String uid) {
try {
BackCouponParam param = BackCouponParam.getNew();
param.setuCouponIds(uCouponId);
param.setUid(uid);
MultiValueMap<String, String> header = CollectionUtil.linkedMultiValueMapStringString();
ArrayList<BackCouponParam> params = new ArrayList();
params.add(param);
String jsonString = JSON.toJSONString(params);
String returnData = HttpUtil.postRaw(candyUrl + "/candy-coupon/useBack", jsonString, header);
} catch (Exception e) {
log.error("回退券ERROR:{}", e);
}
}
}
......@@ -107,6 +107,9 @@ public class KylinPerformancesPartnerServiceImpl implements IKylinPerformancesPa
PerformancePartnerVo performancePartnerVo = PerformancePartnerVo.getNew();
BeanUtils.copyProperties(step1Param, performancePartnerVo);
performancePartnerVo.setIsTrueName(0);
if (step1Param.getType().equals(101)) {
performancePartnerVo.setIsTrueName(1);
}
performancePartnerVo.setLimitCount(0);
performancePartnerVo.setIdCount(0);
performancePartnerVo.setCreatedAt(createdAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
......
......@@ -94,6 +94,7 @@ public class KylinTicketTimesPartnerServiceImpl implements IKylinTicketTimesPart
kylinTicketTimesPartnerVo.setTitle(title);
kylinTicketTimesPartnerVo.setPerformancesId(createTicketTimesParam.getPerformancesId());
kylinTicketTimesPartnerVo.setType(createTicketTimesParam.getType());
kylinTicketTimesPartnerVo.setRealNameLimit(createTicketTimesParam.getRealNameLimit());
kylinTicketTimesPartnerVo.setCreatedAt(createdAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
mongoSlimeUtils.insertTicketTimesPartnerVo(kylinTicketTimesPartnerVo);
return ResponseDto.success(kylinTicketTimesPartnerVo);
......@@ -132,6 +133,7 @@ public class KylinTicketTimesPartnerServiceImpl implements IKylinTicketTimesPart
kylinTicketTimesPartnerVo.setTitle(title);
kylinTicketTimesPartnerVo.setPerformancesId(createTicketTimesParam.getPerformancesId());
kylinTicketTimesPartnerVo.setType(createTicketTimesParam.getType());
kylinTicketTimesPartnerVo.setRealNameLimit(createTicketTimesParam.getRealNameLimit());
kylinTicketTimesPartnerVo.setCreatedAt(createdAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
mongoSlimeUtils.insertTicketTimesPartnerVo(kylinTicketTimesPartnerVo);
return ResponseDto.success(kylinTicketTimesPartnerVo);
......
......@@ -495,6 +495,10 @@ public class PerformanceUtils {
log.info("performanceId = " + performanceId + " NEED CHANGE TIMES USE_START");
return true;
}
if (!times.getRealNameLimit().equals(timesVo.getRealNameLimit())) {
log.info("performanceId = " + performanceId + " NEED CHANGE TIMES RealNameLimit");
return true;
}
if (!times.getUseEnd().equals(timesVo.getUseEnd())) {
log.info("performanceId = " + performanceId + " NEED CHANGE TIMES USE_END");
return true;
......
......@@ -60,7 +60,7 @@ kylin_performance_relations.insert=INSERT INTO kylin_performance_relations (perf
kylin_ticket_times.del=DELETE FROM kylin_ticket_times WHERE ticket_times_id = ?
kylin_ticket_time_relation.del=DELETE FROM kylin_ticket_time_relation WHERE times_id = ?
kylin_ticket_times.insert=INSERT INTO kylin_ticket_times (ticket_times_id,title,status,type,use_start,use_end,comment,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?)
kylin_ticket_times.insert=INSERT INTO kylin_ticket_times (ticket_times_id,title,status,type,use_start,use_end,comment,created_at,updated_at,real_name_limit) VALUES (?,?,?,?,?,?,?,?,?,?)
kylin_ticket_time_relation.insert=INSERT INTO kylin_ticket_time_relation (ticket_time_relation_id,times_id,performance_id,created_at,updated_at) VALUES (?,?,?,?,?)
kylin_tickets.del=DELETE FROM kylin_tickets WHERE tickets_id = ?
......
-- 草莓演出失物招领功能数据库表结构
-- 创建时间: 2025-01-18
-- 表前缀: sweet_
-- 失物招领管理员表
CREATE TABLE IF NOT EXISTS `sweet_lost_found_admin`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`admin_id` varchar(64) NOT NULL DEFAULT '' COMMENT '管理员ID',
`phone` varchar(11) NOT NULL DEFAULT '' COMMENT '手机号',
`name` varchar(50) NOT NULL DEFAULT '' COMMENT '备注姓名',
`permission_type` tinyint(1) NOT NULL DEFAULT 1 COMMENT '权限类型:1-发帖员(仅发帖,发布后不可编辑) 2-管理员(发帖、编辑、删除)',
`auth_scope` tinyint(1) NOT NULL DEFAULT 1 COMMENT '授权范围:1-本站次 2-全站',
`performance_id` varchar(64) NOT NULL DEFAULT '' COMMENT '演出ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`is_deleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0-未删除 1-已删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_admin_id` (`admin_id`),
KEY `idx_phone` (`phone`),
KEY `idx_performance_id` (`performance_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4 COMMENT ='失物招领管理员表';
-- 失物招领信息表
CREATE TABLE IF NOT EXISTS `sweet_lost_found_item`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`item_id` varchar(64) NOT NULL DEFAULT '' COMMENT '失物信息ID',
`item_image` varchar(500) NOT NULL DEFAULT '' COMMENT '物品图片URL',
`description` varchar(500) NOT NULL DEFAULT '' COMMENT '物品描述,最多120字',
`pickup_location` tinyint(1) NOT NULL DEFAULT 1 COMMENT '拾捡地:1-音乐节现场 2-其他',
`pickup_date` varchar(20) NOT NULL DEFAULT '' COMMENT '捡拾日期',
`item_type` tinyint(1) NOT NULL DEFAULT 1 COMMENT '物品类型:1-证件卡类 2-3C数码类 3-服饰类 4-其他',
`performance_id` varchar(64) NOT NULL DEFAULT '' COMMENT '演出ID',
`publisher_uid` varchar(64) NOT NULL DEFAULT '' COMMENT '发布人uid',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`is_deleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除:0-未删除 1-已删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_item_id` (`item_id`),
KEY `idx_performance_id` (`performance_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4 COMMENT ='失物招领信息表';
\ No newline at end of file
package com.liquidnet.service.sweet.controller;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.sweet.param.SweetLostFoundAdminParam;
import com.liquidnet.service.sweet.param.ValidationGroups;
import com.liquidnet.service.sweet.service.ISweetLostFoundAdminService;
import com.liquidnet.service.sweet.vo.SweetLostFoundAdminVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 失物招领管理员Controller
*
* @author liquidnet
* @since 2025-01-18
*/
@RestController
@RequestMapping("/lost-found/admin")
@Api(value = "失物招领管理员管理", tags = "失物招领管理员管理")
@Validated
public class SweetLostFoundAdminController {
@Autowired
private ISweetLostFoundAdminService sweetLostFoundAdminService;
@PostMapping("/add")
@ApiOperation("添加管理员")
public ResponseDto<Boolean> addAdmin(@RequestBody @Validated SweetLostFoundAdminParam admin) {
return sweetLostFoundAdminService.addAdmin(admin);
}
@PutMapping("/update")
@ApiOperation("编辑管理员")
public ResponseDto<Boolean> updateAdmin(@RequestBody @Validated({ValidationGroups.Update.class}) SweetLostFoundAdminParam admin) {
return sweetLostFoundAdminService.editAdmin(admin);
}
@DeleteMapping("/delete/{id}")
@ApiOperation("删除管理员")
public ResponseDto<Boolean> deleteAdmin(
@ApiParam("管理员ID") @PathVariable Long id) {
return ResponseDto.success(sweetLostFoundAdminService.deleteAdmin(id));
}
@GetMapping("/detail/{id}")
@ApiOperation("获取管理员详情")
public ResponseDto<SweetLostFoundAdminVo> getAdminDetail(
@ApiParam("管理员ID") @PathVariable Long id) {
return ResponseDto.success(sweetLostFoundAdminService.getAdminDetail(id));
}
@GetMapping("/list/{performanceId}")
@ApiOperation("获取管理员列表")
public ResponseDto<List<SweetLostFoundAdminVo>> getAdminList(@ApiParam("演出ID") @PathVariable String performanceId) {
return ResponseDto.success(sweetLostFoundAdminService.getAdminList(performanceId));
}
@GetMapping("/permission/{phone}/{performanceId}")
@ApiOperation("获取权限")
/**
* 1. 删除不能图简单直接删除两个 key 这样容易删除单站把全站的也删除掉
* 2. 不能再读取的时候读不到在查 sql 再写入 redis 这里的情况不适用,没权限的用户导致一直查 sql 了
* 另外还会导致因为权限混在一起,crud 的时候考虑的会太复杂,现在分开处理逻辑就简单些,所以要在 cu的写入 redis
*/
public ResponseDto<SweetLostFoundAdminVo> getPermission(
@ApiParam("手机号") @PathVariable String phone,
@ApiParam("演出ID") @PathVariable String performanceId) {
return ResponseDto.success(sweetLostFoundAdminService.hasPermission(phone, performanceId));
}
}
\ No newline at end of file
package com.liquidnet.service.sweet.controller;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.sweet.param.SweetLostFoundItemParam;
import com.liquidnet.service.sweet.param.ValidationGroups;
import com.liquidnet.service.sweet.service.ISweetLostFoundItemService;
import com.liquidnet.service.sweet.vo.SweetLostFoundItemVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 失物招领信息Controller
*
* @author liquidnet
* @since 2025-01-18
*/
@RestController
@RequestMapping("/lost-found/item")
@Api(value = "失物招领信息管理", tags = "失物招领信息管理")
@Validated
public class SweetLostFoundItemController {
@Autowired
private ISweetLostFoundItemService sweetLostFoundItemService;
@PostMapping("/publish")
@ApiOperation("发布失物信息")
public ResponseDto<Boolean> publishItem(@RequestBody @Validated SweetLostFoundItemParam item) {
return ResponseDto.success(sweetLostFoundItemService.publishItem(item));
}
@PutMapping("/update")
@ApiOperation("编辑失物信息")
public ResponseDto<Boolean> updateItem(@RequestBody @Validated({ValidationGroups.Update.class}) SweetLostFoundItemParam item) {
return ResponseDto.success(sweetLostFoundItemService.editItem(item));
}
@DeleteMapping("/delete/{itemId}")
@ApiOperation("删除失物信息")
public ResponseDto<Boolean> deleteItem(
@ApiParam("失物信息ID") @PathVariable Long itemId) {
return ResponseDto.success(sweetLostFoundItemService.deleteItem(itemId));
}
@GetMapping("/detail/{itemId}")
@ApiOperation("获取失物信息详情")
public ResponseDto<SweetLostFoundItemVo> getItemDetail(
@ApiParam("失物信息ID") @PathVariable Long itemId) {
return ResponseDto.success(sweetLostFoundItemService.getItemDetail(itemId));
}
@GetMapping("/list")
@ApiOperation("获取失物信息列表")
public ResponseDto<List<SweetLostFoundItemVo>> getItemList(
@ApiParam("物品类型") @RequestParam(required = false) Integer itemType,
@ApiParam("演出ID") @RequestParam String performanceId
) {
return ResponseDto.success(sweetLostFoundItemService.getItemList(itemType, performanceId));
}
}
\ No newline at end of file
......@@ -11,7 +11,10 @@ import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = "小程序-公众号登陆相关")
@RestController
......@@ -25,18 +28,20 @@ public class SweetWechatLoginController {
@GetMapping("userInfo")
@ApiOperation("小程序解密手机号")
@ApiImplicitParams({
@ApiImplicitParam(type = "query", dataType = "String", name = "code", value = "微信code", required = true),
@ApiImplicitParam(type = "query", dataType = "String", name = "encryptedData", value = "encryptedData", required = true),
@ApiImplicitParam(type = "query", dataType = "String", name = "iv", value = "iv", required = true),
@ApiImplicitParam(type = "query", dataType = "Integer", name = "type", value = "1草莓 2五百里 3mdsk 4正在 5跳飞船音乐节 6小家伙"),
@ApiImplicitParam(type = "query", dataType = "String", name = "userCode", value = " 获取 uid oid的 code"),
@ApiImplicitParam(type = "query", dataType = "String", name = "code", value = "获取手机号的 code", required = true),
@ApiImplicitParam(type = "query", dataType = "String", name = "encryptedData", value = "encryptedData"),
@ApiImplicitParam(type = "query", dataType = "String", name = "iv", value = "iv"),
@ApiImplicitParam(type = "query", dataType = "Integer", name = "type", value = "1草莓 2五百里 3mdsk 4正在 5跳飞船音乐节 6小家伙", required = true),
})
public ResponseDto userInfo(
@RequestParam(required = false) String userCode,
@RequestParam() String code,
@RequestParam() String encryptedData,
@RequestParam() String iv,
@RequestParam(required = false) String encryptedData,
@RequestParam(required = false) String iv,
@RequestParam(defaultValue = "1") Integer type
) {
return sweetLoginService.userInfo(code, encryptedData, iv, type);
return sweetLoginService.userInfo(userCode, code, encryptedData, iv, type);
}
@ApiOperation(value = "小程序获取openid", notes = "这里仅用于获取OPENID使用")
......
package com.liquidnet.service.sweet.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.sweet.entity.SweetLostFoundAdmin;
import com.liquidnet.service.sweet.mapper.SweetLostFoundAdminMapper;
import com.liquidnet.service.sweet.param.SweetLostFoundAdminParam;
import com.liquidnet.service.sweet.service.ISweetLostFoundAdminService;
import com.liquidnet.service.sweet.utils.LostFoundRedisUtils;
import com.liquidnet.service.sweet.vo.SweetLostFoundAdminVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* 失物招领管理员服务实现类
*
* @author liquidnet
* @since 2025-01-18
*/
@Service
public class SweetLostFoundAdminServiceImpl extends ServiceImpl<SweetLostFoundAdminMapper, SweetLostFoundAdmin> implements ISweetLostFoundAdminService {
@Autowired
private LostFoundRedisUtils lostFoundRedisUtils;
@Override
public ResponseDto<Boolean> addAdmin(SweetLostFoundAdminParam admin) {
String phone = admin.getPhone().trim();
String performanceId = admin.getPerformanceId().trim();
Integer authScope = admin.getAuthScope();
// 统一查询:检查当前手机号在所有相关场景下的冲突
QueryWrapper<SweetLostFoundAdmin> conflictWrapper = new QueryWrapper<>();
conflictWrapper.eq("phone", phone)
.eq("is_deleted", 0);
// 规则1:如果创建的是全站管理员,检查是否已存在全站管理员
if (authScope != null && authScope == 2) {
conflictWrapper.eq("auth_scope", 2);
}
// 规则2:如果创建的是特定演出管理员,检查是否已存在该演出记录或全站管理员
else {
conflictWrapper.and(wrapper ->
wrapper.eq("performance_id", performanceId)
.or()
.eq("auth_scope", 2)
);
}
if (baseMapper.selectCount(conflictWrapper) > 0) {
return ResponseDto.failure("该手机号已存在");
}
SweetLostFoundAdmin foundAdmin = SweetLostFoundAdmin.getNew();
foundAdmin.setAdminId(IDGenerator.nextSnowId());
foundAdmin.setPhone(phone);
foundAdmin.setName(admin.getName());
foundAdmin.setPermissionType(admin.getPermissionType());
foundAdmin.setAuthScope(admin.getAuthScope());
foundAdmin.setPerformanceId(performanceId);
boolean result = baseMapper.insert(foundAdmin) > 0;
SweetLostFoundAdminVo vo = new SweetLostFoundAdminVo();
BeanUtils.copyProperties(foundAdmin, vo);
lostFoundRedisUtils.setAdminCache(phone, performanceId, vo);
return ResponseDto.success(result);
}
// 假设:
// - 已存在记录:phone=13800138000, performanceId="A", authScope=1
// - 现在创建:phone=13800138000, performanceId="B", authScope=2
//
// 当前写法:允许创建(因为只在全站管理员场景检查)
// 建议写法:会报错(因为会查到performanceId="A"的记录)
// 假设:
// - 已存在记录:phone=13800138000, performanceId="A", authScope=2
// - 现在创建:phone=13800138000, performanceId="B", authScope=1
//
// 当前行为:会允许创建,但这可能不符合业务需求
@Override
public ResponseDto<Boolean> editAdmin(SweetLostFoundAdminParam admin) {
Long id = admin.getId();
String phone = admin.getPhone().trim();
String performanceId = admin.getPerformanceId().trim();
Integer authScope = admin.getAuthScope();
// 检查要修改的管理员是否存在
SweetLostFoundAdmin existingAdmin = baseMapper.selectById(id);
if (existingAdmin == null || existingAdmin.getIsDeleted() == 1) {
return ResponseDto.failure("管理员记录不存在或已删除");
}
// 统一查询:检查修改后手机号在所有相关场景下的冲突(排除自身)
QueryWrapper<SweetLostFoundAdmin> conflictWrapper = new QueryWrapper<>();
conflictWrapper.eq("phone", phone)
.ne("id", id)
.eq("is_deleted", 0);
// 规则1:如果修改为全站管理员,检查是否已存在全站管理员
if (authScope != null && authScope == 2) {
conflictWrapper.eq("auth_scope", 2);
}
// 规则2:如果修改为特定演出管理员,检查是否已存在该演出记录或全站管理员
else {
conflictWrapper.and(wrapper ->
wrapper.eq("performance_id", performanceId)
.or()
.eq("auth_scope", 2)
);
}
if (baseMapper.selectCount(conflictWrapper) > 0) {
return ResponseDto.failure("该手机号已存在");
}
SweetLostFoundAdmin foundAdmin = SweetLostFoundAdmin.getNew();
foundAdmin.setId(id);
foundAdmin.setPhone(phone);
foundAdmin.setName(admin.getName());
foundAdmin.setPermissionType(admin.getPermissionType());
foundAdmin.setAuthScope(admin.getAuthScope());
foundAdmin.setPerformanceId(performanceId);
// 缓存
SweetLostFoundAdminVo vo = new SweetLostFoundAdminVo();
BeanUtils.copyProperties(foundAdmin, vo);
// 因为可能会更改权限范围 写入有范围的判断 所以直接删除老的
lostFoundRedisUtils.deleteAdminCache(existingAdmin.getPhone(), existingAdmin.getPerformanceId(), existingAdmin.getAuthScope());
lostFoundRedisUtils.setAdminCache(phone, performanceId, vo);
return ResponseDto.success(baseMapper.updateById(foundAdmin) > 0);
}
@Override
public boolean deleteAdmin(Long id) {
// 检查管理员是否存在
SweetLostFoundAdmin admin = baseMapper.selectById(id);
if (admin == null) {
return false;
}
// 逻辑删除:更新is_deleted字段为1
admin.setIsDeleted(1);
lostFoundRedisUtils.deleteAdminCache(admin.getPhone(), admin.getPerformanceId(), admin.getAuthScope());
return baseMapper.updateById(admin) > 0;
}
@Override
public SweetLostFoundAdminVo getAdminDetail(Long id) {
SweetLostFoundAdmin admin = baseMapper.selectById(id);
if (admin == null || admin.getIsDeleted() == 1) {
return null;
}
SweetLostFoundAdminVo vo = new SweetLostFoundAdminVo();
BeanUtils.copyProperties(admin, vo);
return vo;
}
@Override
public List<SweetLostFoundAdminVo> getAdminList(String performanceId) {
// 构建查询条件
QueryWrapper<SweetLostFoundAdmin> queryWrapper = new QueryWrapper<>();
// 过滤逻辑删除的记录
queryWrapper.eq("is_deleted", 0);
// 查询条件:performanceId = 指定演出ID OR authScope = 2(全站)
queryWrapper.and(wrapper ->
wrapper.eq("performance_id", performanceId.trim())
.or()
.eq("auth_scope", 2)
);
// 默认按创建时间降序
queryWrapper.orderByDesc("create_time");
// 执行查询
List<SweetLostFoundAdmin> adminList = baseMapper.selectList(queryWrapper);
// 转换为VO对象
List<SweetLostFoundAdminVo> voList = adminList.stream()
.map(admin -> {
SweetLostFoundAdminVo vo = new SweetLostFoundAdminVo();
BeanUtils.copyProperties(admin, vo);
return vo;
})
.collect(Collectors.toList());
return voList;
}
@Override
public SweetLostFoundAdminVo hasPermission(String phone, String performanceId) {
SweetLostFoundAdminVo adminCache = lostFoundRedisUtils.getAdminCache(phone, performanceId);
// if (adminCache == null) {
// QueryWrapper<SweetLostFoundAdmin> queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("phone", phone.trim())
// .eq("is_deleted", 0);
// queryWrapper.and(wrapper ->
// wrapper.eq("performance_id", performanceId.trim())
// .or()
// .eq("auth_scope", 2)
// );
// SweetLostFoundAdmin admin = baseMapper.selectOne(queryWrapper);
// if (admin == null) {
// return null;
// }
// SweetLostFoundAdminVo vo = new SweetLostFoundAdminVo();
// BeanUtils.copyProperties(admin, vo);
// lostFoundRedisUtils.setAdminCache(phone, performanceId, vo);
// return vo;
// }
return adminCache;
}
}
\ No newline at end of file
package com.liquidnet.service.sweet.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.sweet.entity.SweetLostFoundItem;
import com.liquidnet.service.sweet.mapper.SweetLostFoundItemMapper;
import com.liquidnet.service.sweet.param.SweetLostFoundItemParam;
import com.liquidnet.service.sweet.service.ISweetLostFoundItemService;
import com.liquidnet.service.sweet.utils.LostFoundRedisUtils;
import com.liquidnet.service.sweet.vo.SweetLostFoundItemVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* 失物招领信息服务实现类
*
* @author liquidnet
* @since 2025-01-18
*/
@Service
public class SweetLostFoundItemServiceImpl extends ServiceImpl<SweetLostFoundItemMapper, SweetLostFoundItem> implements ISweetLostFoundItemService {
@Autowired
private LostFoundRedisUtils lostFoundRedisUtils;
@Override
public boolean publishItem(SweetLostFoundItemParam item) {
if (item == null) {
return false;
}
SweetLostFoundItem lostFoundItem = SweetLostFoundItem.getNew();
lostFoundItem.setItemId(IDGenerator.nextSnowId());
BeanUtils.copyProperties(item, lostFoundItem);
lostFoundRedisUtils.deleteItemListCache(item.getPerformanceId());
return baseMapper.insert(lostFoundItem) > 0;
}
@Override
public boolean editItem(SweetLostFoundItemParam item) {
if (item == null || item.getId() == null) {
return false;
}
SweetLostFoundItem lostFoundItem = SweetLostFoundItem.getNew();
BeanUtils.copyProperties(item, lostFoundItem);
lostFoundRedisUtils.deleteItemListCache(item.getPerformanceId());
lostFoundRedisUtils.deleteItemDetailCache(item.getId());
return baseMapper.updateById(lostFoundItem) > 0;
}
@Override
public boolean deleteItem(Long id) {
if (id == null) {
return false;
}
// 检查物品是否存在
SweetLostFoundItem item = baseMapper.selectById(id);
if (item == null || item.getIsDeleted() == 1) {
return false;
}
item.setIsDeleted(1);
lostFoundRedisUtils.deleteItemListCache(item.getPerformanceId());
return baseMapper.updateById(item) > 0;
}
@Override
public SweetLostFoundItemVo getItemDetail(Long id) {
if (id == null) {
return null;
}
SweetLostFoundItemVo itemDetail = lostFoundRedisUtils.getItemDetail(id);
if (itemDetail == null) {
SweetLostFoundItem item = baseMapper.selectById(id);
if (item == null || item.getIsDeleted() == 1) {
return null;
}
SweetLostFoundItemVo vo = new SweetLostFoundItemVo();
BeanUtils.copyProperties(item, vo);
lostFoundRedisUtils.setItemDetail(id, vo);
return vo;
}
return itemDetail;
}
@Override
public List<SweetLostFoundItemVo> getItemList(Integer itemType, String performanceId) {
List<SweetLostFoundItemVo> itemList = lostFoundRedisUtils.getItemList(performanceId, itemType);
if (itemList == null || itemList.isEmpty()) {
QueryWrapper<SweetLostFoundItem> queryWrapper = new QueryWrapper<>();
// 过滤
queryWrapper.eq("is_deleted", 0);
queryWrapper.eq("performance_id", performanceId.trim());
// 排序
queryWrapper.orderByDesc("create_time");
// 执行查询
List<SweetLostFoundItem> items = baseMapper.selectList(queryWrapper);
// 转换为VO对象列表
List<SweetLostFoundItemVo> itemVos = items.stream()
.map(item -> {
SweetLostFoundItemVo vo = new SweetLostFoundItemVo();
BeanUtils.copyProperties(item, vo);
return vo;
})
.collect(Collectors.toList());
lostFoundRedisUtils.setItemList(performanceId, itemVos);
if(null == itemType) {
return itemVos;
}
return itemVos.stream()
.filter(item -> itemType.equals(item.getItemType()))
.collect(Collectors.toList());
}
return itemList;
}
}
\ No newline at end of file
......@@ -12,13 +12,11 @@ import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.feign.adam.api.FeignAdamBaseClient;
import com.liquidnet.service.feign.stone.api.FeignStoneIntegralClient;
import com.liquidnet.service.sweet.dto.vo.WechatTokenInfoVo;
import com.liquidnet.service.sweet.dto.vo.WechatUserInfoVo;
import com.liquidnet.service.sweet.utils.QueueUtils;
import com.liquidnet.service.sweet.utils.WechatUsersRedisUtils;
import com.liquidnet.service.sweet.vo.SweetAppletUsersVo;
import com.liquidnet.service.sweet.vo.SweetWechatUsersVo;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
......@@ -58,20 +56,29 @@ public class SweetWechatLoginServiceImpl {
@Lazy
private FeignAdamBaseClient feignAdamBaseClient;
public ResponseDto userInfo(String code, String encryptedData, String iv, Integer type) {
public ResponseDto userInfo(String userCode, String code, String encryptedData, String iv, Integer type) {
log.info("小程序解密用户信息参数:[code=[{}], encryptedData=[{}], [iv=[{}], type=[{}]", code, encryptedData, iv, type);
try {
// 获取unid openid
WxMaJscode2SessionResult sessionInfo = sweetWechatService.sessionInfo(code, type);
if (null == sessionInfo) {
WxMaJscode2SessionResult sessionInfo = null;
WxMaPhoneNumberInfo wxMaPhoneNumberInfo = null;
String unionId = null;
String openId = null;
if (type == 1 && Objects.isNull(encryptedData)) {
// 获取unid openid
sessionInfo = sweetWechatService.sessionInfo(userCode, type);
// 解密手机号码信息
wxMaPhoneNumberInfo = sweetWechatService.getPhoneNumber(code, type);
} else {
sessionInfo = sweetWechatService.sessionInfo(code, type);
wxMaPhoneNumberInfo = sweetWechatService.phoneNumberInfo(sessionInfo.getSessionKey(), encryptedData, iv, type);
}
if (Objects.isNull(sessionInfo)) {
return ResponseDto.failure("login handler error");
}
String unionId = sessionInfo.getUnionid();
String openId = sessionInfo.getOpenid();
// 解密手机号码信息
WxMaPhoneNumberInfo wxMaPhoneNumberInfo = sweetWechatService.phoneNumberInfo(sessionInfo.getSessionKey(), encryptedData, iv, type);
unionId = sessionInfo.getUnionid();
openId = sessionInfo.getOpenid();
if (Objects.isNull(wxMaPhoneNumberInfo) || StringUtils.isBlank(wxMaPhoneNumberInfo.getPhoneNumber())) {
return ResponseDto.failure("解密手机信息失败");
return ResponseDto.failure("获取手机信息失败");
}
String phoneNumber = wxMaPhoneNumberInfo.getPhoneNumber();
String purePhoneNumber = wxMaPhoneNumberInfo.getPurePhoneNumber();
......
......@@ -43,6 +43,16 @@ public class SweetWechatService {
return wxMaService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
}
public WxMaPhoneNumberInfo getPhoneNumber(String code, Integer anum) {
WxMaService wxMaService = wechatMaConfigure.getWxMaService(anum);
try {
return wxMaService.getUserService().getPhoneNumber(code);
} catch (Exception e) {
log.error("getPhoneNumber error", e);
return null;
}
}
/**
* 服务号--------------
*/
......
package com.liquidnet.service.sweet.utils;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.service.sweet.vo.SweetLostFoundAdminVo;
import com.liquidnet.service.sweet.vo.SweetLostFoundItemVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* 失物招领Redis缓存工具类
*
* @author liquidnet
* @since 2025-01-18
*/
@Slf4j
@Component
public class LostFoundRedisUtils {
@Autowired
private RedisUtil redisUtil;
// Redis key前缀
private static final String LOST_FOUND_KEY_PREFIX = "sweet:lost_found:";
private static final String ITEM_LIST_KEY = LOST_FOUND_KEY_PREFIX + "item_list:";
private static final String ITEM_DETAIL_KEY = LOST_FOUND_KEY_PREFIX + "item_detail:";
private static final String ADMIN_DETAIL_KEY = LOST_FOUND_KEY_PREFIX + "admin_detail:";
// 缓存过期时间(秒)
private static final long LIST_EXPIRE_TIME = 432000; // 5天
private static final long DETAIL_EXPIRE_TIME = 432000; // 5天
/**
* 获取失物信息列表缓存
*
* @param performanceId 演出ID
* @param itemType 物品类型(可选,null表示全部)
* @return 失物信息列表
*/
public List<SweetLostFoundItemVo> getItemList(String performanceId, Integer itemType) {
try {
String key = buildItemListKey(performanceId);
Object cachedValue = redisUtil.get(key);
if (cachedValue != null) {
List<SweetLostFoundItemVo> allItems = (List<SweetLostFoundItemVo>) cachedValue;
// 如果指定了itemType,进行筛选
if (itemType != null) {
return allItems.stream()
.filter(item -> itemType.equals(item.getItemType()))
.collect(Collectors.toList());
}
return allItems;
}
} catch (Exception e) {
log.error("获取失物信息列表缓存失败", e);
}
return null;
}
/**
* 设置失物信息列表缓存
*
* @param performanceId 演出ID
* @param itemList 失物信息列表
*/
public void setItemList(String performanceId, List<SweetLostFoundItemVo> itemList) {
try {
String key = buildItemListKey(performanceId);
redisUtil.set(key, itemList, LIST_EXPIRE_TIME);
} catch (Exception e) {
log.error("设置失物信息列表缓存失败", e);
}
}
/**
* 获取失物信息详情缓存
*
* @param itemId 物品ID
* @return 失物信息详情
*/
public SweetLostFoundItemVo getItemDetail(Long itemId) {
try {
String key = ITEM_DETAIL_KEY + itemId;
Object cachedValue = redisUtil.get(key);
if (cachedValue != null) {
return (SweetLostFoundItemVo) cachedValue;
}
} catch (Exception e) {
log.error("获取失物信息详情缓存失败", e);
}
return null;
}
/**
* 设置失物信息详情缓存
*
* @param itemId 物品ID
* @param itemDetail 失物信息详情
*/
public void setItemDetail(Long itemId, SweetLostFoundItemVo itemDetail) {
try {
String key = ITEM_DETAIL_KEY + itemId;
redisUtil.set(key, itemDetail, DETAIL_EXPIRE_TIME);
} catch (Exception e) {
log.error("设置失物信息详情缓存失败", e);
}
}
/**
* 删除失物信息列表缓存
*
* @param performanceId 演出ID
*/
public void deleteItemListCache(String performanceId) {
try {
String key = buildItemListKey(performanceId);
redisUtil.del(key);
} catch (Exception e) {
log.error("删除失物信息列表缓存失败", e);
}
}
/**
* 删除失物信息详情缓存
*
* @param itemId 物品ID
*/
public void deleteItemDetailCache(Long itemId) {
try {
String key = ITEM_DETAIL_KEY + itemId;
redisUtil.del(key);
} catch (Exception e) {
log.error("删除失物信息详情缓存失败", e);
}
}
/**
* 构建失物信息列表缓存key
*
* @param performanceId 演出ID
* @return 缓存key
*/
private String buildItemListKey(String performanceId) {
return ITEM_LIST_KEY + performanceId;
}
/*private String buildItemListKey(String performanceId) {
StringBuilder keyBuilder = new StringBuilder(ITEM_LIST_KEY);
keyBuilder.append(performanceId);
return keyBuilder.toString();
}*/
/**
* 检查管理员是否存在
*
* @param phone 手机号
* @param performanceId 演出ID
* @return 是否存在
*/
public SweetLostFoundAdminVo getAdminCache(String phone, String performanceId) {
try {
// 优先检查全站管理员缓存
String globalKey = ADMIN_DETAIL_KEY + phone + ":global";
Object globalCache = redisUtil.get(globalKey);
if (globalCache != null) {
return (SweetLostFoundAdminVo) globalCache;
}
// 检查特定演出管理员缓存
String specificKey = ADMIN_DETAIL_KEY + phone + ":" + performanceId;
Object specificCache = redisUtil.get(specificKey);
if (specificCache != null) {
return (SweetLostFoundAdminVo) specificCache;
}
} catch (Exception e) {
log.error("检查管理员缓存失败", e);
}
return null;
}
/**
* 设置管理员缓存
*
* @param phone 手机号
* @param performanceId 演出ID
* @param vo 管理员信息
*/
public void setAdminCache(String phone, String performanceId, SweetLostFoundAdminVo vo) {
try {
if (vo.getAuthScope() != null && vo.getAuthScope() == 2) {
// 全站管理员使用全局缓存键
String globalKey = ADMIN_DETAIL_KEY + phone + ":global";
redisUtil.set(globalKey, vo, DETAIL_EXPIRE_TIME);
} else {
// 特定演出管理员使用演出特定的缓存键
String specificKey = ADMIN_DETAIL_KEY + phone + ":" + performanceId;
redisUtil.set(specificKey, vo, DETAIL_EXPIRE_TIME);
}
} catch (Exception e) {
log.error("设置管理员缓存失败", e);
}
}
/**
* 删除管理员缓存
*
* @param phone 手机号
* @param performanceId 演出ID
*/
public void deleteAdminCache(String phone, String performanceId, Integer authScope) {
try {
if (authScope != null && authScope == 1) {
// 删除特定演出管理员缓存
String specificKey = ADMIN_DETAIL_KEY + phone + ":" + performanceId;
redisUtil.del(specificKey);
} else if (authScope != null && authScope == 2) {
// 删除全站管理员缓存
String globalKey = ADMIN_DETAIL_KEY + phone + ":global";
redisUtil.del(globalKey);
} else {
String specificKey = ADMIN_DETAIL_KEY + phone + ":" + performanceId;
redisUtil.del(specificKey);
String globalKey = ADMIN_DETAIL_KEY + phone + ":global";
redisUtil.del(globalKey);
}
} catch (Exception e) {
log.error("删除管理员缓存失败", e);
}
}
}
\ No newline at end of file
......@@ -280,7 +280,7 @@
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
<version>4.1.0</version>
<version>4.7.0</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
......
......@@ -20,8 +20,8 @@ liquidnet:
# username: admin
# password: admin
config:
# location: /Users/hujiachen/IdeaProjects/liquidnet-bus-v1/liquidnet-bus-config/liquidnet-config
location: /Users/jiangxiulong/IdeaProjects/liquidnet-bus-v1/liquidnet-bus-config/liquidnet-config
# location: /Users/jiangxiulong/IdeaProjects/liquidnet-bus-v1/liquidnet-bus-config/liquidnet-config
location: /app/support-config
# end-dev-这里是配置信息基本值
spring:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment