生日祝福修改

This commit is contained in:
2026-09-10 17:24:55 +08:00
parent 3fc338af1e
commit 2353998794
4 changed files with 185 additions and 73 deletions
@@ -3,10 +3,6 @@ package com.budwk.app.sys.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
@@ -49,7 +45,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
;
@@ -60,8 +55,6 @@ import java.util.Map;
@At("/platform/sys/unit")
public class SysUnitController {
private static final Log log = Logs.get();
/** 浙江交通职业技术学院在 sys_unit 中的单位主键,作为单位树未指定 pid 时的默认根。 */
private static final String DEFAULT_UNIT_ROOT_ID = "4133012036";
@Inject
private SysUnitService sysUnitService;
@Inject
@@ -78,20 +71,17 @@ public class SysUnitController {
}
/**
* @param pageForm 分页参数,pageNumber 为页码,pageSize 为每页条数
* @param unitName 单位名称模糊查询条件,可为空
* @param unitId 上级单位ID,可为空;为空时保留原有单位范围
* @return Resultdata.list 为按生日祝福编号排序的单位,data.totalCount 为总条数
*/
@At("/pageData")
@Ok("json")
@SaCheckLogin
public Object pageData(PageForm pageForm, String unitName, String unitId) {
Cnd cnd = Cnd.NEW();
// cnd.and("parentId", "is not", null).andEX("unitLevel", "=", unitLevel).asc("unitLevel").asc("unitcode");
cnd.and("parentId", "is not", null);
cnd.andEX("parentId", "=", unitId);
// cnd.and("unitTypeCode", "=", "1");
cnd.asc("unitcode");
cnd.and(Cnd.likeEX("name", unitName));
Pagination<Sys_unit> listPage = sysUnitService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), Sys_unit.class, cnd);
return Result.success(listPage);
return Result.success(sysUnitService.pageUnits(pageForm, unitName, unitId));
}
@At("/userPageData")
@@ -297,43 +287,34 @@ public class SysUnitController {
}
}
/**
* @param pid 单位树根ID;为空时使用学校默认根节点
* @param req 当前请求上下文
* @return Resultdata 为含 id、parentId、name、unitTypeCode、children 的单位树列表
*/
@At("/tree")
@Ok("json")
@SaCheckLogin
public Object tree(@Param("pid") String pid, HttpServletRequest req) {
try {
String rootId = StrUtil.blankToDefault(pid, DEFAULT_UNIT_ROOT_ID);
String virtualRootId = "root";
Cnd cnd = Cnd.NEW();
cnd.asc("unitcode");
List<Sys_unit> list = sysUnitService.query(cnd);
List<TreeNode<String>> nodeList = CollUtil.newArrayList();
for (int i = 0; i < list.size(); i++) {
Sys_unit unit = list.get(i);
/*
* 单位根节点存在 id 与 parentId 都为 0 的自引用数据。
* 构建树时把当前查询根挂到虚拟根下,避免“中国地质大学”和 parentId=0 的学院被构造成同级。
*/
String parentId = rootId.equals(unit.getId()) ? virtualRootId : unit.getParentId();
nodeList.add(new TreeNode<>(unit.getId(), parentId, unit.getName(), i)
.setExtra(
Map.of(
"unitTypeCode", unit.getUnitTypeCode()
)
));
}
List<Tree<String>> treeList = TreeUtil.build(nodeList, virtualRootId);
return Result.success(treeList);
return Result.success(sysUnitService.getUnitTree(pid));
} catch (Exception e) {
log.error("单位树加载失败,路径=/platform/sys/unit/treepid=" + pid, e);
return Result.error();
}
}
/**
* @param unit 单位表单;name/unitcode 为名称和编码,aliasName 为最长100字简称,birthdaySortNo 为可空整数编号
* @param parentId 上级单位ID,新建时决定所属单位
* @param req 请求上下文;编辑时 birthdaySortNo 传空表示清空,未传表示保留
* @return Resultcode=0 表示保存成功,msg 为操作提示
*/
@At
@Ok("json")
@SaCheckPermission("sys.manager.unit.add")
@SLog(tag = "新建单位", msg = "单位名称:${args[0].name}")
@Aop(TransAop.READ_COMMITTED)
public Object addDo(@Param("..") Sys_unit unit, @Param("parentId") String parentId, HttpServletRequest req) {
try {
if ("root".equals(parentId)) {
@@ -343,6 +324,7 @@ public class SysUnitController {
sysUnitService.save(unit, parentId);
return Result.success();
} catch (Exception e) {
log.error("单位保存失败,接口=addDo,单位ID=" + unit.getId(), e);
return Result.error();
}
}
@@ -373,16 +355,24 @@ public class SysUnitController {
}
}
/**
* @param unit 单位表单;name/unitcode 为名称和编码,aliasName 为最长100字简称,birthdaySortNo 为可空整数编号
* @param parentId 上级单位ID,新建时决定所属单位
* @param req 请求上下文;编辑时 birthdaySortNo 传空表示清空,未传表示保留
* @return Resultcode=0 表示保存成功,msg 为操作提示
*/
@At
@Ok("json")
@SaCheckPermission("sys.manager.unit.edit")
@SLog(tag = "编辑单位", msg = "单位名称:${args[0].name}")
@Aop(TransAop.READ_COMMITTED)
public Object editDo(@Param("..") Sys_unit unit, @Param("parentId") String parentId, HttpServletRequest req) {
try {
unit.setUpdatedBy(SecurityUtil.getUserId());
sysUnitService.updateIgnoreNull(unit);
sysUnitService.updateUnit(unit, req.getParameter("birthdaySortNo") != null);
return Result.success();
} catch (Exception e) {
log.error("单位保存失败,接口=editDo,单位ID=" + unit.getId(), e);
return Result.error();
}
}
@@ -1,5 +1,7 @@
package com.budwk.app.sys.services;
import cn.hutool.core.lang.tree.Tree;
import java.util.List;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.BaseService;
@@ -9,6 +11,27 @@ import com.budwk.app.sys.models.Sys_unit;
* Created by wizzer on 2016/12/22.
*/
public interface SysUnitService extends BaseService<Sys_unit> {
/**
* 按生日祝福编号升序分页;空编号排后,同编号和空编号按单位编码升序。
* @param pageForm 分页参数,pageNumber 为页码,pageSize 为每页条数
* @param unitName 单位名称模糊查询条件,可为空
* @param unitId 上级单位ID,可为空;为空时查询 parentId 非空的单位
* @return 分页结果,list 为当前页单位,totalCount 为符合条件的单位总数
*/
Pagination<Sys_unit> pageUnits(PageForm pageForm, String unitName, String unitId);
/**
* @param pid 查询根单位ID;为空时使用学校默认根
* @return 单位树,节点包含 id、parentId、name、unitTypeCode 和 children;类别允许为空
*/
List<Tree<String>> getUnitTree(String pid);
/**
* @param unit 待编辑单位,id 必填;aliasName 为简称,birthdaySortNo 为可空整数
* @param birthdaySortNoProvided 请求是否提交排序编号;true 时允许将原编号清空,false 时保留原值
*/
void updateUnit(Sys_unit unit, boolean birthdaySortNoProvided);
/**
* 分页查询指定分工会的组成单位。
*
@@ -1,6 +1,13 @@
package com.budwk.app.sys.services.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.constant.RedisConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
@@ -25,6 +32,69 @@ import org.nutz.plugins.wkcache.annotation.CacheRemoveAll;
@IocBean(args = {"refer:dao"})
@CacheDefaults(cacheName = RedisConstant.PLATFORM_REDIS_WKCACHE_PREFIX + "sys_unit",isHash = true)
public class SysUnitServiceImpl extends BaseServiceImpl<Sys_unit> implements SysUnitService {
/** 学校单位主键,未指定 pid 时作为单位树的默认根。 */
private static final String DEFAULT_UNIT_ROOT_ID = "4133012036";
/**
* 单位列表与树共用数据库排序:有编号的优先(含0),编号升序后以单位编码升序兜底。
* @return 仅包含排序规则的新条件对象,可继续追加各自的查询条件
*/
private Cnd unitBirthdayOrder() {
Cnd cnd = Cnd.NEW();
cnd.asc("CASE WHEN birthdaySortNo IS NULL THEN 1 ELSE 0 END")
.asc("birthdaySortNo").asc("unitcode");
return cnd;
}
/** 保留单位名称与上级单位筛选条件,在数据库分页前完成统一排序。 */
@Override
public Pagination<Sys_unit> pageUnits(PageForm pageForm, String unitName, String unitId) {
Cnd cnd = unitBirthdayOrder();
cnd.and("parentId", "is not", null);
cnd.andEX("parentId", "=", unitId);
cnd.and(Cnd.likeEX("name", unitName));
return listPage(pageForm.getPageNumber(), pageForm.getPageSize(), Sys_unit.class, cnd);
}
/** 构建单位树时保留类别空值,避免历史数据因 Map.of 禁止 null 而导致整棵树加载失败。 */
@Override
public List<Tree<String>> getUnitTree(String pid) {
String rootId = StrUtil.blankToDefault(pid, DEFAULT_UNIT_ROOT_ID);
String virtualRootId = "root";
List<Sys_unit> list = query(unitBirthdayOrder());
List<TreeNode<String>> nodeList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Sys_unit unit = list.get(i);
/*
* 单位根节点存在 id 与 parentId 都为 0 的自引用数据。
* 构建树时把当前查询根挂到虚拟根下,保证当前根节点与其下属单位的层级关系。
*/
String parentId = rootId.equals(unit.getId()) ? virtualRootId : unit.getParentId();
// 使用查询顺序作为权重,树构建后同级节点仍遵循生日祝福编号排序。
nodeList.add(new TreeNode<>(unit.getId(), parentId, unit.getName(), i)
.setExtra(
new HashMap<>(java.util.Collections.singletonMap("unitTypeCode", unit.getUnitTypeCode()))
));
}
List<Tree<String>> treeList = TreeUtil.build(nodeList, virtualRootId);
return treeList;
}
/** 编辑单位时保留原有非空更新规则,仅对明确提交的空排序编号执行清空。 */
@Override
@Aop(TransAop.READ_COMMITTED)
public void updateUnit(Sys_unit unit, boolean birthdaySortNoProvided) {
if (unit == null || StrUtil.isBlank(unit.getId())) {
throw new BaseException("单位ID不能为空");
}
updateIgnoreNull(unit);
// 未提交字段的其他调用方不受影响;显式空值需要绕过 updateIgnoreNull。
if (birthdaySortNoProvided && unit.getBirthdaySortNo() == null) {
update(Chain.make("birthdaySortNo", null), Cnd.where("id", "=", unit.getId()));
}
}
public SysUnitServiceImpl(Dao dao) {
super(dao);
}
@@ -16,6 +16,8 @@ const UNIT_MANAGE_TEMPLATE = {
<template v-slot="scope">{{scope.$index + (pageForm.pageNumber - 1) * pageForm.pageSize + 1}}</template>
</el-table-column>
<el-table-column label="单位名称" prop="name"></el-table-column>
<el-table-column label="简称" prop="aliasName" min-width="120"></el-table-column>
<el-table-column label="生日祝福排序编号" prop="birthdaySortNo" width="160"></el-table-column>
<el-table-column label="单位代码" prop="unitcode" width="200"></el-table-column>
<el-table-column label="单位等级" prop="unitLevel" width="100"></el-table-column>
<el-table-column label="操作" width="200px">
@@ -29,16 +31,21 @@ const UNIT_MANAGE_TEMPLATE = {
</el-card>
<el-dialog title="设置单位" :visible.sync="dialogVisible" :close-on-click-modal="false" width="40%" top="2%">
<el-form :model="formData" ref="form" :rules="formRules" size="small" label-width="80px">
<el-form :model="formData" ref="form" :rules="formRules" size="small" label-width="150px">
<el-form-item label="上级单位">
<el-input maxlength="100" disabled :value="currentData?.name" type="text"></el-input>
</el-form-item>
<el-form-item prop="name" label="单位名称">
<el-input maxlength="100" placeholder="请输入单位名称" v-model="formData.name" auto-complete="off" tabindex="2" type="text"></el-input>
</el-form-item>
<!-- <el-form-item prop="aliasName" label="单位别名">-->
<!-- <el-input maxlength="100" placeholder="请输入单位别名" v-model="formData.aliasName" auto-complete="off" tabindex="3" type="text"></el-input>-->
<!-- </el-form-item>-->
<!-- 简称与生日祝福排序编号复用单位实体字段;排序编号允许留空,控件与其他表单项等宽对齐。 -->
<el-form-item prop="aliasName" label="简称">
<el-input maxlength="100" placeholder="请输入简称" v-model="formData.aliasName" clearable></el-input>
</el-form-item>
<el-form-item prop="birthdaySortNo" label="生日祝福排序编号">
<el-input-number v-model="formData.birthdaySortNo" :precision="0" :step="1" style="width: 100%"
:min="-2147483648" :max="2147483647" placeholder="请输入排序编号"></el-input-number>
</el-form-item>
<el-form-item prop="unitcode" label="单位编码">
<el-input maxlength="100" placeholder="请输入单位编码" v-model="formData.unitcode" auto-complete="off" tabindex="4" type="text"></el-input>
</el-form-item>
@@ -75,10 +82,11 @@ const UNIT_MANAGE_TEMPLATE = {
<!-- </el-form-item>-->
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="doHandle">确 定</el-button>
<el-button @click="closeDialog" :disabled="formLoading">取 消</el-button>
<el-button type="primary" @click="doHandle" :loading="formLoading">确 定</el-button>
</span>
</el-dialog>
<slot></slot>
</div>
`,
props: {
@@ -111,6 +119,7 @@ const UNIT_MANAGE_TEMPLATE = {
},
tableData: [],
dialogVisible: false,
formLoading: false,
formData: {},
formRules: {
name: [{ required: true, message: "必填", trigger: "blur" }],
@@ -129,51 +138,71 @@ const UNIT_MANAGE_TEMPLATE = {
},
computed: {},
methods: {
// 通过组件方法关闭弹框,确保 $set 使用当前组件实例。
closeDialog() {
this.$set(this, "dialogVisible", false)
},
doSearch() {
this.pageForm.pageNumber = 1
this.pageData()
},
openAdd() {
this.dialogVisible = true
this.formData = {} //打开新增窗口,表单先清空
// 新建时清空扩展字段,避免沿用上一次编辑的值。
this.$set(this, "formData", { aliasName: "", birthdaySortNo: undefined })
this.parentUnit = []
this.options = []
},
doHandle() {
if (this.formLoading) return
this.$confirm("确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
const self = this
const url = this.formData.id ? "/platform/sys/unit/editDo" : "/platform/sys/unit/addDo"
this.$refs["form"].validate(async function (valid) {
if (valid) {
if (self.currentNode) {
self.formData.parentId = self.currentData.id
}
const resp = await self.$axios.post(url, self.formData)
if (resp.code === 0) {
self.$message.success(resp.msg)
self.doSearch()
self.dialogVisible = false
self.$emit("refresh", null)
} else {
self.$message.warning(resp.msg)
}
this.$refs["form"].validate((valid) => {
if (!valid || this.formLoading) return
const url = this.formData.id ? "/platform/sys/unit/editDo" : "/platform/sys/unit/addDo"
if (this.currentNode) {
this.$set(this.formData, "parentId", this.currentData.id)
}
// 明确提交空字符串表示清空;避免 undefined 被请求序列化忽略。
const params = Object.assign({}, this.formData, {
aliasName: this.formData.aliasName || "",
birthdaySortNo: this.formData.birthdaySortNo == null ? "" : this.formData.birthdaySortNo
})
this.formLoading = true
this.$axios.post(url, params).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
this.$set(this, "dialogVisible", false)
this.$emit("refresh", null)
} else {
this.$message.warning(resp.msg)
}
}).finally(() => {
this.formLoading = false
})
})
})
},
async openEdit(id) {
console.log(this.currentData)
const resp = await this.$axios.post("/platform/sys/unit/edit/" + id)
if (resp.code === 0) {
this.formData = resp.data
this.dialogVisible = true
} else {
this.$message.warning(resp.msg)
}
openEdit(id) {
if (this.formLoading) return
this.formLoading = true
this.$axios.post("/platform/sys/unit/edit/" + id).then((resp) => {
if (resp.code === 0 && resp.data) {
this.$set(this, "formData", resp.data)
// 兼容历史空值,保留编号 0;数字控件使用 undefined 显示空输入。
this.$set(this.formData, "aliasName", resp.data.aliasName || "")
this.$set(this.formData, "birthdaySortNo", resp.data.birthdaySortNo == null ? undefined : resp.data.birthdaySortNo)
this.$set(this, "dialogVisible", true)
} else {
this.$message.warning(resp.msg)
}
}).finally(() => {
this.formLoading = false
})
},
async doDelete(id) {
const confirm = await this.$confirm("此操作将永久删除, 是否继续?", "提示", {