大屏项目初始化

This commit is contained in:
2026-03-07 12:13:00 +08:00
parent d887108e1a
commit b7bfdfd2bc
9 changed files with 222 additions and 71 deletions

View File

@@ -33,6 +33,17 @@ export function getHomeRoleAssign(data) {
}) })
} }
/**
* 保存角色信息列表
*/
export function getHomeRoleSave(data) {
return request({
url: '/biz/homeRole/save',
method: 'post',
data
})
}
/** /**
* 删除角色信息 * 删除角色信息

View File

@@ -191,7 +191,10 @@ const openedSubMenuKeys = ref([])
const getMenuList = async () => { const getMenuList = async () => {
if (!isMounted.value) return if (!isMounted.value) return
try { try {
const res = await getUserMenuList(); const reqParams = {
roleId: userStore.loginUser.roleId,
}
const res = await getUserMenuList(reqParams);
menuList.value = res || []; menuList.value = res || [];
const setMenuNameMap = (menus) => { const setMenuNameMap = (menus) => {
menus.forEach(menu => { menus.forEach(menu => {

View File

@@ -1,8 +1,99 @@
<template> <template>
<el-form
:model="formData"
:rules="formRules"
ref="formRef"
label-width="100px"
class="dialog-form-container"
>
<div class="form-row">
<div class="form-col">
<el-form-item label="角色名称" prop="roleName">
<el-input
v-model="formData.roleName"
placeholder="请输入角色名称"
clearable
:disabled="isEdit"
/>
</el-form-item>
</div>
<div class="form-col">
<el-form-item label="角色状态" prop="ustatus">
<el-select
v-model="formData.ustatus"
placeholder="请选择角色状态"
clearable
>
<el-option label="停用" value="0" />
<el-option label="在用" value="1" />
<el-option label="锁定" value="2" />
</el-select>
</el-form-item>
</div>
</div>
</el-form>
</template> </template>
<script> <script setup>
import { ref, onMounted } from 'vue'
const props = defineProps({
formData: {
type: Object,
required: true,
default: () => ({
roleName: '',
ustatus: '1',
})
},
isEdit: {
type: Boolean,
default: false
}
})
const formRef = ref(null)
const formRules = {
roleName: [ { required: true, message: '请输入角色名称', trigger: 'blur' } ],
ustatus: [ { required: true, message: '请选择角色状态', trigger: 'change' } ],
}
const validate = async () => {
if (!formRef.value) return false
try {
const valid = await formRef.value.validate()
return valid
} catch (error) {
console.error('表单验证失败:', error)
return false
}
}
const resetForm = () => {
if (formRef.value) formRef.value.resetFields()
}
defineExpose({ validate, resetForm })
</script> </script>
<style> <style scoped>
.dialog-form-container {
width: 100%;
padding: 16px;
margin: 0;
border: 1px solid rgba(64, 158, 255, 0.15);
border-radius: 8px;
box-sizing: border-box;
}
.form-row {
display: flex;
flex-wrap: wrap;
width: 100%;
margin: 0 0 16px 0;
gap: 20px;
}
.form-row:last-child { margin-bottom: 0; }
.form-col { flex: 1; min-width: 180px; }
</style> </style>

View File

@@ -20,7 +20,7 @@
</template> </template>
<template #main> <template #main>
<div class="main-content"> <div class="main-content">
<vUser /> <vUser @refresh-role-list="getListData" />
</div> </div>
</template> </template>
</ResizablePage> </ResizablePage>

View File

@@ -67,18 +67,6 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="260" align="center" fixed="right">
<template #default="scope">
<el-button size="small" type="primary" @click="handleEdit(scope.row)">
<el-icon><Edit /></el-icon>
编辑
</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.row)">
<el-icon><Delete /></el-icon>
删除
</el-button>
</template>
</el-table-column>
</template> </template>
</STable> </STable>
</div> </div>
@@ -86,6 +74,7 @@
<PDialog <PDialog
v-model="dialogVisible" v-model="dialogVisible"
:loading="saveLoading"
:title="isEdit ? '编辑数据' : '新增数据'" :title="isEdit ? '编辑数据' : '新增数据'"
@close="handleDialogClose" @close="handleDialogClose"
@reset="handleDialogReset" @reset="handleDialogReset"
@@ -101,6 +90,7 @@ import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { Plus, Download, Edit, Delete } from '@element-plus/icons-vue' import { Plus, Download, Edit, Delete } from '@element-plus/icons-vue'
import { getHomeUserList } from '@/api/bizUser' import { getHomeUserList } from '@/api/bizUser'
import { getHomeRoleSave } from '@/api/bizRole'
import CSearch from '@/components/Search/proSearch.vue' import CSearch from '@/components/Search/proSearch.vue'
import STable from '@/components/Table/proTable.vue' import STable from '@/components/Table/proTable.vue'
@@ -108,8 +98,10 @@ import PDialog from '@/components/Dialog/proDialog.vue'
import VForm from './form.vue' import VForm from './form.vue'
const formComponentRef = ref(null) const formComponentRef = ref(null)
const emit = defineEmits(['refresh-role-list'])
const loading = ref(false) const loading = ref(false)
const saveLoading = ref(false)
const searchForm = reactive({ const searchForm = reactive({
uname: '', uname: '',
ustatus: '', ustatus: '',
@@ -187,10 +179,6 @@ const handleExport = () => {
ElMessage.success('开始导出数据...') ElMessage.success('开始导出数据...')
} }
const handleDelete = (row) => {
ElMessage.warning(`删除ID为 ${row.id} 的数据`)
}
const handleSizeChange = (val) => { const handleSizeChange = (val) => {
pagination.pageSize = val pagination.pageSize = val
getDataList() getDataList()
@@ -222,12 +210,21 @@ const handleSave = async () => {
return return
} }
} }
setTimeout(() => { try {
ElMessage.success(isEdit.value ? '编辑成功' : '新增成功') saveLoading.value = true;
dialogVisible.value = false const reqParams = {
getDataList() ...formData.value
}, 500) }
const res = await getHomeRoleSave(reqParams);
ElMessage.success(res.msg)
dialogVisible.value = false
emit('refresh-role-list')
} catch (error) {
console.error('获取数据失败:', error);
} finally {
saveLoading.value = false;
}
} }
onMounted(() => { onMounted(() => {

View File

@@ -63,13 +63,31 @@ const loading = ref(false)
const menuTreeRef = ref(null) const menuTreeRef = ref(null)
const selectedMenuIds = ref([]) const selectedMenuIds = ref([])
const getLeafNodeIds = (treeData, leafIds = []) => {
treeData.forEach(node => {
if (!node.children || node.children.length === 0) {
leafIds.push(String(node.id))
} else {
getLeafNodeIds(node.children, leafIds)
}
})
return leafIds
}
const filterOnlyLeafIds = (allIds, treeData) => {
const allLeafIds = getLeafNodeIds(treeData)
return allIds.filter(id => allLeafIds.includes(id))
}
const getTreeListData = async () => { const getTreeListData = async () => {
try { try {
const res = await getTreeMenuList() const res = await getTreeMenuList()
menuTreeData.value = res ?? [] menuTreeData.value = res ?? []
return menuTreeData.value
} catch (error) { } catch (error) {
console.error('加载菜单树失败:', error) console.error('加载菜单树失败:', error)
menuTreeData.value = [] menuTreeData.value = []
return []
} }
} }
@@ -90,21 +108,38 @@ const treeProps = reactive({
disabled: 'disabled' disabled: 'disabled'
}) })
function getIndeterminateKeys(node) {
let keys = []
if (node.indeterminate) {
keys.push(node.key)
}
if (node.childNodes) {
node.childNodes.forEach(c => keys.push(...getIndeterminateKeys(c)))
}
return keys
}
function getCheckedAndIndeterminateKeys() {
if (!menuTreeRef.value) return []
const checked = menuTreeRef.value.getCheckedKeys(false)
const indeterminate = getIndeterminateKeys(menuTreeRef.value.root)
return [...new Set([...checked, ...indeterminate])]
}
onMounted(async () => { onMounted(async () => {
loading.value = true loading.value = true
try { try {
const [_, roleMenuIds] = await Promise.all([ const treeData = await getTreeListData()
getTreeListData(), const roleMenuIds = await getRoleMenuIds()
getRoleMenuIds()
])
const propsMenuIds = (props.formData?.menuIds ?? []).map(id => String(id)).filter(id => id) const propsMenuIds = (props.formData?.menuIds ?? []).map(id => String(id)).filter(id => id)
const defaultCheckedIds = roleMenuIds.length > 0 ? roleMenuIds : propsMenuIds const allMenuIds = roleMenuIds.length > 0 ? roleMenuIds : propsMenuIds
if (defaultCheckedIds.length > 0) { const leafMenuIds = filterOnlyLeafIds(allMenuIds, treeData)
selectedMenuIds.value = [...defaultCheckedIds]
if (leafMenuIds.length > 0) {
selectedMenuIds.value = [...leafMenuIds]
setTimeout(() => { setTimeout(() => {
if (menuTreeRef.value && menuTreeData.value.length) { if (menuTreeRef.value && treeData.length) {
menuTreeRef.value.setCheckedKeys(defaultCheckedIds, false) menuTreeRef.value.setCheckedKeys(leafMenuIds, false)
} }
}, 300) }, 300)
} }
@@ -116,12 +151,14 @@ onMounted(async () => {
}) })
watch(() => props.formData.menuIds, (newVal) => { watch(() => props.formData.menuIds, (newVal) => {
if (!newVal || !newVal.length || !menuTreeRef.value) return if (!newVal || !newVal.length || !menuTreeRef.value || !menuTreeData.value.length) return
const menuIds = newVal.map(id => String(id)).filter(id => id) const allMenuIds = newVal.map(id => String(id)).filter(id => id)
if (menuIds.length) { const leafMenuIds = filterOnlyLeafIds(allMenuIds, menuTreeData.value)
selectedMenuIds.value = [...menuIds]
menuTreeRef.value.setCheckedKeys(menuIds, false) if (leafMenuIds.length) {
selectedMenuIds.value = [...leafMenuIds]
menuTreeRef.value.setCheckedKeys(leafMenuIds, false)
} }
}, { deep: true }) }, { deep: true })
@@ -130,7 +167,7 @@ const handleCheck = () => {
selectedMenuIds.value = menuTreeRef.value.getCheckedKeys(false) selectedMenuIds.value = menuTreeRef.value.getCheckedKeys(false)
} }
const handleCheckChange = (data, checked, indeterminate) => { const handleCheckChange = () => {
handleCheck() handleCheck()
} }
@@ -152,7 +189,7 @@ const resetForm = () => {
defineExpose({ defineExpose({
validate, validate,
resetForm, resetForm,
getSelectedMenuIds: () => selectedMenuIds.value, getSelectedMenuIds: () => getCheckedAndIndeterminateKeys(),
getLeafMenuIds: () => menuTreeRef.value ? menuTreeRef.value.getCheckedKeys(true) : [] getLeafMenuIds: () => menuTreeRef.value ? menuTreeRef.value.getCheckedKeys(true) : []
}) })
</script> </script>

View File

@@ -138,12 +138,12 @@ const dialogVisible = ref(false)
async function getDataList() { async function getDataList() {
loading.value = true loading.value = true
try { try {
const reqParmas = { const reqParams = {
... searchForm, ... searchForm,
pageNum: pagination.pageNum, pageNum: pagination.pageNum,
pageSize: pagination.pageSize, pageSize: pagination.pageSize,
} }
const res = await getHomeUserList(reqParmas); const res = await getHomeUserList(reqParams);
pagination.total = res.total; pagination.total = res.total;
tableData.value = res.list || []; tableData.value = res.list || [];
} catch (error) { } catch (error) {

View File

@@ -3,11 +3,15 @@ package com.mini.mybigscreen.biz.controller;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mini.mybigscreen.Model.Menu; import com.mini.mybigscreen.Model.Menu;
import com.mini.mybigscreen.Model.Message; import com.mini.mybigscreen.Model.Message;
import com.mini.mybigscreen.Model.Result; import com.mini.mybigscreen.Model.Result;
import com.mini.mybigscreen.Model.TreeMenu; import com.mini.mybigscreen.Model.TreeMenu;
import com.mini.mybigscreen.biz.domain.HomeMenu; import com.mini.mybigscreen.biz.domain.HomeMenu;
import com.mini.mybigscreen.biz.domain.HomeModule;
import com.mini.mybigscreen.biz.domain.HomeRoleMenu;
import com.mini.mybigscreen.biz.mapper.HomeMenuMapper;
import com.mini.mybigscreen.biz.service.HomeMenuService; import com.mini.mybigscreen.biz.service.HomeMenuService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -28,6 +32,9 @@ import java.util.stream.Collectors;
public class HomeMenuController { public class HomeMenuController {
@Resource
private HomeMenuMapper homeMenuMapper;
@Resource @Resource
private HomeMenuService menuService; private HomeMenuService menuService;
@@ -124,7 +131,6 @@ public class HomeMenuController {
return treeMenu; return treeMenu;
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
menuList.add(new TreeMenu(menu.getMenuId(), menu.getMenuName(), treeMenus)); menuList.add(new TreeMenu(menu.getMenuId(), menu.getMenuName(), treeMenus));
} }
return Result.success(menuList); return Result.success(menuList);
@@ -135,33 +141,38 @@ public class HomeMenuController {
* 用户角色菜单 * 用户角色菜单
*/ */
@GetMapping("userList") @GetMapping("userList")
public Result<?> getUserList() { public Result<?> getUserList(String roleId) {
List<Menu> menuList = new ArrayList<>(); MPJLambdaWrapper<HomeMenu> wrapper = new MPJLambdaWrapper<HomeMenu>()
LambdaQueryWrapper<HomeMenu> parentQuery = new LambdaQueryWrapper<HomeMenu>() .selectAll(HomeMenu.class)
.eq(HomeMenu::getUstatus, "1") .leftJoin(HomeRoleMenu.class,
.eq(HomeMenu::getParentId, "0") HomeRoleMenu::getMenuId,
HomeMenu::getMenuId)
.eq(HomeRoleMenu::getRoleId, roleId)
.eq(HomeRoleMenu::getUstatus, "1")
.isNotNull(HomeMenu::getMenuId)
.orderByAsc(HomeMenu::getSort); .orderByAsc(HomeMenu::getSort);
List<HomeMenu> pMenus = menuService.list(parentQuery); List<HomeMenu> allMenus = homeMenuMapper.selectJoinList(HomeMenu.class, wrapper);
for (HomeMenu menu : pMenus) { Map<String, List<HomeMenu>> parentIdMap = allMenus.stream()
LambdaQueryWrapper<HomeMenu> childQuery = new LambdaQueryWrapper<HomeMenu>() .collect(Collectors.groupingBy(HomeMenu::getParentId));
.eq(HomeMenu::getParentId, menu.getMenuId()); List<Menu> menuList = allMenus.stream()
List<HomeMenu> childMenus = menuService.list(childQuery); .filter(menu -> menu.getParentId().equals("0"))
menuList.add(new Menu( .map(homeMenu -> new Menu(
menu.getMenuId(), homeMenu.getMenuId(),
menu.getParentId(), homeMenu.getParentId(),
menu.getMenuName(), homeMenu.getMenuName(),
menu.getMenuType(), homeMenu.getMenuType(),
menu.getPath(), homeMenu.getPath(),
menu.getMenuIcon(), homeMenu.getMenuIcon(),
menu.getSort(), homeMenu.getSort(),
menu.getIsIframe(), homeMenu.getIsIframe(),
menu.getUstatus(), homeMenu.getUstatus(),
childMenus parentIdMap.getOrDefault(homeMenu.getMenuId(), new ArrayList<>())
)); ))
} .collect(Collectors.toList());
return Result.success(menuList); return Result.success(menuList);
} }
/** /**
* 新增/修改 * 新增/修改
*/ */

View File

@@ -77,8 +77,9 @@ public class HomeRoleController {
return Result.success(roleMenuService.list(query)); return Result.success(roleMenuService.list(query));
} }
@PostMapping("save")
public Result<Message> save() { public Result<Message> save(@RequestBody HomeRole homeRole) {
roleService.save(homeRole);
return Result.success(new Message("数据新增成功", 200)); return Result.success(new Message("数据新增成功", 200));
} }