feat: 封装公共表单/表格组件 BasicForm/BasicTable,并替换业务页面表格

- 新增 BasicForm 配置驱动表单组件,支持多种控件、字典自动加载、校验、插槽扩展
- 新增 BasicTable 公共表格组件,集成搜索栏+工具栏+表格+分页,基于 columns/searchColumns 配置驱动
- 替换 18 个业务页面 el-table 为 BasicTable(post/user/role/dict/config/notice/job/log/logininfor/operlog/online/gen 等)
- 全局注册 BasicForm、BasicTable 组件
- 项目标题由若依管理系统改为 BMS
This commit is contained in:
wuweihua
2026-08-28 11:35:26 +08:00
parent 838965c5a1
commit 3e9b34e0fd
27 changed files with 4593 additions and 4916 deletions
+151 -123
View File
@@ -1,123 +1,151 @@
<template>
<div class="app-container">
<h4 class="form-header h4">基本信息</h4>
<el-form :model="form" label-width="80px">
<el-row>
<el-col :span="8" :offset="2">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" disabled />
</el-form-item>
</el-col>
<el-col :span="8" :offset="2">
<el-form-item label="登录账号" prop="userName">
<el-input v-model="form.userName" disabled />
</el-form-item>
</el-col>
</el-row>
</el-form>
<h4 class="form-header h4">角色信息</h4>
<el-table v-loading="loading" :row-key="getRowKey" @row-click="clickRow" ref="roleRef" @selection-change="handleSelectionChange" :data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)">
<el-table-column label="序号" width="55" type="index" align="center">
<template #default="scope">
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55"></el-table-column>
<el-table-column label="角色编号" align="center" prop="roleId" />
<el-table-column label="角色名称" align="center" prop="roleName" />
<el-table-column label="权限字符" align="center" prop="roleKey" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
<el-form label-width="100px">
<div style="text-align: center;margin-left:-120px;margin-top:30px;">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
</div>
</el-form>
</div>
</template>
<script setup name="AuthRole">
import { getAuthRole, updateAuthRole } from "@/api/system/user"
const route = useRoute()
const { proxy } = getCurrentInstance()
const loading = ref(true)
const total = ref(0)
const pageNum = ref(1)
const pageSize = ref(10)
const roleIds = ref([])
const roles = ref([])
const form = ref({
nickName: undefined,
userName: undefined,
userId: undefined
})
/** 单击选中行数据 */
function clickRow(row) {
if (checkSelectable(row)) {
proxy.$refs["roleRef"].toggleRowSelection(row)
}
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
roleIds.value = selection.map(item => item.roleId)
}
/** 保存选中的数据编号 */
function getRowKey(row) {
return row.roleId
}
// 检查角色状态
function checkSelectable(row) {
return row.status === "0" ? true : false
}
/** 关闭按钮 */
function close() {
const obj = { path: "/system/user" }
proxy.$tab.closeOpenPage(obj)
}
/** 提交按钮 */
function submitForm() {
const userId = form.value.userId
const rIds = roleIds.value.join(",")
updateAuthRole({ userId: userId, roleIds: rIds }).then(() => {
proxy.$modal.msgSuccess("授权成功")
close()
})
}
(() => {
const userId = route.params && route.params.userId
if (userId) {
loading.value = true
getAuthRole(userId).then(response => {
form.value = response.user
roles.value = response.roles
total.value = roles.value.length
nextTick(() => {
roles.value.forEach(row => {
if (row.flag) {
proxy.$refs["roleRef"].toggleRowSelection(row)
}
})
})
loading.value = false
})
}
})()
</script>
<template>
<div class="app-container">
<h4 class="form-header h4">基本信息</h4>
<el-form :model="form" label-width="80px">
<el-row>
<el-col :span="8" :offset="2">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" disabled />
</el-form-item>
</el-col>
<el-col :span="8" :offset="2">
<el-form-item label="登录账号" prop="userName">
<el-input v-model="form.userName" disabled />
</el-form-item>
</el-col>
</el-row>
</el-form>
<h4 class="form-header h4">角色信息</h4>
<basic-table
ref="tableRef"
:columns="columns"
:query="queryList"
:extra-params="extraParams"
row-key="roleId"
:show-index="true"
:show-toolbar="false"
@row-click="clickRow"
@selection-change="handleSelectionChange"
/>
<el-form label-width="100px">
<div style="text-align: center;margin-left:-120px;margin-top:30px;">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
</div>
</el-form>
</div>
</template>
<script setup name="AuthRole">
import { getAuthRole, updateAuthRole } from "@/api/system/user"
const route = useRoute()
const { proxy } = getCurrentInstance()
const tableRef = ref()
const form = ref({
nickName: undefined,
userName: undefined,
userId: undefined
})
const allRoles = ref([])
const currentPageRows = ref([])
const selectedRoleIds = ref(new Set())
// 固定参数:用户 ID(每次请求合并传入)
const extraParams = reactive({ userId: route.params.userId })
// 表格列配置
const columns = [
{ label: "角色编号", prop: "roleId", align: "center" },
{ label: "角色名称", prop: "roleName", align: "center" },
{ label: "权限字符", prop: "roleKey", align: "center" },
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true }
]
/**
* 查询函数:本页数据由 getAuthRole 一次性返回(user + roles),
* BasicTable 走服务端分页机制,这里改为缓存全部角色后按页切片(客户端分页)。
* 跨页选择通过 selectedRoleIds 集合维护(BasicTable 内置 selection 列不支持 reserve-selection)。
*/
function queryList(params) {
const pageNum = params.pageNum || 1
const pageSize = params.pageSize || 10
if (!params.userId) {
return Promise.resolve({ rows: [], total: 0 })
}
if (!allRoles.value.length) {
return getAuthRole(params.userId).then(res => {
form.value = res.user
allRoles.value = res.roles || []
// 初始化已选中集合:原 flag 为 true 的角色
selectedRoleIds.value = new Set(
allRoles.value.filter(r => r.flag).map(r => r.roleId)
)
const total = allRoles.value.length
const rows = allRoles.value.slice((pageNum - 1) * pageSize, pageNum * pageSize)
currentPageRows.value = rows
nextTick(() => applySelection())
return { rows, total }
})
} else {
const total = allRoles.value.length
const rows = allRoles.value.slice((pageNum - 1) * pageSize, pageNum * pageSize)
currentPageRows.value = rows
nextTick(() => applySelection())
return Promise.resolve({ rows, total })
}
}
/** 按当前页回显选中状态(仅当前页可见行可被 toggleRowSelection */
function applySelection() {
const tableEl = tableRef.value?.getTableRef()
currentPageRows.value.forEach(row => {
if (selectedRoleIds.value.has(row.roleId)) {
tableEl?.toggleRowSelection(row, true)
}
})
}
/** 角色状态可选:仅正常(status==="0")角色可勾选 */
function checkSelectable(row) {
return row.status === "0"
}
/** 单击选中行数据 */
function clickRow(row) {
if (checkSelectable(row)) {
tableRef.value?.getTableRef()?.toggleRowSelection(row)
}
}
/** 多选框选中数据:按当前页回填/移除,维护跨页选中集合 */
function handleSelectionChange(selection) {
const pageSelected = new Set(selection.map(r => r.roleId))
currentPageRows.value.forEach(row => {
if (pageSelected.has(row.roleId)) {
selectedRoleIds.value.add(row.roleId)
} else {
selectedRoleIds.value.delete(row.roleId)
}
})
}
/** 关闭按钮 */
function close() {
const obj = { path: "/system/user" }
proxy.$tab.closeOpenPage(obj)
}
/** 提交按钮 */
function submitForm() {
const userId = form.value.userId
const rIds = [...selectedRoleIds.value].join(",")
updateAuthRole({ userId: userId, roleIds: rIds }).then(() => {
proxy.$modal.msgSuccess("授权成功")
close()
})
}
</script>