This commit is contained in:
2026-04-03 10:33:55 +08:00
parent 765c715d28
commit e179abf716
5 changed files with 335 additions and 0 deletions
@@ -0,0 +1,76 @@
package com.budwk.app.zhgh.activity.trainSignUp.controller.manage;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpAnnualLimitConfig;
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpAnnualLimitConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.ArrayList;
import java.util.List;
@IocBean
@Ok("json:full")
@Api(tags = "活动类型年度报名次数配置")
@At("/platform/trainSignUp/annualLimit")
public class TrainSignUpAnnualLimitConfigController {
@Inject
private TrainSignUpAnnualLimitConfigService annualLimitConfigService;
@At("")
@SaCheckPermission("trainSignUp.type")
@Ok("beetl:/platform/zhgh/activity/trainSignUp/annualLimit/index.html")
public void index() {
}
@At
@ApiOperation("查询活动类型年度报名次数配置")
@SaCheckPermission("trainSignUp.type")
public Result listData() {
return Result.success(annualLimitConfigService.listAnnualLimitConfig());
}
@At
@ApiOperation("保存活动类型年度报名次数配置")
@SaCheckPermission("trainSignUp.type")
@SLog(tag = "品牌活动-活动类型年度报名次数配置", msg = "保存活动类型年度报名次数配置")
public Result save(@Param("configList") String configListJson) {
List<NutMap> configMapList = Json.fromJsonAsList(NutMap.class, configListJson);
if (Lang.isEmpty(configMapList)) {
return Result.error("配置信息不能为空");
}
List<TrainSignUpAnnualLimitConfig> configList = new ArrayList<>();
// 保存时只提取配置真正需要的字段,避免页面展示字段变化影响后端解析。
for (NutMap configMap : configMapList) {
TrainSignUpAnnualLimitConfig config = new TrainSignUpAnnualLimitConfig();
config.setId(configMap.getString("id"));
config.setTrainType(configMap.getString("trainType"));
config.setAnnualLimitCount(configMap.getInt("annualLimitCount"));
configList.add(config);
}
for (TrainSignUpAnnualLimitConfig config : configList) {
if (config == null || Lang.isEmpty(config.getTrainType())) {
return Result.error("活动类型不能为空");
}
if (config == null || config.getAnnualLimitCount() == null) {
return Result.error("每年报名次数不能为空");
}
if (config.getAnnualLimitCount() <= 0) {
return Result.error("每年报名次数必须大于0");
}
}
annualLimitConfigService.saveAnnualLimitConfig(configList);
return Result.success("保存成功");
}
}
@@ -0,0 +1,49 @@
package com.budwk.app.zhgh.activity.trainSignUp.models;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.ColDefine;
import org.nutz.dao.entity.annotation.ColType;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Comment;
import org.nutz.dao.entity.annotation.Index;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.entity.annotation.TableIndexes;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.io.Serial;
import java.io.Serializable;
/**
* 活动类型年度报名次数配置。
* 一条配置对应一个活动类型编码,用于控制当前年度该活动类型可报名的活动次数。
*/
@Data
@Accessors(chain = true)
@Comment("品牌活动活动类型年度报名次数配置")
@Table("train_sign_up_annual_limit_config")
@TableIndexes({@Index(name = "INDEX_TRAIN_SIGN_UP_ANNUAL_LIMIT_CONFIG_TYPE", fields = {"trainType"}, unique = true)})
@EqualsAndHashCode(callSuper = false)
public class TrainSignUpAnnualLimitConfig implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Name
@Comment("id")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("活动类型编码")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String trainType;
@Column
@Comment("每年可报名次数")
@ColDefine(type = ColType.INT, width = 10)
private Integer annualLimitCount;
}
@@ -0,0 +1,40 @@
package com.budwk.app.zhgh.activity.trainSignUp.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpAnnualLimitConfig;
import org.nutz.lang.util.NutMap;
import java.util.List;
public interface TrainSignUpAnnualLimitConfigService extends BaseService<TrainSignUpAnnualLimitConfig> {
/**
* 默认年度报名次数。
* 当活动类型尚未配置次数时,沿用当前系统原有默认行为,避免未配置时直接放开限制。
*/
int DEFAULT_ANNUAL_LIMIT_COUNT = 2;
/**
* 查询活动类型年度报名次数配置列表。
* 页面展示时需要把活动类型字典与已保存配置合并,所以返回带名称的结构化数据。
*
* @return 活动类型与年度报名次数配置列表
*/
List<NutMap> listAnnualLimitConfig();
/**
* 保存活动类型年度报名次数配置。
* 这里按活动类型编码逐条更新,不存在则新增,保证页面整表提交时可以直接落库。
*
* @param configList 配置列表
*/
void saveAnnualLimitConfig(List<TrainSignUpAnnualLimitConfig> configList);
/**
* 获取指定活动类型的年度报名次数限制。
*
* @param trainType 活动类型编码
* @return 配置值;若未配置,则返回默认值
*/
int getAnnualLimitCount(String trainType);
}
@@ -0,0 +1,80 @@
package com.budwk.app.zhgh.activity.trainSignUp.service.impl;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_dict;
import com.budwk.app.sys.services.SysDictService;
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpAnnualLimitConfig;
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpAnnualLimitConfigService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
public class TrainSignUpAnnualLimitConfigServiceImpl extends BaseServiceImpl<TrainSignUpAnnualLimitConfig> implements TrainSignUpAnnualLimitConfigService {
@Inject
private SysDictService dictService;
public TrainSignUpAnnualLimitConfigServiceImpl(Dao dao) {
super(dao);
}
@Override
public List<NutMap> listAnnualLimitConfig() {
List<Sys_dict> trainTypeList = dictService.getSubListByCode("TRAIN_SIGNUP_TYPE");
List<TrainSignUpAnnualLimitConfig> configList = query(Cnd.NEW());
Map<String, TrainSignUpAnnualLimitConfig> configMap = configList.stream()
.collect(Collectors.toMap(TrainSignUpAnnualLimitConfig::getTrainType, item -> item, (left, right) -> left));
// 页面需要展示全部活动类型,所以以字典为准进行补齐;未配置时回落到默认值。
return trainTypeList.stream().map(item -> {
TrainSignUpAnnualLimitConfig config = configMap.get(item.getCode());
return NutMap.NEW()
.addv("id", config != null ? config.getId() : null)
.addv("trainType", item.getCode())
.addv("trainTypeName", item.getName())
.addv("annualLimitCount", config != null && config.getAnnualLimitCount() != null ? config.getAnnualLimitCount() : DEFAULT_ANNUAL_LIMIT_COUNT);
}).toList();
}
@Override
public void saveAnnualLimitConfig(List<TrainSignUpAnnualLimitConfig> configList) {
if (Lang.isEmpty(configList)) {
return;
}
List<TrainSignUpAnnualLimitConfig> dbConfigList = query(Cnd.NEW());
Map<String, TrainSignUpAnnualLimitConfig> dbConfigMap = dbConfigList.stream()
.collect(Collectors.toMap(TrainSignUpAnnualLimitConfig::getTrainType, item -> item, (left, right) -> left));
for (TrainSignUpAnnualLimitConfig config : configList) {
if (config == null || StrUtil.isBlank(config.getTrainType())) {
continue;
}
TrainSignUpAnnualLimitConfig dbConfig = dbConfigMap.get(config.getTrainType());
if (dbConfig != null) {
config.setId(dbConfig.getId());
}
insertOrUpdate(config);
}
}
@Override
public int getAnnualLimitCount(String trainType) {
if (StrUtil.isBlank(trainType)) {
return DEFAULT_ANNUAL_LIMIT_COUNT;
}
TrainSignUpAnnualLimitConfig config = fetch(Cnd.where("trainType", "=", trainType));
if (config == null || config.getAnnualLimitCount() == null || config.getAnnualLimitCount() <= 0) {
return DEFAULT_ANNUAL_LIMIT_COUNT;
}
return config.getAnnualLimitCount();
}
}
@@ -0,0 +1,90 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.page-tip {
color: #c64120;
line-height: 24px;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<div class="left-span-label">活动类型年度报名次数配置</div>
<div class="page-tip mt10">
注:这里配置的是“同一活动类型在同一年度内最多可报名多少次”。未单独配置过的活动类型默认按 2 次处理。
</div>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="配置列表"></table-tool>
<el-form ref="formRef" :model="formData">
<el-table :data="formData.configList">
<el-table-column label="序号" type="index" width="80"></el-table-column>
<el-table-column label="活动类型" prop="trainTypeName"></el-table-column>
<el-table-column label="活动类型编码" prop="trainType"></el-table-column>
<el-table-column label="每年可报名次数" prop="annualLimitCount" width="220">
<template v-slot="{row}">
<el-input-number v-model="row.annualLimitCount" :min="1" :precision="0" :step="1"></el-input-number>
</template>
</el-table-column>
</el-table>
</el-form>
<div style="margin-top: 20px; text-align: right">
<el-button type="primary" @click="onSave">保 存</el-button>
</div>
</el-card>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: '#app',
data: function () {
return {
formData: {
configList: []
}
}
},
methods: {
fetchData: function () {
this.$axios.post('/platform/trainSignUp/annualLimit/listData').then((res) => {
if (res.code === 0) {
this.formData.configList = res.data
} else {
this.$message.warning(res.msg)
}
})
},
onSave: function () {
var hasInvalidData = this.formData.configList.some(function (item) {
return !item.annualLimitCount || item.annualLimitCount <= 0
})
if (hasInvalidData) {
this.$message.warning('每年可报名次数必须大于0')
return
}
// 页面直接按活动类型整表提交,后端会按活动类型编码进行新增或更新。
this.$axios.post('/platform/trainSignUp/annualLimit/save', {
configList: JSON.stringify(this.formData.configList)
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.fetchData()
} else {
this.$message.warning(res.msg)
}
})
}
},
created: function () {
this.fetchData()
}
})
</script>
<!--#
}
#-->