同步用户数据

This commit is contained in:
luojiaquan
2026-09-29 16:08:27 +08:00
parent b363945e26
commit 61a7aaf096
10 changed files with 686 additions and 1 deletions
@@ -29,6 +29,7 @@ import com.bms.common.enums.BusinessType;
import com.bms.common.utils.SecurityUtils;
import com.bms.common.utils.StringUtils;
import com.bms.common.utils.poi.ExcelUtil;
import com.bms.system.orgsync.OrgSyncService;
import com.bms.system.service.ISysDeptService;
import com.bms.system.service.ISysPostService;
import com.bms.system.service.ISysRoleService;
@@ -55,6 +56,9 @@ public class SysUserController extends BaseController
@Autowired
private ISysPostService postService;
@Autowired
private OrgSyncService orgSyncService;
/**
* 获取用户列表
*/
@@ -67,6 +71,19 @@ public class SysUserController extends BaseController
return getDataTable(list);
}
/**
* 从老系统(Oracle)同步部门/角色/用户。
* 覆盖式迁移:除内置超级管理员外,现有演示部门、角色、用户将被替换。
*/
@PreAuthorize("@ss.hasPermi('system:user:add')")
@Log(title = "用户管理-老系统组织同步", businessType = BusinessType.IMPORT)
@PostMapping("/syncFromOracle")
public AjaxResult syncFromOracle()
{
Map<String, Object> result = orgSyncService.syncFromOracle();
return AjaxResult.success(String.valueOf(result.get("summary")), result);
}
/**
* 获取用户下拉选项(业务员/客服/采购员等选择用)。
* 不加 @PreAuthorize:登录即可访问,只返回 id/账号/姓名/部门等展示字段,
@@ -0,0 +1,66 @@
package com.bms.system.orgsync;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.bms.common.annotation.DataSource;
import com.bms.common.enums.DataSourceType;
import com.bms.system.orgsync.mapper.OracleOrgSyncMapper;
/**
* Oracle 组织/用户/角色读取器。
* 走 SLAVE(Oracle 只读账号)数据源;必须独立 Bean,
* 否则 @DataSource 切面在同类自调用时不生效。
*
* @author bms
*/
@Service
public class OracleOrgReader
{
@Autowired
private OracleOrgSyncMapper oracleOrgSyncMapper;
@DataSource(DataSourceType.SLAVE)
public List<Map<String, Object>> readAllDept()
{
try
{
PageHelper.clearPage();
return oracleOrgSyncMapper.selectAllTabDept();
}
finally
{
PageHelper.clearPage();
}
}
@DataSource(DataSourceType.SLAVE)
public List<Map<String, Object>> readAllEmployee()
{
try
{
PageHelper.clearPage();
return oracleOrgSyncMapper.selectAllTabEmployee();
}
finally
{
PageHelper.clearPage();
}
}
@DataSource(DataSourceType.SLAVE)
public List<Map<String, Object>> readAllRole()
{
try
{
PageHelper.clearPage();
return oracleOrgSyncMapper.selectAllSysRole();
}
finally
{
PageHelper.clearPage();
}
}
}
@@ -0,0 +1,350 @@
package com.bms.system.orgsync;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.bms.common.core.domain.entity.SysDept;
import com.bms.common.core.domain.entity.SysRole;
import com.bms.common.core.domain.entity.SysUser;
/**
* 老系统组织架构(Oracle)-> BMS(MySQL)覆盖式迁移。
*
* 部门:TAB_DEPT 11 个部门统一挂到根节点“威狮国际”(dept_id=200)下,子部门 201 起顺序编号;
* 角色:T_SYS_ROLE 有效内部角色原样迁入,role_id 沿用 Oracle ID,不带菜单权限;
* 用户:TAB_EMPLOYEE 全量迁入,EMPLOYEE_CODE 作登录账号;user_id 取 Oracle USER_ID,
* USER_ID 为空时取 EMP_ID;默认密码 123456;不分配角色。
* 内置超级管理员 admin(user_id=1)/超级管理员角色(role_id=1)保留,仅将 admin 调到根部门。
*
* @author bms
*/
@Service
public class OrgSyncService
{
private static final Logger log = LoggerFactory.getLogger(OrgSyncService.class);
/** 根部门 ID(威狮国际) */
public static final long ROOT_DEPT_ID = 200L;
private static final long FIRST_CHILD_DEPT_ID = 201L;
private static final String ROOT_DEPT_NAME = "威狮国际";
/** 写库人标记 */
public static final String SYNC_MARKER = "oracle-sync";
/** 新用户默认密码(BCrypt,明文 123456) */
private static final String DEFAULT_PASSWORD =
"$2a$10$gAOzrNJaYLM2m85.9ykkLO0IPvQktxqee8RVpAu1e3.J0Ujiv4Z0G";
/** 老系统内置 admin 账号不迁移,避免覆盖 BMS 超级管理员 */
private static final String BUILTIN_ADMIN = "admin";
@Autowired
private OracleOrgReader oracleOrgReader;
@Autowired
private OrgSyncWriter orgSyncWriter;
/**
* 执行一次全量迁移
*/
public Map<String, Object> syncFromOracle()
{
long t0 = System.currentTimeMillis();
List<Map<String, Object>> deptRows = oracleOrgReader.readAllDept();
List<Map<String, Object>> roleRows = oracleOrgReader.readAllRole();
List<Map<String, Object>> empRows = oracleOrgReader.readAllEmployee();
// ---- 部门 ----
List<SysDept> depts = buildDepts(deptRows);
Map<String, Long> deptIdByCode = new HashMap<>();
for (SysDept d : depts)
{
if (d.getParentId() == ROOT_DEPT_ID)
{
deptIdByCode.put(d.getDeptName(), d.getDeptId());
}
}
// ---- 角色 ----
List<SysRole> roles = buildRoles(roleRows);
// ---- 用户 ----
List<SysUser> users = buildUsers(empRows, deptIdByCode);
orgSyncWriter.writeAll(depts, roles, users, ROOT_DEPT_ID);
long disabled = users.stream().filter(u -> "1".equals(u.getStatus())).count();
long cost = System.currentTimeMillis() - t0;
String summary = String.format(
"老系统组织同步完成:部门 %d 个(含根节点“%s”),角色 %d 个(不含权限),用户 %d 个(启用 %d/停用 %d,默认密码 123456),耗时 %dms",
depts.size(), ROOT_DEPT_NAME, roles.size(), users.size(), users.size() - disabled, disabled, cost);
log.info(summary);
Map<String, Object> result = new LinkedHashMap<>();
result.put("deptCount", depts.size());
result.put("roleCount", roles.size());
result.put("userCount", users.size());
result.put("enabledUserCount", users.size() - disabled);
result.put("disabledUserCount", disabled);
result.put("costMs", cost);
result.put("summary", summary);
return result;
}
private List<SysDept> buildDepts(List<Map<String, Object>> rows)
{
List<SysDept> list = new ArrayList<>();
SysDept root = newDept(ROOT_DEPT_ID, 0L, "0", ROOT_DEPT_NAME, 0);
list.add(root);
long id = FIRST_CHILD_DEPT_ID;
int order = 1;
Set<String> seen = new HashSet<>();
for (Map<String, Object> row : rows)
{
String code = clean(str(row, "DEPT_CODE"));
String name = clean(str(row, "DEPT_NAME"));
String deptName = name != null ? name : code;
if (code == null || !seen.add(code))
{
continue;
}
list.add(newDept(id++, ROOT_DEPT_ID, "0," + ROOT_DEPT_ID, deptName, order++));
}
return list;
}
private SysDept newDept(long id, long parentId, String ancestors, String name, int order)
{
SysDept d = new SysDept();
d.setDeptId(id);
d.setParentId(parentId);
d.setAncestors(ancestors);
d.setDeptName(name);
d.setOrderNum(order);
d.setStatus("0");
d.setDelFlag("0");
d.setCreateBy(SYNC_MARKER);
d.setCreateTime(new Date());
return d;
}
private List<SysRole> buildRoles(List<Map<String, Object>> rows)
{
List<SysRole> list = new ArrayList<>();
Set<Long> seenIds = new HashSet<>();
int sort = 1;
for (Map<String, Object> row : rows)
{
Long rid = lng(row, "ID");
String name = clean(str(row, "ROLE_NAME"));
if (rid == null || name == null || !seenIds.add(rid))
{
continue;
}
SysRole r = new SysRole();
r.setRoleId(rid);
r.setRoleName(truncate(name, 30));
r.setRoleKey("ORA_" + rid);
r.setRoleSort(sort++);
r.setDataScope("1");
r.setMenuCheckStrictly(true);
r.setDeptCheckStrictly(true);
r.setStatus("0");
r.setDelFlag("0");
r.setCreateBy(SYNC_MARKER);
r.setCreateTime(new Date());
r.setRemark(truncate(clean(str(row, "ROLE_DESC")), 500));
list.add(r);
}
return list;
}
private List<SysUser> buildUsers(List<Map<String, Object>> rows, Map<String, Long> deptIdByCode)
{
List<SysUser> list = new ArrayList<>();
Set<Long> seenIds = new HashSet<>();
Set<String> seenNames = new HashSet<>();
int skipped = 0;
for (Map<String, Object> row : rows)
{
String code = clean(str(row, "EMPLOYEE_CODE"));
String name = clean(str(row, "EMPLOYEE_NAME"));
if (code == null || name == null)
{
skipped++;
continue;
}
if (BUILTIN_ADMIN.equalsIgnoreCase(code))
{
// 保留 BMS 内置超级管理员,不被老系统 admin 覆盖
skipped++;
continue;
}
// ID:优先 USER_ID,为空取 EMP_ID
Long uid = lng(row, "USER_ID");
if (uid == null)
{
uid = lng(row, "EMP_ID");
}
if (uid == null || !seenIds.add(uid) || !seenNames.add(code))
{
log.warn("用户同步跳过:{}({}),ID 缺失或重复", code, name);
skipped++;
continue;
}
SysUser u = new SysUser();
u.setUserId(uid);
String deptCode = clean(str(row, "DEPT_CODE"));
Long deptId = deptCode == null ? null : deptIdByCode.get(deptCode);
u.setDeptId(deptId != null ? deptId : ROOT_DEPT_ID);
u.setUserName(code);
u.setNickName(truncate(name, 30));
u.setPassword(DEFAULT_PASSWORD);
u.setStatus("1".equals(clean(str(row, "BL_OPEN"))) ? "0" : "1");
u.setSex(mapSex(clean(str(row, "SEX"))));
u.setEmail(cleanEmail(str(row, "EMAIL")));
u.setPhonenumber(cleanPhone(str(row, "MOBILE_PHONE")));
u.setRemark(truncate(clean(str(row, "REMARK")), 500));
Object createDate = row.get("CREATE_DATE");
if (createDate instanceof Date)
{
u.setCreateTime((Date) createDate);
}
else
{
u.setCreateTime(new Date());
}
u.setCreateBy(SYNC_MARKER);
list.add(u);
}
if (skipped > 0)
{
log.warn("用户同步共跳过 {} 条(内置 admin / 编码或ID重复 / 关键字段为空)", skipped);
}
return list;
}
/** Oracle:1男 0女;BMS:0男 1女 2未知 */
private static String mapSex(String sex)
{
if ("1".equals(sex))
{
return "0";
}
if ("0".equals(sex))
{
return "1";
}
return "2";
}
/** 老系统手机号存在加密脏值,仅接收纯号码/短横线/加号格式且不超过 11 位 */
private static String cleanPhone(String v)
{
String s = clean(v);
if (s == null)
{
return null;
}
s = s.replace(" ", "");
if (s.length() > 11 || !s.matches("[0-9+\\-]{6,11}"))
{
return null;
}
return s;
}
private static String cleanEmail(String v)
{
String s = clean(v);
if (s == null || s.length() > 50 || !s.contains("@"))
{
return null;
}
return s;
}
private static String truncate(String v, int max)
{
if (v == null)
{
return null;
}
return v.length() > max ? v.substring(0, max) : v;
}
private static String clean(String v)
{
if (v == null)
{
return null;
}
String s = v.trim();
return s.isEmpty() ? null : s;
}
private static String str(Map<String, Object> row, String key)
{
Object v = getIgnoreCase(row, key);
return v == null ? null : String.valueOf(v);
}
/** Oracle NUMBER 经 JDBC 多为 BigDecimal */
private static Long lng(Map<String, Object> row, String key)
{
Object v = getIgnoreCase(row, key);
if (v == null)
{
return null;
}
if (v instanceof Number)
{
return ((Number) v).longValue();
}
String s = String.valueOf(v).trim();
if (s.isEmpty())
{
return null;
}
int dot = s.indexOf('.');
if (dot >= 0)
{
s = s.substring(0, dot);
}
try
{
return Long.parseLong(s);
}
catch (NumberFormatException e)
{
return null;
}
}
private static Object getIgnoreCase(Map<String, Object> row, String key)
{
if (row.containsKey(key))
{
return row.get(key);
}
for (Map.Entry<String, Object> e : row.entrySet())
{
if (e.getKey() != null && e.getKey().equalsIgnoreCase(key))
{
return e.getValue();
}
}
return null;
}
}
@@ -0,0 +1,62 @@
package com.bms.system.orgsync;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.bms.common.core.domain.entity.SysDept;
import com.bms.common.core.domain.entity.SysRole;
import com.bms.common.core.domain.entity.SysUser;
import com.bms.system.orgsync.mapper.SysOrgSyncWriterMapper;
/**
* 组织迁移写库。独立 Bean:保证 @Transactional 经代理生效,且与 SLAVE 读连接隔离。
* 单个事务内覆盖式重建:除内置超级管理员(user_id=1 / role_id=1)外全部替换。
*
* @author bms
*/
@Service
public class OrgSyncWriter
{
/** 用户批量插入每批条数 */
private static final int USER_BATCH = 200;
@Autowired
private SysOrgSyncWriterMapper writerMapper;
@Transactional(rollbackFor = Exception.class)
public void writeAll(List<SysDept> depts, List<SysRole> roles, List<SysUser> users, Long adminDeptId)
{
// 1. 清关联(保留 admin <-> 超级管理员角色)
writerMapper.deleteAllRoleDept();
writerMapper.deleteRoleMenuKeepAdmin();
writerMapper.deleteUserRoleKeepAdmin();
writerMapper.deleteUserPostKeepAdmin();
// 2. 清用户/角色/部门
writerMapper.deleteUsersKeepAdmin();
writerMapper.deleteRolesKeepAdmin();
writerMapper.deleteAllDept();
// 3. 重建部门
for (SysDept d : depts)
{
writerMapper.insertDept(d);
}
// 4. 重建角色(不带任何菜单权限)
for (SysRole r : roles)
{
writerMapper.insertRole(r);
}
// 5. 重建用户(分批,避免单条 SQL 过长)
for (int i = 0; i < users.size(); i += USER_BATCH)
{
writerMapper.batchInsertUser(users.subList(i, Math.min(i + USER_BATCH, users.size())));
}
// 6. 超级管理员挂到根部门
writerMapper.updateUserDept(1L, adminDeptId);
}
}
@@ -0,0 +1,21 @@
package com.bms.system.orgsync.mapper;
import java.util.List;
import java.util.Map;
/**
* 老系统 Oracle 组织/用户/角色只读查询(SLAVE 数据源,账号只读)
*
* @author bms
*/
public interface OracleOrgSyncMapper
{
/** TAB_DEPT 全部部门(扁平结构,DEPT_CODE=DEPT_NAME) */
List<Map<String, Object>> selectAllTabDept();
/** TAB_EMPLOYEE 全部员工 */
List<Map<String, Object>> selectAllTabEmployee();
/** T_SYS_ROLE 有效角色(REC_FLAG=1,内部角色 ROLE_TYPE=100) */
List<Map<String, Object>> selectAllSysRole();
}
@@ -0,0 +1,46 @@
package com.bms.system.orgsync.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.bms.common.core.domain.entity.SysDept;
import com.bms.common.core.domain.entity.SysRole;
import com.bms.common.core.domain.entity.SysUser;
/**
* 组织架构老系统数据迁移写库(MASTER 数据源)。
* 覆盖式迁移:除内置超级管理员(user_id=1 / role_id=1)外,
* 现有演示部门、角色、用户全部清空后按 Oracle 数据重建。
*
* @author bms
*/
public interface SysOrgSyncWriterMapper
{
/** 清空角色-部门(自定义数据范围)关联 */
int deleteAllRoleDept();
/** 清空全部部门 */
int deleteAllDept();
/** 新增部门 */
int insertDept(SysDept dept);
/** 清空除超级管理员角色(role_id=1)以外角色的菜单、用户关联 */
int deleteRoleMenuKeepAdmin();
int deleteUserRoleKeepAdmin();
/** 删除除超级管理员角色外的全部角色 */
int deleteRolesKeepAdmin();
/** 新增角色 */
int insertRole(SysRole role);
/** 删除除超级管理员(user_id=1)以外用户的岗位关联与用户 */
int deleteUserPostKeepAdmin();
int deleteUsersKeepAdmin();
/** 新增用户(批量) */
int batchInsertUser(@Param("list") List<SysUser> list);
/** 将指定用户挂到根部门 */
int updateUserDept(@Param("userId") Long userId, @Param("deptId") Long deptId);
}
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bms.system.orgsync.mapper.OracleOrgSyncMapper">
<!-- TAB_DEPT:老系统部门,扁平表,仅 11 个部门;迁移时统一挂到“威狮国际”根节点下 -->
<select id="selectAllTabDept" resultType="java.util.HashMap" fetchSize="500">
SELECT DEPT_CODE, DEPT_NAME
FROM WEISHI_USER.TAB_DEPT
ORDER BY DEPT_CODE
</select>
<!-- TAB_EMPLOYEE:员工;EMPLOYEE_CODE 作为登录账号,USER_ID 为空时用 EMP_ID 作为新库用户ID -->
<select id="selectAllTabEmployee" resultType="java.util.HashMap" fetchSize="500">
SELECT EMPLOYEE_CODE, EMPLOYEE_NAME, DEPT_CODE, PHONE, MOBILE_PHONE,
SEX, BL_OPEN, EMAIL, REMARK, CREATE_DATE, USER_ID, EMP_ID
FROM WEISHI_USER.TAB_EMPLOYEE
ORDER BY EMPLOYEE_CODE
</select>
<!-- T_SYS_ROLE:只迁有效内部角色;角色菜单权限(sys_role_menu)不迁移 -->
<select id="selectAllSysRole" resultType="java.util.HashMap" fetchSize="500">
SELECT ID, ROLE_NAME, ROLE_DESC
FROM WEISHI_USER.T_SYS_ROLE
WHERE REC_FLAG = 1 AND ROLE_TYPE = '100'
ORDER BY ID
</select>
</mapper>
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bms.system.orgsync.mapper.SysOrgSyncWriterMapper">
<delete id="deleteAllRoleDept">
delete from sys_role_dept
</delete>
<delete id="deleteAllDept">
delete from sys_dept
</delete>
<insert id="insertDept" parameterType="com.bms.common.core.domain.entity.SysDept">
insert into sys_dept(dept_id, parent_id, ancestors, dept_name, order_num, leader, phone, email,
status, del_flag, create_by, create_time)
values(#{deptId}, #{parentId}, #{ancestors}, #{deptName}, #{orderNum}, #{leader}, #{phone}, #{email},
#{status}, '0', #{createBy}, sysdate())
</insert>
<delete id="deleteRoleMenuKeepAdmin">
delete from sys_role_menu where role_id &lt;&gt; 1
</delete>
<delete id="deleteUserRoleKeepAdmin">
delete from sys_user_role where role_id &lt;&gt; 1
</delete>
<delete id="deleteRolesKeepAdmin">
delete from sys_role where role_id &lt;&gt; 1
</delete>
<insert id="insertRole" parameterType="com.bms.common.core.domain.entity.SysRole">
insert into sys_role(role_id, role_name, role_key, role_sort, data_scope,
menu_check_strictly, dept_check_strictly, status, del_flag,
create_by, create_time, remark)
values(#{roleId}, #{roleName}, #{roleKey}, #{roleSort}, #{dataScope},
1, 1, '0', '0', #{createBy}, sysdate(), #{remark})
</insert>
<delete id="deleteUserPostKeepAdmin">
delete from sys_user_post where user_id &lt;&gt; 1
</delete>
<delete id="deleteUsersKeepAdmin">
delete from sys_user where user_id &lt;&gt; 1
</delete>
<insert id="batchInsertUser" parameterType="java.util.List">
insert into sys_user(user_id, dept_id, user_name, nick_name, user_type, email, phonenumber, sex,
password, status, del_flag, create_by, create_time, remark)
values
<foreach collection="list" item="u" separator=",">
(#{u.userId}, #{u.deptId}, #{u.userName}, #{u.nickName}, '00', #{u.email}, #{u.phonenumber},
#{u.sex}, #{u.password}, #{u.status}, '0', #{u.createBy},
<choose><when test="u.createTime != null">#{u.createTime}</when><otherwise>sysdate()</otherwise></choose>,
#{u.remark})
</foreach>
</insert>
<update id="updateUserDept">
update sys_user set dept_id = #{deptId} where user_id = #{userId}
</update>
</mapper>
+9
View File
@@ -35,6 +35,15 @@ export function addUser(data) {
})
}
// 从老系统(Oracle)同步部门/角色/用户(覆盖式迁移)
export function syncUsersFromOracle() {
return request({
url: '/system/user/syncFromOracle',
method: 'post',
timeout: 120000
})
}
// 修改用户
export function updateUser(data) {
return request({
+21 -1
View File
@@ -28,6 +28,9 @@
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Refresh" :loading="syncLoading" @click="handleSyncFromOracle" v-hasPermi="['system:user:add']">TMS系统同步用户数据</el-button>
</el-col>
</template>
<template #col-userName="{ row }">
@@ -160,7 +163,7 @@ import TreePanel from "@/components/TreePanel"
import ExcelImportDialog from "@/components/ExcelImportDialog"
import UserViewDrawer from "./view"
import { usePasswordRule } from "@/utils/passwordRule"
import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user"
import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect, syncUsersFromOracle } from "@/api/system/user"
import { nextTick } from "vue"
const router = useRouter()
@@ -169,6 +172,7 @@ const { pwdValidator, pwdPromptValidator } = usePasswordRule()
const { sys_normal_disable, sys_user_sex } = useDict("sys_normal_disable", "sys_user_sex")
const tableRef = ref()
const syncLoading = ref(false)
const open = ref(false)
const title = ref("")
const deptId = ref(undefined)
@@ -257,6 +261,22 @@ function handleDelete(userIds) {
}).catch(() => {})
}
/** 从老系统(Oracle)同步部门/角色/用户 */
function handleSyncFromOracle() {
proxy.$modal.confirm(
'将从老系统同步部门(威狮国际及其下级部门)、角色、用户数据。注意:同步为覆盖式迁移,除超级管理员外,系统现有部门、角色、用户将被老系统数据替换(角色权限需另行配置,新用户默认密码 123456)。是否继续?'
).then(() => {
syncLoading.value = true
return syncUsersFromOracle()
}).then(res => {
proxy.$modal.msgSuccess(res.msg || '同步成功')
getDeptTree()
tableRef.value.refresh()
}).catch(() => {}).finally(() => {
syncLoading.value = false
})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/user/export", {