Compare commits
3
Commits
feature_周何峰
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2353998794 | ||
|
|
3fc338af1e | ||
|
|
5ea061ee8e |
@@ -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 Result,data.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 Result,data 为含 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/tree,pid=" + pid, e);
|
||||
return Result.error();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param unit 单位表单;name/unitcode 为名称和编码,aliasName 为最长100字简称,birthdaySortNo 为可空整数编号
|
||||
* @param parentId 上级单位ID,新建时决定所属单位
|
||||
* @param req 请求上下文;编辑时 birthdaySortNo 传空表示清空,未传表示保留
|
||||
* @return Result,code=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 Result,code=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);
|
||||
|
||||
/**
|
||||
* 分页查询指定分工会的组成单位。
|
||||
*
|
||||
|
||||
@@ -101,6 +101,11 @@ public class SysMsgServiceImpl extends BaseServiceImpl<Sys_msg> implements SysMs
|
||||
}
|
||||
});
|
||||
|
||||
// false 仅保存并通知站内消息,供业务自行按渠道发送,避免再次触发学校平台组合推送。
|
||||
if (!isExternal) {
|
||||
return sysMsg;
|
||||
}
|
||||
|
||||
//发送学校平台消息
|
||||
ThreadUtil.execute(() -> {
|
||||
// 46表示短信和钉钉组合发送;按照消息中心要求,组合中包含短信时手机号必填。
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -141,6 +141,10 @@ public class View_user {
|
||||
@Column
|
||||
private String unionCode;
|
||||
|
||||
/** 用户视图中的所属校区值,供变更表单回显及原值比较使用。 */
|
||||
@Column
|
||||
private String campus;
|
||||
|
||||
@Column
|
||||
private String campusId;
|
||||
|
||||
|
||||
+28
@@ -2,6 +2,13 @@ package com.budwk.app.zhgh.staffmanage.birthday.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.annotation.RepeatSubmit;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.mvc.annotation.POST;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
import com.budwk.app.zhgh.staffmanage.birthday.param.UserBirthdayPageForm;
|
||||
import com.budwk.app.zhgh.staffmanage.birthday.service.UserBirthdayService;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -23,6 +30,27 @@ import javax.servlet.http.HttpServletResponse;
|
||||
@Api(tags = "生日祝福数据导出")
|
||||
public class UserBirthdayExportController {
|
||||
|
||||
/**
|
||||
* 修改生日列表中指定人员的所属校区,复用生日导出权限。
|
||||
*
|
||||
* @param userId 列表行的人员 ID;工号、姓名由服务端查询,不接收前端覆盖
|
||||
* @param campusId 校区编码,仅允许 hz(杭州校区)或 cx(长兴校区)
|
||||
* @return Result:code=0 表示保存成功,msg 为操作提示,无额外业务数据
|
||||
*/
|
||||
@At
|
||||
@POST
|
||||
@RepeatSubmit
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("staff.birthday.export")
|
||||
@SLog(tag = "生日校区维护", msg = "修改人员生日校区")
|
||||
public Result saveCampus(@Param("userId") String userId, @Param("campusId") String campusId) {
|
||||
if (StrUtil.isBlank(userId) || !StrUtil.equalsAny(campusId, "hz", "cx")) {
|
||||
return Result.error("请选择人员和有效的所属校区");
|
||||
}
|
||||
userBirthdayService.saveCampus(userId, campusId);
|
||||
return Result.success("所属校区修改成功");
|
||||
}
|
||||
|
||||
@Inject
|
||||
private UserBirthdayService userBirthdayService;
|
||||
|
||||
|
||||
@@ -22,6 +22,15 @@ public interface UserBirthdayService extends BaseService<Sys_user> {
|
||||
*/
|
||||
Pagination pageData(UserBirthdayPageForm pageForm);
|
||||
|
||||
/**
|
||||
* 按人员工号新增或更新生日校区标记,保留现有备注及创建信息。
|
||||
*
|
||||
* @param userId 当前操作者可管理的生日会员 ID
|
||||
* @param campusId hz 表示杭州校区,cx 表示长兴校区
|
||||
* @throws com.budwk.app.base.exception.BaseException 参数无效或人员不在可管理范围时抛出
|
||||
*/
|
||||
void saveCampus(String userId, String campusId);
|
||||
|
||||
/**
|
||||
* 导出符合查询条件的生日会员。
|
||||
*
|
||||
|
||||
+129
-19
@@ -4,13 +4,19 @@ import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.zhgh.staffmanage.birthday.models.UserBirthdayCampus;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.base.sms.SmsService;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.sys.models.Sys_msg;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.services.SysMsgService;
|
||||
import com.budwk.app.web.commons.base.Globals;
|
||||
import com.budwk.app.zhgh.staffmanage.birthday.models.UserBirthdayConfig;
|
||||
import com.budwk.app.zhgh.staffmanage.birthday.param.UserBirthdayPageForm;
|
||||
import com.budwk.app.zhgh.staffmanage.birthday.param.UserBirthdaySendMsgForm;
|
||||
@@ -63,6 +69,9 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
@Inject
|
||||
private SysMsgService sysMsgService;
|
||||
|
||||
@Inject
|
||||
private SmsService smsService;
|
||||
|
||||
@Inject
|
||||
private UserBirthdayMsgLogService userBirthdayMsgLogService;
|
||||
|
||||
@@ -75,6 +84,60 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), buildBirthdaySql(pageForm));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验人员范围并保存生日校区;锁定人员行,使同一人员的并发保存串行执行。
|
||||
*
|
||||
* @param userId 列表人员 ID,须属于当前操作者可查询的会员且已维护生日
|
||||
* @param campusId hz(杭州校区)或 cx(长兴校区),名称由后端确定
|
||||
* @throws BaseException 人员无效、超出管理范围或校区编码无效
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void saveCampus(String userId, String campusId) {
|
||||
if (StrUtil.isBlank(userId) || !StrUtil.equalsAny(campusId, "hz", "cx")) {
|
||||
throw new BaseException("请选择人员和有效的所属校区");
|
||||
}
|
||||
// 即使尚未创建校区标记,也通过已存在的人员行互斥,避免并发插入重复工号标记。
|
||||
Sql lockSql = Sqls.create("SELECT id FROM sys_user WHERE id = @userId FOR UPDATE");
|
||||
lockSql.params().set("userId", userId);
|
||||
lockSql.setCallback(Sqls.callback.str());
|
||||
dao().execute(lockSql);
|
||||
if (lockSql.getObject(String.class) == null) {
|
||||
throw new BaseException("人员不存在");
|
||||
}
|
||||
|
||||
// 复用生日列表的组织权限条件,范围由登录身份确定,不信任客户端传入的组织信息。
|
||||
Cnd scope = Cnd.where("id", "=", userId).and("member", "=", 1).and("birthday", "is not", null);
|
||||
new UserBirthdayPageForm().buildSearch(scope, "");
|
||||
View_user user = dao().fetch(View_user.class, scope);
|
||||
if (user == null || StrUtil.isBlank(user.getLoginname())) {
|
||||
throw new BaseException("人员不在可管理的生日会员范围内");
|
||||
}
|
||||
List<UserBirthdayCampus> records = dao().query(UserBirthdayCampus.class,
|
||||
Cnd.where("loginname", "=", user.getLoginname()).desc("updatedAt").asc("id"));
|
||||
UserBirthdayCampus campus = records.stream()
|
||||
.filter(item -> !Boolean.TRUE.equals(item.getDelFlag()))
|
||||
.findFirst().orElse(records.isEmpty() ? new UserBirthdayCampus() : records.get(0));
|
||||
boolean insert = StrUtil.isBlank(campus.getId());
|
||||
campus.setLoginname(user.getLoginname());
|
||||
campus.setUsername(user.getUsername());
|
||||
campus.setCampusId(campusId);
|
||||
campus.setCampusName("cx".equals(campusId) ? "长兴校区" : "杭州校区");
|
||||
campus.setDelFlag(false);
|
||||
if (insert) {
|
||||
dao().insert(campus);
|
||||
} else {
|
||||
dao().update(campus);
|
||||
}
|
||||
// 当前工号若已有重复有效记录,仅保留本次更新的记录,其余逻辑删除,避免列表联表重复。
|
||||
for (UserBirthdayCampus duplicate : records) {
|
||||
if (!duplicate.getId().equals(campus.getId()) && !Boolean.TRUE.equals(duplicate.getDelFlag())) {
|
||||
duplicate.setDelFlag(true);
|
||||
dao().update(duplicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportXlsx(UserBirthdayPageForm pageForm, HttpServletResponse response) {
|
||||
try {
|
||||
@@ -95,7 +158,19 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
// 当前列表按查询校区生成顶部标题,未指定校区时使用全校标题。
|
||||
exportParams.setTitle(buildSignatureTitle(getCampusDisplayName(pageForm.getCampusName())));
|
||||
try (Workbook workbook = ExcelExportUtil.exportExcel(exportParams, columns, list)) {
|
||||
// 调整当前工作簿的全部字体,保留各字体原有的加粗、颜色和字体名称。
|
||||
for (int fontIndex = 0; fontIndex < workbook.getNumberOfFontsAsInt(); fontIndex++) {
|
||||
workbook.getFontAt(fontIndex).setFontHeightInPoints((short) 16);
|
||||
}
|
||||
// 字号增大后为每行保留至少 28 磅高度,已有更高的标题或数据行不缩小。
|
||||
for (Sheet sheet : workbook) {
|
||||
for (Row row : sheet) {
|
||||
row.setHeightInPoints(Math.max(row.getHeightInPoints(), 28));
|
||||
}
|
||||
}
|
||||
CommonDownloadUtil.download("生日祝福人员名单.xlsx", workbook, response);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -433,9 +508,9 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
sheet.setColumnWidth(7, 16 * 256);
|
||||
|
||||
CellStyle titleStyle = createCellStyle(workbook, true, (short) 16, false);
|
||||
CellStyle subtitleStyle = createCellStyle(workbook, false, (short) 12, false);
|
||||
CellStyle headerStyle = createCellStyle(workbook, true, (short) 11, true);
|
||||
CellStyle contentStyle = createCellStyle(workbook, false, (short) 11, true);
|
||||
CellStyle subtitleStyle = createCellStyle(workbook, false, (short) 16, false);
|
||||
CellStyle headerStyle = createCellStyle(workbook, true, (short) 16, true);
|
||||
CellStyle contentStyle = createCellStyle(workbook, false, (short) 16, true);
|
||||
|
||||
Row titleRow = sheet.createRow(0);
|
||||
titleRow.setHeightInPoints(28);
|
||||
@@ -443,13 +518,13 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 7));
|
||||
|
||||
Row subtitleRow = sheet.createRow(1);
|
||||
subtitleRow.setHeightInPoints(22);
|
||||
subtitleRow.setHeightInPoints(28);
|
||||
createCell(subtitleRow, 0, buildSignatureSubtitle(displayPeriod), subtitleStyle);
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 7));
|
||||
|
||||
String[] headers = {"序号", "部门", "姓名", "签名", "序号", "部门", "姓名", "签名"};
|
||||
Row headerRow = sheet.createRow(2);
|
||||
headerRow.setHeightInPoints(22);
|
||||
headerRow.setHeightInPoints(28);
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
createCell(headerRow, i, headers[i], headerStyle);
|
||||
}
|
||||
@@ -457,7 +532,7 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
int leftSize = (list.size() + 1) / 2;
|
||||
for (int i = 0; i < leftSize; i++) {
|
||||
Row row = sheet.createRow(i + 3);
|
||||
row.setHeightInPoints(22);
|
||||
row.setHeightInPoints(28);
|
||||
fillSignatureRow(row, 0, i, getListItem(list, i), contentStyle);
|
||||
fillSignatureRow(row, 4, i + leftSize, getListItem(list, i + leftSize), contentStyle);
|
||||
}
|
||||
@@ -551,10 +626,10 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
}
|
||||
if (start.getYear() == end.getYear()) {
|
||||
return start.format(DateTimeFormatter.ofPattern("yyyy年M月")) + "-" +
|
||||
end.format(DateTimeFormatter.ofPattern("M月"));
|
||||
end.format(DateTimeFormatter.ofPattern("M月"));
|
||||
}
|
||||
return start.format(DateTimeFormatter.ofPattern("yyyy年M月")) + "-" +
|
||||
end.format(DateTimeFormatter.ofPattern("yyyy年M月"));
|
||||
end.format(DateTimeFormatter.ofPattern("yyyy年M月"));
|
||||
}
|
||||
|
||||
private String buildSignatureDisplayPeriod(LocalDate start, LocalDate end) {
|
||||
@@ -563,10 +638,10 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
}
|
||||
if (start.getYear() == end.getYear()) {
|
||||
return start.format(DateTimeFormatter.ofPattern("yyyy年M")) + "-" +
|
||||
end.format(DateTimeFormatter.ofPattern("M月"));
|
||||
end.format(DateTimeFormatter.ofPattern("M月"));
|
||||
}
|
||||
return start.format(DateTimeFormatter.ofPattern("yyyy年M月")) + "-" +
|
||||
end.format(DateTimeFormatter.ofPattern("yyyy年M月"));
|
||||
end.format(DateTimeFormatter.ofPattern("yyyy年M月"));
|
||||
}
|
||||
|
||||
private String buildSignatureDateDisplayPeriod(LocalDate start, LocalDate end) {
|
||||
@@ -575,21 +650,22 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
}
|
||||
if (isSameMonth(start, end)) {
|
||||
return start.format(DateTimeFormatter.ofPattern("yyyy年M月d日")) + "-" +
|
||||
end.format(DateTimeFormatter.ofPattern("d日"));
|
||||
end.format(DateTimeFormatter.ofPattern("d日"));
|
||||
}
|
||||
if (start.getYear() == end.getYear()) {
|
||||
return start.format(DateTimeFormatter.ofPattern("yyyy年M月d日")) + "-" +
|
||||
end.format(DateTimeFormatter.ofPattern("M月d日"));
|
||||
end.format(DateTimeFormatter.ofPattern("M月d日"));
|
||||
}
|
||||
return start.format(DateTimeFormatter.ofPattern("yyyy年M月d日")) + "-" +
|
||||
end.format(DateTimeFormatter.ofPattern("yyyy年M月d日"));
|
||||
end.format(DateTimeFormatter.ofPattern("yyyy年M月d日"));
|
||||
}
|
||||
|
||||
/** 统一列表和签名表的顶部标题,校区取按钮参数或列表筛选条件。 */
|
||||
private String buildSignatureTitle(String campusDisplayName) {
|
||||
if (StrUtil.isBlank(campusDisplayName)) {
|
||||
return "浙江交通职业技术学院职工生日蛋糕券发放名单";
|
||||
return "浙江交通职业技术学院职工座谈会及生日蛋糕券发放名单";
|
||||
}
|
||||
return "浙江交通职业技术学院" + campusDisplayName + "职工生日蛋糕券发放名单";
|
||||
return "浙江交通职业技术学院" + campusDisplayName + "职工座谈会及生日蛋糕券发放名单";
|
||||
}
|
||||
|
||||
private String buildSignatureSubtitle(String displayPeriod) {
|
||||
@@ -643,8 +719,9 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
|
||||
/**
|
||||
* 将生日消息写入当前项目消息中心并生成发送记录。
|
||||
* 发送内容只包含标题和正文,不向站内、短信或钉钉渠道传递生日页面链接。
|
||||
* 单人、批量和自动发送共用此入口:站内保留跳转地址,短信仅发祝福正文,钉钉正文附带生日链接。
|
||||
*/
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
private int sendMessages(List<String> loginNames, String title, String content,
|
||||
String pushBy, String pushByName, String pushType) {
|
||||
List<String> recipients = loginNames == null ? List.of() : loginNames.stream()
|
||||
@@ -655,17 +732,50 @@ public class UserBirthdayServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 链接携带发送时的福利贺卡文件 ID;未配置时仍进入生日页面,由页面展示未配置提示。
|
||||
String fileId = StrUtil.blankToDefault(getConfig().getBirthdayUrl(), "");
|
||||
String link = StrUtil.removeSuffix(Globals.AppDomain, "/")
|
||||
+ "/platform/staffManage/birthday/manage/h5";
|
||||
|
||||
Sys_msg message = new Sys_msg();
|
||||
message.setTitle(title);
|
||||
message.setNote(content);
|
||||
message.setUrl(link);
|
||||
message.setType("user");
|
||||
message.setSendType("show");
|
||||
message.setSendAt(Times.getTS());
|
||||
message.setCreatedBy(pushBy);
|
||||
sysMsgService.saveMsg(message, recipients.toArray(String[]::new), true);
|
||||
|
||||
userBirthdayMsgLogService.insertLogs(recipients, title, content, "",
|
||||
pushBy, pushByName, pushType);
|
||||
|
||||
// 短信接收人需携带工号和手机号,沿用消息中心按工号分组的查询范围。
|
||||
Sql receiverSql = Sqls.create("SELECT loginname, mobile FROM vw_user $condition");
|
||||
receiverSql.setCondition(Cnd.where("loginname", "in", recipients).groupBy("loginname"));
|
||||
List<NutMap> receivers = listMap(receiverSql).stream()
|
||||
.map(user -> NutMap.NEW()
|
||||
.addv("userId", user.getString("loginname"))
|
||||
.addv("mobile", user.getString("mobile"))
|
||||
.addv("email", "")
|
||||
.addv("flag", 0))
|
||||
.toList();
|
||||
if (!receivers.isEmpty()) {
|
||||
// 分别提交渠道任务,任一渠道失败不会阻断另一渠道;实际结果由学校消息服务分别留存。
|
||||
ThreadUtil.execute(() -> {
|
||||
boolean success = smsService.sendMsg("4", null, receivers, title, content, null, null);
|
||||
if (!success) {
|
||||
log.warn("生日短信发送未成功,消息ID:{},请查看学校平台发送记录", message.getId());
|
||||
}
|
||||
});
|
||||
ThreadUtil.execute(() -> {
|
||||
// 当前钉钉使用文本消息,链接明确写入正文,跳转参数留空以避免平台重复追加。
|
||||
boolean success = smsService.sendMsg("6", null, receivers, title, content, null, link);
|
||||
if (!success) {
|
||||
log.warn("生日钉钉发送未成功,消息ID:{},请查看学校平台发送记录", message.getId());
|
||||
} else {
|
||||
userBirthdayMsgLogService.insertLogs(recipients, title, content, link,
|
||||
pushBy, pushByName, pushType);
|
||||
}
|
||||
});
|
||||
}
|
||||
return recipients.size();
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -87,6 +87,7 @@ public class MemberManageServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
u.unitName,
|
||||
u.unionId,
|
||||
u.unionName,
|
||||
u.campus,
|
||||
u.birthday,
|
||||
u.manyUnit,
|
||||
u.member,
|
||||
@@ -267,6 +268,7 @@ public class MemberManageServiceImpl extends BaseServiceImpl<Sys_user> implement
|
||||
NutMap newMap = Lang.obj2nutmap(record);
|
||||
// 原数据
|
||||
NutMap sourceMap = Lang.obj2nutmap(info);
|
||||
// 原数据已映射 campus,直接与表单同名字段比较,避免被 campusId 覆盖而误报异动。
|
||||
List<NutMap> changeList = new ArrayList<>();
|
||||
|
||||
for (String fieldName : allowChangeFieldNames) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.budwk.app.zhgh.welfare.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.welfare.service.WelfareProjectService;
|
||||
@@ -27,6 +29,7 @@ public class WelfareNoticeController {
|
||||
@At
|
||||
@Ok("beetl:/platform/zhghh5/welfare/notice/detail.html")
|
||||
@ApiOperation("福利通知附件详情页")
|
||||
@SaCheckLogin
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@@ -38,6 +41,7 @@ public class WelfareNoticeController {
|
||||
*/
|
||||
@At
|
||||
@ApiOperation("查询福利通知附件详情")
|
||||
@SaCheckLogin
|
||||
public Result detailData(@Valid String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("福利项目ID不能为空");
|
||||
|
||||
+26
-4
@@ -586,6 +586,7 @@ public class WelfareStatisticsServiceImpl extends BaseServiceImpl<WelfareProject
|
||||
u.loginname AS loginName,
|
||||
u.username AS userName,
|
||||
wpus.mobile,
|
||||
wpus.userName AS recipient,
|
||||
wl.userState,
|
||||
wl.personType,
|
||||
wl.welfareUnionName,
|
||||
@@ -635,12 +636,23 @@ public class WelfareStatisticsServiceImpl extends BaseServiceImpl<WelfareProject
|
||||
return unionId;
|
||||
}
|
||||
|
||||
/** 将历史收货信息拆为 V3 导出所需的收货人、联系方式和收货地址三列。 */
|
||||
/**
|
||||
* 填充品牌导出的收货信息。当前选择记录分别保存收货人、手机号和纯地址文本;
|
||||
* 历史记录可能将三项信息拼接在 receiveAddress 中,因此继续兼容旧格式解析。
|
||||
*/
|
||||
private void fillV3ReceiveAddress(NutMap row) {
|
||||
String mobile = row.getString("mobile");
|
||||
if (StrUtil.isNotBlank(mobile)) {
|
||||
row.put("phone", mobile);
|
||||
}
|
||||
|
||||
String receiveAddress = row.getString("receiveAddress");
|
||||
if (StrUtil.isBlank(receiveAddress)) {
|
||||
return;
|
||||
}
|
||||
// 新数据的 receiveAddress 仅保存地址正文,可直接作为收货地址导出。
|
||||
row.put("address", receiveAddress);
|
||||
|
||||
Map<String, String> values = new HashMap<>();
|
||||
for (String pair : receiveAddress.split("[,,]")) {
|
||||
String[] keyValue = pair.split("[::]", 2);
|
||||
@@ -648,9 +660,19 @@ public class WelfareStatisticsServiceImpl extends BaseServiceImpl<WelfareProject
|
||||
values.put(keyValue[0].trim(), keyValue[1].trim());
|
||||
}
|
||||
}
|
||||
row.put("recipient", values.get("收件人"));
|
||||
row.put("phone", values.get("联系方式"));
|
||||
row.put("address", values.get("收货地址"));
|
||||
String recipient = StrUtil.blankToDefault(values.get("收件人"), values.get("收货人"));
|
||||
String phone = StrUtil.blankToDefault(values.get("联系方式"),
|
||||
StrUtil.blankToDefault(values.get("手机号码"), values.get("手机号")));
|
||||
String address = StrUtil.blankToDefault(values.get("收货地址"), values.get("详细地址"));
|
||||
if (StrUtil.isNotBlank(recipient)) {
|
||||
row.put("recipient", recipient);
|
||||
}
|
||||
if (StrUtil.isNotBlank(phone)) {
|
||||
row.put("phone", phone);
|
||||
}
|
||||
if (StrUtil.isNotBlank(address)) {
|
||||
row.put("address", address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,17 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<configuration scan="false" scanPeriod="60000" debug="false">
|
||||
|
||||
<!-- 定义日志文件的存储路径 -->
|
||||
<!-- 日志存储路径 -->
|
||||
<property name="LOG_HOME" value="./logs"/>
|
||||
|
||||
<!-- 控制台输出配置 -->
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- INFO级别日志文件配置 -->
|
||||
|
||||
<!--
|
||||
#################################################################################
|
||||
# #
|
||||
# 全文输出日志(一个文件存储)start #
|
||||
# #
|
||||
#################################################################################
|
||||
-->
|
||||
|
||||
<!-- 所有级别日志写入同一个文件 -->
|
||||
<appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/app.log</file>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/app-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>300</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<!-- 框架日志级别(按需调整) -->
|
||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||
<logger name="org.quartz" level="INFO"/>
|
||||
<logger name="org.nutz" level="DEBUG"/>
|
||||
|
||||
<!-- root logger:DEBUG 级别,输出到控制台和全量文件 -->
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="ALL_FILE"/>
|
||||
</root>
|
||||
|
||||
<!--
|
||||
#################################################################################
|
||||
# #
|
||||
# 全文输出日志(一个文件存储)end #
|
||||
# #
|
||||
#################################################################################
|
||||
-->
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
#################################################################################
|
||||
# #
|
||||
# debug、info、error分文件输出 start #
|
||||
# #
|
||||
#################################################################################
|
||||
-->
|
||||
|
||||
<!-- DEBUG级别日志文件配置 -->
|
||||
<!--<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/debug.log</file>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>DEBUG</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/debug-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>300</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<!– INFO级别日志文件配置 –>
|
||||
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/info.log</file>
|
||||
<encoder>
|
||||
@@ -24,11 +92,11 @@
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/info-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
<maxHistory>300</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<!-- ERROR级别日志文件配置 -->
|
||||
<!– ERROR级别日志文件配置 –>
|
||||
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/error.log</file>
|
||||
<encoder>
|
||||
@@ -41,19 +109,31 @@
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/error-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
<maxHistory>300</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<logger name="java" additivity="false" />
|
||||
<!– 框架日志级别 –>
|
||||
<!– <logger name="java" additivity="false" />–>
|
||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||
<logger name="org.quartz" level="INFO"/>
|
||||
<logger name="org.nutz" level="DEBUG"/>
|
||||
|
||||
<!-- 日志级别和appender的关联 -->
|
||||
<!– 日志级别和appender的关联 –>
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="DEBUG_FILE"/>
|
||||
<appender-ref ref="INFO_FILE"/>
|
||||
<appender-ref ref="ERROR_FILE"/>
|
||||
</root>
|
||||
</root>-->
|
||||
|
||||
<!--
|
||||
#################################################################################
|
||||
# #
|
||||
# debug、info、error分文件输出 end #
|
||||
# #
|
||||
#################################################################################
|
||||
-->
|
||||
|
||||
</configuration>
|
||||
|
||||
|
||||
@@ -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("此操作将永久删除, 是否继续?", "提示", {
|
||||
|
||||
@@ -55,10 +55,36 @@ layout("/layouts/platform.html"){
|
||||
:label="column.label" :width="column.width" :fixed="column.fixed"
|
||||
:sortable="column.sortable"
|
||||
header-align="center" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="150" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button type="text" size="small" @click="openCampusForm(row)">修改所属校区</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</template>
|
||||
<el-dialog title="修改所属校区" :visible.sync="campusDialogVisible" width="480px"
|
||||
:close-on-click-modal="false" :close-on-press-escape="!formLoading" :show-close="!formLoading">
|
||||
<el-form ref="campusFormRef" :model="campusForm" :rules="campusRules" label-width="100px">
|
||||
<el-form-item label="工号">
|
||||
<el-input :value="campusForm.loginname" readonly></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名">
|
||||
<el-input :value="campusForm.username" readonly></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属校区" prop="campusId">
|
||||
<el-select v-model="campusForm.campusId" :disabled="formLoading" placeholder="请选择所属校区" style="width:100%">
|
||||
<el-option v-for="item in campuses" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div class="text-muted">此设置用于生日名单及签名表。</div>
|
||||
</el-form>
|
||||
<template slot="footer">
|
||||
<el-button :disabled="formLoading" @click="closeCampusForm">取消</el-button>
|
||||
<el-button type="primary" :loading="formLoading" @click="saveCampus">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</guava>
|
||||
</div>
|
||||
|
||||
@@ -86,6 +112,11 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
queryForm: {userStates:[],personTypes:[]},
|
||||
birthdayRange: [],
|
||||
campusDialogVisible: false,
|
||||
campusForm: {userId:"",loginname:"",username:"",campusId:""},
|
||||
campusRules: {
|
||||
campusId: [{required:true,message:"请选择所属校区",trigger:"change"}]
|
||||
},
|
||||
campuses: [
|
||||
{id:"hz",name:"杭州校区"},
|
||||
{id:"cx",name:"长兴校区"}
|
||||
@@ -109,6 +140,48 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 回显列表中实际生效的生日校区,包括未设置标记时按单位推导出的校区。
|
||||
openCampusForm(row) {
|
||||
const campus = this.campuses.find(item => item.name === row.campusName || item.id === row.campusName)
|
||||
this.$set(this, "campusForm", {
|
||||
userId: row.id,
|
||||
loginname: row.loginname,
|
||||
username: row.username,
|
||||
campusId: campus ? campus.id : ""
|
||||
})
|
||||
this.$set(this, "campusDialogVisible", true)
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.campusFormRef) this.$refs.campusFormRef.clearValidate()
|
||||
})
|
||||
},
|
||||
// 保存中禁止关闭,避免请求未完成时切换到其他人员。
|
||||
closeCampusForm() {
|
||||
if (!this.formLoading) this.$set(this, "campusDialogVisible", false)
|
||||
},
|
||||
// 仅提交人员 ID 和校区编码,工号、姓名及校区名称由后端读取并校验。
|
||||
saveCampus() {
|
||||
if (this.formLoading) return
|
||||
this.$refs.campusFormRef.validate((valid) => {
|
||||
if (!valid) return
|
||||
this.$set(this, "formLoading", true)
|
||||
this.$axios.post("/platform/staffManage/birthday/export/saveCampus", {
|
||||
userId: this.campusForm.userId,
|
||||
campusId: this.campusForm.campusId
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("所属校区修改成功")
|
||||
this.$set(this, "campusDialogVisible", false)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.error(res.msg || "所属校区修改失败")
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$message.error("所属校区修改失败,请稍后重试")
|
||||
}).finally(() => {
|
||||
this.$set(this, "formLoading", false)
|
||||
})
|
||||
})
|
||||
},
|
||||
initOrganizationOptions() {
|
||||
if (this.$auth.hasRoleOr("SYSADMIN, SCHOOL_UNION_ADMIN, SCHOOL_UNION_MEMBER_ADMIN")) {
|
||||
this.$businessTool.listUnion().then((data) => {
|
||||
|
||||
+13
-5
@@ -110,7 +110,7 @@ const MEMBER_CHANGE = {
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-else label="所属校区">
|
||||
<el-descriptions-item v-else-if="!replaceWelfareWithCampus" label="所属校区">
|
||||
<el-form-item prop="campus">
|
||||
<dict-select style="width: 100%" placeholder="请选择所属校区" v-model="formData.campus"
|
||||
:disabled="allowFields('campus')" code="USER_CAMPUS"></dict-select>
|
||||
@@ -196,7 +196,14 @@ const MEMBER_CHANGE = {
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="福利会员状态">
|
||||
<!-- 管理页在福利会员位置展示校区,保留三级单位;其他调用方沿用原字段布局。 -->
|
||||
<el-descriptions-item v-if="replaceWelfareWithCampus" label="所属校区">
|
||||
<el-form-item prop="campus">
|
||||
<dict-select style="width: 100%" placeholder="请选择所属校区" v-model="formData.campus"
|
||||
:disabled="allowFields('campus')" code="USER_CAMPUS"></dict-select>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-else label="福利会员状态">
|
||||
<el-form-item prop="welfareMember">
|
||||
<el-radio-group v-model="formData.welfareMember" size="small" class="welfare-member-radio-group"
|
||||
style="display: flex; align-items: center; flex-wrap: nowrap; white-space: nowrap;">
|
||||
@@ -288,6 +295,8 @@ const MEMBER_CHANGE = {
|
||||
props: {
|
||||
id: { type: String, default: '' },
|
||||
showThreeUnit: { type: Boolean, default: false },
|
||||
// 仅管理页启用福利会员与校区的展示替换,默认保持共用页面行为。
|
||||
replaceWelfareWithCampus: { type: Boolean, default: false },
|
||||
},
|
||||
mixins: [initTableMixins],
|
||||
store,
|
||||
@@ -406,9 +415,7 @@ const MEMBER_CHANGE = {
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.threeUnits = resp.data || []
|
||||
if (this.threeUnits.length === 0) {
|
||||
this.$message.warning("当前所属单位未配置三级单位")
|
||||
}
|
||||
// 未配置三级单位时保持空选项,允许继续编辑其他人员信息。
|
||||
} else {
|
||||
this.$message.error(resp.msg || "三级单位查询失败")
|
||||
}
|
||||
@@ -525,6 +532,7 @@ const MEMBER_CHANGE = {
|
||||
this.$set(this.formData, "position", position)
|
||||
this.$set(this.formData, "education", education)
|
||||
this.$set(this.formData, "academicDegree", academicDegree)
|
||||
// 与编辑接口及变更记录统一使用 campus,正确回显当前人员所属校区。
|
||||
this.$set(this.formData, "campus", campus)
|
||||
this.$set(this.formData, "threeUnitId", threeUnitId)
|
||||
this.$set(this.formData, "userState", userState)
|
||||
|
||||
@@ -185,16 +185,9 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" header-align="center" label="福利会员" prop="member"
|
||||
<!-- 所属校区展示列表接口返回的 campus 字段。 -->
|
||||
<el-table-column align="center" header-align="center" label="所属校区" prop="campus"
|
||||
show-overflow-tooltip sortable>
|
||||
<template scope="{row}">
|
||||
<span class="text-success " v-if="row.welfareMember==1">
|
||||
<i class="fa fa-circle ml5"></i> 是
|
||||
</span>
|
||||
<span class="text-danger" v-else>
|
||||
<i class="fa fa-circle ml5"></i> 否
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" header-align="center" label="操作"
|
||||
@@ -227,7 +220,7 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
|
||||
<template #public>
|
||||
<member-change ref="memberChangeRef" :show-three-unit="true" @do-back="$refs.guava.index()" @do-submit="doSubmit"></member-change>
|
||||
<member-change ref="memberChangeRef" :show-three-unit="true" :replace-welfare-with-campus="true" @do-back="$refs.guava.index()" @do-submit="doSubmit"></member-change>
|
||||
</template>
|
||||
|
||||
<template #edit>
|
||||
|
||||
@@ -22,7 +22,7 @@ layout("/layouts/platform_h5.html"){
|
||||
@keyframes confetti-fall { 0% { transform: translate3d(0,-20px,0) rotate(0); opacity: 0; }
|
||||
12% { opacity: 1; } 100% { transform: translate3d(35px,62vh,0) rotate(540deg); opacity: 0; } }
|
||||
.greeting-zone { position: relative; z-index: 4; height: 48%; display: flex; flex-direction: column; align-items: center;
|
||||
justify-content: flex-start; padding: 0 24px calc(20px + env(safe-area-inset-bottom)); box-sizing: border-box; }
|
||||
justify-content: flex-start; padding: 24px 24px calc(20px + env(safe-area-inset-bottom)); box-sizing: border-box; /* 下移祝福卡片,为蛋糕底部留出间距。 */ }
|
||||
.greeting-card { width: 100%; box-sizing: border-box; padding: 20px 20px 16px; border: 1px solid rgba(164,60,26,.3);
|
||||
border-radius: 18px; background: rgba(255,249,228,.92); box-shadow: 0 12px 30px rgba(109,29,10,.22);
|
||||
text-align: center; animation: card-enter .7s ease-out both; }
|
||||
@@ -115,7 +115,7 @@ layout("/layouts/platform_h5.html"){
|
||||
生日快乐,幸福安康!
|
||||
</div>
|
||||
</div>
|
||||
<button class="receive-button" @click="openCoupon">领取生日福利</button>
|
||||
<button v-if="hasCouponId" class="receive-button" @click="openCoupon">领取生日福利</button>
|
||||
</div>
|
||||
|
||||
<button type="button" class="music-button" :class="{playing:musicPlaying}"
|
||||
@@ -165,6 +165,8 @@ layout("/layouts/platform_h5.html"){
|
||||
return {
|
||||
appName: "${AppName!}",
|
||||
userName: "${userName!}",
|
||||
// 仅地址参数 id 非空时提供福利入口,后台配置的贺卡不作为按钮显示依据。
|
||||
hasCouponId: "${fileId!}".trim().length > 0,
|
||||
pageLoading: false,
|
||||
showMusicPrompt: false,
|
||||
musicPromptResolved: false,
|
||||
@@ -230,7 +232,7 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
openCoupon() {
|
||||
if (this.showCoupon) return
|
||||
if (!this.hasCouponId || this.showCoupon) return
|
||||
this.$set(this, "showCoupon", true)
|
||||
window.h5PopupHistory.open(this.popupHistoryToken, "birthdayCoupon")
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user