feat: 新增数据管理模块(区域管理)及修复前端已知问题

后端(bms-back):
- 新增区域管理完整后端:Domain/Mapper/Service/Controller + MyBatis XML
- 新增 RestTemplateConfig 配置类,用于第三方API调用
- 新增 countries.json 本地国家数据源(105个国家)
- RuoYiApplication 加 @EnableAsync 支持异步任务
- application-druid.yml 修复 Druid 连接池字符集配置(SET NAMES utf8mb4)
- logback.xml 日志路径改为 ${user.dir}/logs 避免沙箱写入受限
- pom.xml 增加 JVM 编码参数(-Dfile.encoding=UTF-8)
- 新增 sql/bms_region.sql 建表脚本+菜单权限

前端(bms-front):
- 新增区域管理页面(列表/编辑/状态切换/同步国家数据/导出)
- 新增同步日志功能(内嵌为区域管理弹窗,移除独立菜单)
- 新增 API 层: region.js / region-log.js
- 修复 BasicForm/index.vue 缺失 import FormControl 导致搜索栏控件不渲染
- 修复 user/role/region 三个页面 el-switch 初始化时弹 undefined 提示
This commit is contained in:
wuweihua
2026-08-31 11:01:25 +08:00
parent b003b73b77
commit 44d2b690de
28 changed files with 2318 additions and 1105 deletions
+19 -3
View File
@@ -179,6 +179,7 @@
<script setup name="Role">
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role"
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu"
import { nextTick } from "vue"
const router = useRouter()
const { proxy } = getCurrentInstance()
@@ -263,13 +264,28 @@ function handleExport() {
/** 角色状态修改 */
function handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
proxy.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function () {
if (row.roleId === undefined || row.roleId === null || row.roleId === '' ||
row.roleName === undefined || row.roleName === null || row.roleName === '') {
nextTick(() => {
row.status = row.status === "0" ? "1" : "0"
})
return
}
if (row.__originalStatus !== undefined && row.__originalStatus === row.status) {
return
}
row.__originalStatus = row.status === "0" ? "1" : "0"
const text = row.status === "0" ? "启用" : "停用"
proxy.$modal.confirm(`确认要${text}「${row.roleName}」角色吗?`).then(function () {
return changeRoleStatus(row.roleId, row.status)
}).then(() => {
row.__originalStatus = row.status
proxy.$modal.msgSuccess(text + "成功")
}).catch(function () {
row.status = row.status === "0" ? "1" : "0"
const restored = row.status === "0" ? "1" : "0"
row.__originalStatus = restored
nextTick(() => { row.status = restored })
})
}
+24 -3
View File
@@ -161,6 +161,7 @@ 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 { nextTick } from "vue"
const router = useRouter()
const { proxy } = getCurrentInstance()
@@ -265,13 +266,33 @@ function handleExport() {
/** 用户状态修改 */
function handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
proxy.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
// 守卫:页面初始化/数据加载过程中 el-switch 可能发生赋值抖动,
// userId 或 userName 缺失时不弹确认,只把状态反向重置防止显示偏差
if (row.userId === undefined || row.userId === null || row.userId === '' ||
row.userName === undefined || row.userName === null || row.userName === '') {
nextTick(() => {
row.status = row.status === "0" ? "1" : "0"
})
return
}
// 与原始记录中的 status 对比:status 只能是字符串 "0"/"1",若不一致(如 loading 中被改)则回滚
if (row.__originalStatus !== undefined && row.__originalStatus === row.status) {
return
}
// 为当前行记录一次原始值,后面 catch 时与回滚同步,避免重复触发 change
row.__originalStatus = row.status === "0" ? "1" : "0"
const text = row.status === "0" ? "启用" : "停用"
proxy.$modal.confirm(`确认要${text}「${row.userName}」用户吗?`).then(function () {
return changeUserStatus(row.userId, row.status)
}).then(() => {
row.__originalStatus = row.status
proxy.$modal.msgSuccess(text + "成功")
}).catch(function () {
row.status = row.status === "0" ? "1" : "0"
const restored = row.status === "0" ? "1" : "0"
row.__originalStatus = restored
// 回滚赋值时短暂忽略 change,防止递归弹框
nextTick(() => { row.status = restored })
})
}