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

Commit 78f562bf authored by 姜秀龙's avatar 姜秀龙

100032-100037 bug 修复

parent ae5cdba0
......@@ -20,6 +20,12 @@ public class AdamCaomeiBadgeSearchParam {
@ApiModelProperty(value = "上架状态: 0-下架(默认), 1-已发布")
private Integer displayStatus;
@ApiModelProperty(value = "添加时间起(yyyy-MM-dd)")
private String createdAtBegin;
@ApiModelProperty(value = "添加时间止(yyyy-MM-dd)")
private String createdAtEnd;
@ApiModelProperty(value = "当前页码")
private Integer pageNum = 1;
......
......@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
@ApiModel("草莓护照-补签审核详情")
......@@ -39,6 +40,9 @@ public class AdamCaomeiBadgeApplyAuditDetailVo {
@ApiModelProperty(value = "申请附件")
private String proofImageUrl;
@ApiModelProperty(value = "申请附件 URL 列表(解析自原始字段)")
private List<String> proofImageUrls;
@ApiModelProperty(value = "审核状态:0-待审核 1-已通过 2-已驳回")
private Integer auditStatus;
......
......@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
@ApiModel("草莓护照-补签审核列表")
......@@ -33,6 +34,9 @@ public class AdamCaomeiBadgeApplyAuditVo {
@ApiModelProperty(value = "申请附件")
private String proofImageUrl;
@ApiModelProperty(value = "申请附件 URL 列表(解析自原始字段)")
private List<String> proofImageUrls;
@ApiModelProperty(value = "审核状态:0-待审核 1-已通过 2-已驳回")
private Integer auditStatus;
......
......@@ -23,6 +23,7 @@ import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.Objects;
@Api(tags = "草莓护照-徽章管理")
@Controller
@RequestMapping("adam/caomei/badge")
......@@ -30,6 +31,8 @@ public class AdamCaomeiBadgeController extends BaseController {
private final String prefix = "zhengzai/adam/caomei/badge";
private static final int BADGE_NAME_MAX_CHARS = 20;
@Autowired
private IAdamCaomeiBadgeAdminService adamCaomeiBadgeAdminService;
......@@ -59,8 +62,21 @@ public class AdamCaomeiBadgeController extends BaseController {
@PostMapping("add")
@ResponseBody
public AjaxResult addSave(AdamCaomeiBadgeParam param) {
if (param == null) {
return error("参数错误");
}
AjaxResult nameCheck = validateBadgeName(param.getName());
if (nameCheck != null) {
return nameCheck;
}
String trimmedName = StringUtils.trimToEmpty(param.getName());
if (adamCaomeiBadgeAdminService.existsOtherBadgeWithSameName(trimmedName, null)) {
return error("徽章名称已存在,请勿重复");
}
AdamCaomeiBadge badge = new AdamCaomeiBadge();
BeanUtils.copyProperties(param, badge);
badge.setName(trimmedName);
badge.setShareText(StringUtils.defaultString(badge.getShareText()));
badge.setBadgeId(IDGenerator.nextSnowId());
badge.setDisplayStatus(0); // 默认下架
......@@ -72,9 +88,14 @@ public class AdamCaomeiBadgeController extends BaseController {
// 演出类型校验
if (badge.getType() != null && badge.getType() == 2) {
if (StringUtils.isBlank(badge.getPerformanceId())) {
String pid = StringUtils.trimToEmpty(badge.getPerformanceId());
if (StringUtils.isBlank(pid)) {
return error("演出纪念徽章必须关联演出");
}
badge.setPerformanceId(pid);
if (!adamCaomeiBadgeAdminService.kylinPerformanceExists(pid)) {
return error("无相关演出");
}
} else {
badge.setPerformanceId("");
}
......@@ -123,18 +144,45 @@ public class AdamCaomeiBadgeController extends BaseController {
@PostMapping("edit")
@ResponseBody
public AjaxResult editSave(AdamCaomeiBadgeParam param) {
if (param == null || StringUtils.isBlank(param.getBadgeId())) {
return error("参数错误");
}
AdamCaomeiBadge oldBadge = adamCaomeiBadgeAdminService.getOne(
Wrappers.lambdaQuery(AdamCaomeiBadge.class).eq(AdamCaomeiBadge::getBadgeId, param.getBadgeId()), false
);
if (oldBadge == null || oldBadge.getDisplayStatus() == 1) {
return error("已发布的徽章不允许修改");
}
AjaxResult nameCheck = validateBadgeName(param.getName());
if (nameCheck != null) {
return nameCheck;
}
String trimmedName = StringUtils.trimToEmpty(param.getName());
if (adamCaomeiBadgeAdminService.existsOtherBadgeWithSameName(trimmedName, param.getBadgeId())) {
return error("徽章名称已存在,请勿重复");
}
if (!Objects.equals(param.getType(), oldBadge.getType())) {
return error("徽章类型不允许修改");
}
AdamCaomeiBadge badge = new AdamCaomeiBadge();
BeanUtils.copyProperties(param, badge);
badge.setName(trimmedName);
badge.setShareText(StringUtils.defaultString(badge.getShareText()));
badge.setMid(oldBadge.getMid());
badge.setUpdatedAt(new java.util.Date());
if (badge.getType() != null && badge.getType() != 2) {
// 徽章类型与「已发布不可改」一致:编辑时不允许变更类型
badge.setType(oldBadge.getType());
if (badge.getType() != null && badge.getType() == 2) {
String pid = StringUtils.trimToEmpty(badge.getPerformanceId());
if (StringUtils.isBlank(pid)) {
return error("演出纪念徽章必须关联演出");
}
badge.setPerformanceId(pid);
if (!adamCaomeiBadgeAdminService.kylinPerformanceExists(pid)) {
return error("无相关演出");
}
} else {
badge.setPerformanceId("");
}
return toAjax(adamCaomeiBadgeAdminService.updateById(badge));
......@@ -157,4 +205,19 @@ public class AdamCaomeiBadgeController extends BaseController {
updateBadge.setUpdatedAt(new java.util.Date());
return toAjax(adamCaomeiBadgeAdminService.updateById(updateBadge));
}
/**
* @return 校验通过返回 null,否则返回错误 AjaxResult
*/
private AjaxResult validateBadgeName(String name) {
String n = StringUtils.trimToEmpty(name);
if (StringUtils.isBlank(n)) {
return error("徽章名称不能为空");
}
int len = n.codePointCount(0, n.length());
if (len > BADGE_NAME_MAX_CHARS) {
return error("徽章名称不能超过" + BADGE_NAME_MAX_CHARS + "个字");
}
return null;
}
}
......@@ -9,7 +9,7 @@
<div class="form-group">
<label class="col-sm-3 control-label is-required">徽章名称:</label>
<div class="col-sm-8">
<input name="name" class="form-control" type="text" required>
<input name="name" class="form-control" type="text" maxlength="20" required placeholder="最多20个字">
</div>
</div>
<div class="form-group">
......
......@@ -10,7 +10,7 @@
<div class="form-group">
<label class="col-sm-3 control-label is-required">徽章名称:</label>
<div class="col-sm-8">
<input name="name" th:field="*{name}" class="form-control" type="text" required>
<input name="name" th:field="*{name}" class="form-control" type="text" maxlength="20" required placeholder="最多20个字">
</div>
</div>
<div class="form-group">
......@@ -22,12 +22,12 @@
<div class="form-group">
<label class="col-sm-3 control-label is-required">徽章类型:</label>
<div class="col-sm-8">
<select name="type" class="form-control m-b" th:field="*{type}" required onchange="typeChange(this.value)">
<option value="">请选择</option>
<option value="1">护照纪念徽章</option>
<option value="2">演出纪念徽章</option>
<!-- <option value="3">特殊徽章</option> -->
<input type="hidden" name="type" th:value="*{type}"/>
<select class="form-control m-b" disabled>
<option th:selected="${badge.type == 1}" value="1">护照纪念徽章</option>
<option th:selected="${badge.type == 2}" value="2">演出纪念徽章</option>
</select>
<span class="help-block m-b-none"><i class="fa fa-info-circle"></i> 徽章类型保存后不可修改</span>
</div>
</div>
<div class="form-group">
......@@ -56,7 +56,7 @@
var prefix = ctx + "adam/caomei/badge";
function typeChange(val) {
if (val == 2) {
if (val == 2 || val == '2') {
$("#ticketTimesDiv").show();
$("#performanceId").prop("required", true);
} else {
......@@ -66,6 +66,10 @@
}
}
$(function () {
typeChange($('input[name="type"]').val());
});
$("#form-badge-edit").validate({
focusCleanup: true
});
......
......@@ -28,6 +28,12 @@
<option value="1">已发布</option>
</select>
</li>
<li class="select-time">
<label>添加时间:</label>
<input type="text" class="time-input" id="badgeCreatedBegin" placeholder="开始日期" name="createdAtBegin"/>
<span> - </span>
<input type="text" class="time-input" id="badgeCreatedEnd" placeholder="结束日期" name="createdAtEnd"/>
</li>
<li>
<a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;搜索</a>
<a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;重置</a>
......
......@@ -22,9 +22,9 @@
<tr>
<td>申请附件</td>
<td>
<span th:if="${detail.proofImageUrl == null or detail.proofImageUrl == ''}">-</span>
<a th:if="${detail.proofImageUrl != null and detail.proofImageUrl != ''}" th:href="${detail.proofImageUrl}" target="_blank">
<img th:src="${detail.proofImageUrl}" style="max-height: 90px; border-radius: 4px;"/>
<span th:if="${detail.proofImageUrls == null or detail.proofImageUrls.isEmpty()}">-</span>
<a th:each="u : ${detail.proofImageUrls}" th:href="${u}" target="_blank" style="display:inline-block;margin:0 8px 8px 0;">
<img th:src="${u}" style="max-height: 90px; border-radius: 4px;"/>
</a>
</td>
</tr>
......
......@@ -59,9 +59,19 @@
field: 'proofImageUrl',
title: '申请附件',
align: 'center',
formatter: function(value) {
if (!value) return '-';
return '<img src="' + value + '" style="height:32px;max-width:60px;cursor:pointer;border-radius:3px;" onclick=\'viewImage(' + JSON.stringify(value) + ')\' />';
formatter: function(value, row) {
var urls = row.proofImageUrls;
if (!urls || urls.length === 0) {
if (!value) return '-';
urls = [value];
}
var html = [];
for (var i = 0; i < urls.length; i++) {
var u = urls[i];
if (!u) continue;
html.push('<a href="' + u + '" target="_blank" title="查看原图"><img src="' + u + '" style="height:32px;max-width:60px;margin:0 2px;cursor:pointer;border-radius:3px;"/></a>');
}
return html.length ? html.join('') : '-';
}
},
{
......@@ -93,10 +103,6 @@
$.table.init(options);
});
function viewImage(url) {
window.open(url, "_blank");
}
function detail(applyRecordId) {
$.modal.open("补签详情", prefix + "/detail/" + encodeURIComponent(applyRecordId));
}
......
......@@ -32,4 +32,17 @@ public interface IAdamCaomeiBadgeAdminService extends IService<AdamCaomeiBadge>
* 后台新增/编辑/上下架成功后应调用,避免用户端仍读到旧列表。
*/
void delPublishedCaomeiBadges();
/**
* kylin 演出是否存在(performances_id)
*/
boolean kylinPerformanceExists(String performancesId);
/**
* 是否存在与名称相同的其他徽章(trim 后精确匹配)
*
* @param name 徽章名称
* @param excludeBadgeId 编辑时排除当前徽章 ID;新增传 null 或空
*/
boolean existsOtherBadgeWithSameName(String name, String excludeBadgeId);
}
......@@ -15,12 +15,17 @@ import com.liquidnet.service.adam.dto.vo.AdamCaomeiBadgeClaimUserVo;
import com.liquidnet.service.adam.dto.vo.AdamCaomeiBadgeVo;
import com.liquidnet.service.adam.entity.AdamCaomeiBadge;
import com.liquidnet.service.adam.mapper.AdamCaomeiBadgeMapper;
import com.liquidnet.service.kylin.entity.KylinPerformances;
import com.liquidnet.service.kylin.mapper.KylinPerformancesMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.List;
import java.util.Map;
......@@ -33,6 +38,9 @@ public class AdamCaomeiBadgeAdminServiceImpl extends ServiceImpl<AdamCaomeiBadge
@Autowired
private RedisDataSourceUtil redisDataSourceUtil;
@Autowired
private KylinPerformancesMapper kylinPerformancesMapper;
@Override
public void delPublishedCaomeiBadges() {
redisDataSourceUtil.getRedisAdamUtil().del(AdamRedisConst.INFO_CAOMEI_BADGE_PUBLISHED);
......@@ -56,6 +64,31 @@ public class AdamCaomeiBadgeAdminServiceImpl extends ServiceImpl<AdamCaomeiBadge
return ok;
}
@Override
public boolean kylinPerformanceExists(String performancesId) {
String id = StringUtils.trimToEmpty(performancesId);
if (StringUtils.isBlank(id)) {
return false;
}
int c = kylinPerformancesMapper.selectCount(
Wrappers.lambdaQuery(KylinPerformances.class).eq(KylinPerformances::getPerformancesId, id)
);
return c > 0;
}
@Override
public boolean existsOtherBadgeWithSameName(String name, String excludeBadgeId) {
String n = StringUtils.trimToEmpty(name);
if (StringUtils.isBlank(n)) {
return false;
}
LambdaQueryWrapper<AdamCaomeiBadge> w = Wrappers.lambdaQuery(AdamCaomeiBadge.class).eq(AdamCaomeiBadge::getName, n);
if (StringUtils.isNotBlank(excludeBadgeId)) {
w.ne(AdamCaomeiBadge::getBadgeId, excludeBadgeId.trim());
}
return this.count(w) > 0;
}
@Override
public PageInfo<AdamCaomeiBadgeVo> listWithClaimedCount(AdamCaomeiBadgeSearchParam param) {
LambdaQueryWrapper<AdamCaomeiBadge> queryWrapper = Wrappers.lambdaQuery(AdamCaomeiBadge.class);
......@@ -68,6 +101,22 @@ public class AdamCaomeiBadgeAdminServiceImpl extends ServiceImpl<AdamCaomeiBadge
if (param.getDisplayStatus() != null) {
queryWrapper.eq(AdamCaomeiBadge::getDisplayStatus, param.getDisplayStatus());
}
if (StringUtils.isNotBlank(param.getCreatedAtBegin())) {
try {
LocalDate d = LocalDate.parse(param.getCreatedAtBegin().trim());
queryWrapper.ge(AdamCaomeiBadge::getCreatedAt, Timestamp.valueOf(d.atStartOfDay()));
} catch (DateTimeParseException e) {
log.warn("invalid createdAtBegin: {}", param.getCreatedAtBegin());
}
}
if (StringUtils.isNotBlank(param.getCreatedAtEnd())) {
try {
LocalDate d = LocalDate.parse(param.getCreatedAtEnd().trim());
queryWrapper.le(AdamCaomeiBadge::getCreatedAt, Timestamp.valueOf(d.atTime(23, 59, 59)));
} catch (DateTimeParseException e) {
log.warn("invalid createdAtEnd: {}", param.getCreatedAtEnd());
}
}
queryWrapper.orderByDesc(AdamCaomeiBadge::getSort, AdamCaomeiBadge::getUpdatedAt);
List<AdamCaomeiBadge> badges = this.list(queryWrapper);
......
......@@ -3,6 +3,7 @@ package com.liquidnet.client.admin.zhengzai.adam.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import com.liquidnet.client.admin.zhengzai.adam.service.IAdamCaomeiBadgeApplyAuditAdminService;
import com.liquidnet.client.admin.zhengzai.adam.util.CaomeiBadgeApplyProofUrls;
import com.liquidnet.service.adam.dto.AdamCaomeiBadgeApplyAuditDetailDto;
import com.liquidnet.service.adam.dto.AdamCaomeiBadgeApplyAuditDto;
import com.liquidnet.service.adam.dto.param.AdamCaomeiBadgeApplyAuditSearchParam;
......@@ -39,6 +40,7 @@ public class AdamCaomeiBadgeApplyAuditAdminServiceImpl implements IAdamCaomeiBad
AdamCaomeiBadgeApplyAuditVo vo = new AdamCaomeiBadgeApplyAuditVo();
BeanUtils.copyProperties(item, vo);
vo.setIdCard(maskIdCard(item.getIdCard()));
vo.setProofImageUrls(CaomeiBadgeApplyProofUrls.parse(item.getProofImageUrl()));
return vo;
}).collect(Collectors.toList());
PageInfo<AdamCaomeiBadgeApplyAuditVo> voPage = new PageInfo<>(voList);
......@@ -58,6 +60,7 @@ public class AdamCaomeiBadgeApplyAuditAdminServiceImpl implements IAdamCaomeiBad
AdamCaomeiBadgeApplyAuditDetailVo vo = new AdamCaomeiBadgeApplyAuditDetailVo();
BeanUtils.copyProperties(detail, vo);
vo.setIdCard(maskIdCard(detail.getIdCard()));
vo.setProofImageUrls(CaomeiBadgeApplyProofUrls.parse(detail.getProofImageUrl()));
return vo;
}
......
package com.liquidnet.client.admin.zhengzai.adam.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* 补签申请附件 URL 解析(支持逗号/分号/换行分隔或 JSON 字符串数组)。
*/
public final class CaomeiBadgeApplyProofUrls {
private CaomeiBadgeApplyProofUrls() {
}
public static List<String> parse(String raw) {
if (StringUtils.isBlank(raw)) {
return Collections.emptyList();
}
String t = raw.trim();
if (t.startsWith("[") && t.endsWith("]")) {
try {
JSONArray arr = JSON.parseArray(t);
if (arr != null && !arr.isEmpty()) {
Set<String> seen = new LinkedHashSet<>();
for (int i = 0; i < arr.size(); i++) {
String u = StringUtils.trimToEmpty(arr.getString(i));
if (StringUtils.isNotBlank(u)) {
seen.add(u);
}
}
return new ArrayList<>(seen);
}
} catch (Exception ignored) {
// fall through to delimiter split
}
}
String[] parts = t.split("[,;\\n]+");
List<String> out = new ArrayList<>();
for (String p : parts) {
String u = StringUtils.trimToEmpty(p);
if (StringUtils.isNotBlank(u)) {
out.add(u);
}
}
return out;
}
}
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