华住会更新人员整改
This commit is contained in:
@@ -5,15 +5,17 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.huazhu.param.HuaZhuEmployeePageForm;
|
||||
import com.budwk.app.zhgh.huazhu.service.HuaZhuEmployeeService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* PC 端华住员工同步管理。
|
||||
@@ -38,7 +40,12 @@ public class HuaZhuManageController {
|
||||
return Result.success(huaZhuEmployeeService.pageUsers(pageForm));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userIds 页面勾选员工的本项目用户主键数组,至少传入一个主键
|
||||
* @return Result,data 为逐人同步结果,含 userId、loginName、userName、success 和 message
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("huazhu.manage")
|
||||
public Result syncUsers(@Param("userIds") String[] userIds) {
|
||||
if (userIds == null || userIds.length == 0) {
|
||||
@@ -47,6 +54,35 @@ public class HuaZhuManageController {
|
||||
return Result.success(huaZhuEmployeeService.syncUsers(Arrays.asList(userIds)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 无需请求参数;只读取规则说明,供页面确认使用,不推送人员。
|
||||
* @return Result,data.description 为包含实际单位名称的中文规则;单位缺失时返回错误提示
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("huazhu.manage")
|
||||
public Result syncRuleDescription() {
|
||||
try {
|
||||
return Result.success(NutMap.NEW().addv("description", huaZhuEmployeeService.getSyncRuleDescription()));
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 无需请求参数;由服务端按固定业务规则筛选全部待同步人员。
|
||||
* @return Result,data 为逐人同步结果,含 userId、loginName、userName、success 和 message;无人符合时为空列表
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("huazhu.manage")
|
||||
public Result syncRuleUsers() {
|
||||
try {
|
||||
return Result.success(huaZhuEmployeeService.syncRuleUsers());
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("huazhu.manage")
|
||||
public Result queryStatus(@Param("userId") String userId) {
|
||||
|
||||
@@ -29,6 +29,20 @@ public interface HuaZhuEmployeeService {
|
||||
*/
|
||||
List<HuaZhuSyncResult> syncUsers(List<String> userIds);
|
||||
|
||||
/**
|
||||
* 获取规则同步的中文说明,无需传参;单位名称从当前单位表读取,缺失时拒绝继续同步。
|
||||
*
|
||||
* @return 包含在岗条件、限定单位名称及非自聘条件的说明文字
|
||||
*/
|
||||
String getSyncRuleDescription();
|
||||
|
||||
/**
|
||||
* 同步全部符合规则且未删除的员工,无需传参,不受页面搜索、分页或勾选范围限制。
|
||||
*
|
||||
* @return 每位员工的工号、姓名、success 成功标记和 message 结果说明;无人符合时返回空列表
|
||||
*/
|
||||
List<HuaZhuSyncResult> syncRuleUsers();
|
||||
|
||||
/**
|
||||
* 查询指定本项目员工在华住的实时状态。
|
||||
*
|
||||
|
||||
+59
-6
@@ -7,11 +7,14 @@ import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.models.Sys_unit;
|
||||
import com.budwk.app.zhgh.huazhu.constant.HuaZhuConstant;
|
||||
import com.budwk.app.zhgh.huazhu.param.HuaZhuEmployeePageForm;
|
||||
import com.budwk.app.zhgh.huazhu.service.HuaZhuEmployeeService;
|
||||
import com.budwk.app.zhgh.huazhu.vo.HuaZhuEmployeeStatus;
|
||||
import com.budwk.app.zhgh.huazhu.vo.HuaZhuSyncResult;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
@@ -34,6 +37,8 @@ import java.util.List;
|
||||
public class HuaZhuEmployeeServiceImpl implements HuaZhuEmployeeService {
|
||||
|
||||
private static final String TOKEN_CACHE_KEY = "zhgh:huazhu:oauth-token";
|
||||
// 这两个单位的在岗人员还需满足非自聘条件;说明文字和筛选使用同一组单位主键。
|
||||
private static final List<String> RULE_UNIT_IDS = List.of("110100", "116110");
|
||||
|
||||
private final Dao dao;
|
||||
|
||||
@@ -69,20 +74,28 @@ public class HuaZhuEmployeeServiceImpl implements HuaZhuEmployeeService {
|
||||
return new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), totalCount, listSql.getList(NutMap.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 逐人推送,人员已删除、缺少工号或接口失败均记录为该人员失败,继续处理其余人员。
|
||||
* @param userIds 待同步的本项目用户主键列表
|
||||
* @return 每位员工的标识、success 成功标记和 message 结果说明
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public List<HuaZhuSyncResult> syncUsers(List<String> userIds) {
|
||||
if (userIds == null || userIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<HuaZhuSyncResult> results = new ArrayList<>();
|
||||
for (String userId : userIds) {
|
||||
Sys_user user = findAvailableUser(userId);
|
||||
HuaZhuSyncResult result = new HuaZhuSyncResult()
|
||||
.setUserId(user.getId())
|
||||
.setLoginName(user.getLoginname())
|
||||
.setUserName(user.getUsername());
|
||||
HuaZhuSyncResult result = new HuaZhuSyncResult().setUserId(userId);
|
||||
try {
|
||||
request("/userInfo/addUser", buildEmployeeRequest(user.getLoginname()));
|
||||
Sys_user user = findAvailableUser(userId);
|
||||
result.setLoginName(user.getLoginname()).setUserName(user.getUsername());
|
||||
// 新增员工按参考同步方法携带预订卡及姓名;状态查询仍使用原有参数。
|
||||
NutMap requestBody = buildEmployeeRequest(user.getLoginname())
|
||||
.addv("bookId", HuaZhuConstant.CARD_ID)
|
||||
.addv("userName", user.getUsername());
|
||||
request("/userInfo/addUser", requestBody);
|
||||
result.setSuccess(true).setMessage("同步成功");
|
||||
} catch (Exception e) {
|
||||
result.setSuccess(false).setMessage("同步失败:" + safeMessage(e));
|
||||
@@ -92,6 +105,46 @@ public class HuaZhuEmployeeServiceImpl implements HuaZhuEmployeeService {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 无需入参,按规则内单位主键读取名称,避免向操作人员展示单位编码。
|
||||
* @return 中文同步规则;任一单位不存在或没有名称时抛出异常,禁止继续推送
|
||||
*/
|
||||
@Override
|
||||
public String getSyncRuleDescription() {
|
||||
List<String> unitNames = new ArrayList<>();
|
||||
for (String unitId : RULE_UNIT_IDS) {
|
||||
Sys_unit unit = dao.fetch(Sys_unit.class, Cnd.where("id", "=", unitId).and("delFlag", "=", false));
|
||||
if (unit == null || StrUtil.isBlank(unit.getName())) {
|
||||
throw new IllegalStateException("无法获取同步规则中的单位名称,请检查单位信息");
|
||||
}
|
||||
unitNames.add("【" + unit.getName() + "】");
|
||||
}
|
||||
return "仅同步在岗人员,其中" + String.join("和", unitNames)
|
||||
+ "仅同步非自聘人员,其他单位不限制人员类型。";
|
||||
}
|
||||
|
||||
/**
|
||||
* 无需入参,复用参考方法的在岗及单位/人员类型条件,并排除当前项目已删除人员。
|
||||
* @return 与选中同步一致的逐人结果列表;无符合人员时为空列表
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public List<HuaZhuSyncResult> syncRuleUsers() {
|
||||
// 推送前再次检查单位信息,避免确认后单位被删除或名称缺失仍继续同步。
|
||||
getSyncRuleDescription();
|
||||
// 保留原 SQL 的空值语义:单位为空不入选,限定单位的人员类型为空也不入选。
|
||||
Sql sql = Sqls.create("SELECT id FROM sys_user WHERE delFlag = 0 AND userState = @userState "
|
||||
+ "AND (unitId NOT IN (@unitOne, @unitTwo) "
|
||||
+ "OR (unitId IN (@unitOne, @unitTwo) AND personType != @personType)) ORDER BY id");
|
||||
sql.setParam("userState", "在岗");
|
||||
sql.setParam("unitOne", RULE_UNIT_IDS.get(0));
|
||||
sql.setParam("unitTwo", RULE_UNIT_IDS.get(1));
|
||||
sql.setParam("personType", "自聘");
|
||||
sql.setCallback(Sqls.callback.strList());
|
||||
dao.execute(sql);
|
||||
return syncUsers(sql.getList(String.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HuaZhuEmployeeStatus queryStatus(String userId) {
|
||||
Sys_user user = findAvailableUser(userId);
|
||||
|
||||
@@ -13,7 +13,8 @@ layout("/layouts/platform.html"){
|
||||
</el-card>
|
||||
<el-card class="mt10" shadow="never">
|
||||
<table-tool :app="this" label="华住员工管理">
|
||||
<el-button @click="syncSelected" icon="el-icon-refresh" size="small" type="primary">同步选中员工</el-button>
|
||||
<el-button :disabled="syncLoading || tableLoading" @click="syncSelected" icon="el-icon-refresh" size="small" type="primary">同步选中员工</el-button>
|
||||
<el-button :disabled="tableLoading" :loading="syncLoading" @click="syncRuleUsers" icon="el-icon-refresh" size="small" type="primary">同步规则内人员</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" :size="tableSize" @selection-change="selectionChange" class="vi-table" v-loading="tableLoading">
|
||||
<el-table-column type="selection" width="55"></el-table-column>
|
||||
@@ -46,35 +47,79 @@ layout("/layouts/platform.html"){
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data: function () { return {pageForm: {searchKeyword: "", pageNumber: 1, pageSize: 10, totalCount: 0}, selectedRows: [], statusDialogVisible: false, statusData: null} },
|
||||
data() { return {selectedRows: [], syncLoading: false, statusDialogVisible: false, statusData: null} },
|
||||
methods: {
|
||||
selectionChange: function (rows) { this.$set(this, "selectedRows", rows) },
|
||||
syncSelected: function () {
|
||||
var self = this;
|
||||
selectionChange(rows) { this.$set(this, "selectedRows", rows) },
|
||||
// 确认期间锁定同步入口,并固定本次勾选范围,防止重复点击或勾选变化影响提交。
|
||||
syncSelected() {
|
||||
if (this.syncLoading || this.tableLoading) { return }
|
||||
if (!this.selectedRows.length) { this.$message.warning("请先选择需要同步的员工"); return }
|
||||
this.$confirm("确定同步选中的 " + this.selectedRows.length + " 名员工到华住吗?", "提示", {type: "warning"}).then(function () {
|
||||
self.$set(self, "tableLoading", true);
|
||||
return $.post(loc() + "/syncUsers", {userIds: self.selectedRows.map(function (row) { return row.id })})
|
||||
}).then(function (res) {
|
||||
if (res && res.code === 0) {
|
||||
var failed = (res.data || []).filter(function (item) { return !item.success });
|
||||
self.$message.success("同步完成,成功 " + ((res.data || []).length - failed.length) + " 人,失败 " + failed.length + " 人");
|
||||
if (failed.length) { self.$alert(failed.map(function (item) { return item.userName + "(" + item.loginName + "):" + item.message }).join("\n"), "失败明细") }
|
||||
} else if (res) { self.$message.warning(res.msg || "同步失败") }
|
||||
}).catch(function () {}).then(function () { self.$set(self, "tableLoading", false) })
|
||||
const userIds = this.selectedRows.map((row) => row.id);
|
||||
this.$set(this, "syncLoading", true);
|
||||
this.confirmSync("确定同步选中的 " + userIds.length + " 名员工到华住吗?", "/syncUsers", {userIds: userIds});
|
||||
},
|
||||
queryStatus: function (row) {
|
||||
var self = this;
|
||||
// 先读取包含实际单位名称的规则;只有确认后才调用全量规则同步接口。
|
||||
syncRuleUsers() {
|
||||
if (this.syncLoading || this.tableLoading) { return }
|
||||
this.$set(this, "syncLoading", true);
|
||||
let description = "";
|
||||
$.post(loc() + "/syncRuleDescription", {}).then((res) => {
|
||||
if (!res || res.code !== 0 || !res.data || !res.data.description) {
|
||||
this.$message.warning((res && res.msg) || "无法获取同步规则中的单位名称,请检查单位信息");
|
||||
return;
|
||||
}
|
||||
description = res.data.description;
|
||||
}, () => {
|
||||
this.$message.error("无法获取同步规则中的单位名称,请检查单位信息");
|
||||
}).always(() => {
|
||||
if (!description) { this.$set(this, "syncLoading", false); return }
|
||||
// 项目使用旧版 jQuery,完成读取后再开启原生确认 Promise,避免提前解除同步锁。
|
||||
const message = "确定将符合以下规则的人员同步至华住会吗? " + description
|
||||
+ " 本次将同步全部符合规则的有效人员,不受当前搜索条件、分页或勾选范围限制。";
|
||||
this.confirmSync(message, "/syncRuleUsers", {});
|
||||
});
|
||||
},
|
||||
// message 为中文同步范围,path/params 为确认后才提交的接口及参数;取消不推送。
|
||||
confirmSync(message, path, params) {
|
||||
this.$confirm(message, "同步确认", {
|
||||
type: "warning", confirmButtonText: "确定同步", cancelButtonText: "取消"
|
||||
}).then(() => this.submitSync(path, params)).catch((reason) => {
|
||||
if (reason !== "cancel" && reason !== "close") {
|
||||
this.$message.error("同步请求失败,部分人员可能已同步,请核实状态后再操作");
|
||||
}
|
||||
}).finally(() => { this.$set(this, "syncLoading", false) });
|
||||
},
|
||||
// path 为本菜单的同步接口后缀;params 为选中用户主键数组或规则同步的空参数。
|
||||
// 响应 data 为逐人结果数组,success 表示是否成功,message 为结果说明。
|
||||
submitSync(path, params) {
|
||||
this.$set(this, "tableLoading", true);
|
||||
$.post(loc() + "/queryStatus", {userId: row.id}).then(function (res) {
|
||||
if (res.code === 0) { self.$set(self, "statusData", res.data); self.$set(self, "statusDialogVisible", true) } else { self.$message.warning(res.msg || "查询失败") }
|
||||
}).catch(function (xhr) {
|
||||
var message = xhr && xhr.responseJSON && xhr.responseJSON.msg;
|
||||
self.$message.error(message || "查询华住状态失败,请稍后重试");
|
||||
}).then(function () { self.$set(self, "tableLoading", false) })
|
||||
return $.post(loc() + path, params).then((res) => {
|
||||
if (!res || res.code !== 0) {
|
||||
this.$message.warning((res && res.msg) || "同步失败");
|
||||
return;
|
||||
}
|
||||
const results = res.data || [];
|
||||
if (!results.length) { this.$message.info("没有符合规则的人员需要同步"); return }
|
||||
const failed = results.filter((item) => !item.success);
|
||||
const message = "同步完成,成功 " + (results.length - failed.length) + " 人,失败 " + failed.length + " 人";
|
||||
if (failed.length) {
|
||||
this.$message.warning(message);
|
||||
this.$alert(failed.map((item) => (item.userName || "未知姓名") + "(" + (item.loginName || item.userId) + "):" + item.message).join("\n"), "失败明细")
|
||||
.catch(() => { /* 关闭失败明细不影响本次同步结果。 */ });
|
||||
} else { this.$message.success(message) }
|
||||
}).always(() => { this.$set(this, "tableLoading", false) });
|
||||
},
|
||||
queryStatus(row) {
|
||||
this.$set(this, "tableLoading", true);
|
||||
$.post(loc() + "/queryStatus", {userId: row.id}).then((res) => {
|
||||
if (res.code === 0) { this.$set(this, "statusData", res.data); this.$set(this, "statusDialogVisible", true) } else { this.$message.warning(res.msg || "查询失败") }
|
||||
}, (xhr) => {
|
||||
const message = xhr && xhr.responseJSON && xhr.responseJSON.msg;
|
||||
this.$message.error(message || "查询华住状态失败,请稍后重试");
|
||||
}).always(() => { this.$set(this, "tableLoading", false) })
|
||||
}
|
||||
},
|
||||
created: function () { this.pageData() }
|
||||
created() { this.pageData() }
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
|
||||
Reference in New Issue
Block a user