feat(menu): 优化菜单路径唯一性校验并更新前端界面

- 在SysLoginController中添加optionMap数据返回
- 添加JSQLParser依赖支持MyBatis Plus功能
- 实现selectMenuByPathExcludeId方法用于排除当前菜单的路径唯一性校验
- 在SysMenuServiceImpl中添加日志记录并优化路径唯一性判断逻辑
- 在SysMenuMapper.xml中添加LIMIT 1限制并实现排除ID查询
- 在前端路由中注释患者管理相关路由配置
- 在用户store中添加optionMap配置项并优先从optionMap获取医院名称
- 重构检查项目设置页面的操作按钮样式为统一的圆形按钮设计
- 更新检查项目设置页面的导航栏样式和交互体验
- 优化门诊记录页面的搜索条件和表格展示功能
- 添加性别和状态筛选条件并改进数据加载逻辑
This commit is contained in:
2026-01-03 23:47:09 +08:00
parent 61f4020487
commit 0c35044231
54 changed files with 5871 additions and 510 deletions

View File

@@ -112,72 +112,73 @@
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table
v-loading="loading"
:data="typeList"
height="calc(100vh - 300px)"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编号" align="center" prop="dictId" />
<el-table-column
label="字典名称"
align="center"
prop="dictName"
:show-overflow-tooltip="true"
/>
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
<template #default="scope">
<router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">
<span>{{ scope.row.dictType }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" class="dict-tag" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<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-column
label="操作"
align="center"
width="160"
class-name="small-padding fixed-width"
<div class="table-wrapper">
<el-table
v-loading="loading"
:data="typeList"
@selection-change="handleSelectionChange"
>
<template #default="scope">
<el-button
link
type="primary"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:dict:edit']"
class="action-button">修改</el-button
>
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:dict:remove']"
class="action-button">删除</el-button
>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编号" align="center" prop="dictId" />
<el-table-column
label="字典名称"
align="center"
prop="dictName"
:show-overflow-tooltip="true"
/>
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
<template #default="scope">
<router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">
<span>{{ scope.row.dictType }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" class="dict-tag" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<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-column
label="操作"
align="center"
width="160"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
link
type="primary"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:dict:edit']"
class="action-button">修改</el-button
>
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:dict:remove']"
class="action-button">删除</el-button
>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
</div>
<!-- 添加或修改参数配置对话框 -->
@@ -357,3 +358,68 @@ function handleRefreshCache() {
getList();
</script>
<style scoped>
.app-container {
padding: 16px;
background-color: #f5f7fa;
min-height: 100vh;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.query-form {
background: white;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
}
.button-group {
background: white;
padding: 16px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
}
.search-buttons {
margin-left: auto;
}
.table-wrapper {
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
padding: 0;
display: flex;
flex-direction: column;
}
:deep(.el-table) {
background: transparent;
border-radius: 0;
box-shadow: none;
}
:deep(.el-table__inner-wrapper) {
border-radius: 8px 8px 0 0;
}
.pagination-container {
padding: 20px 16px 20px;
display: flex;
justify-content: flex-end;
border-top: 1px solid #ebeef5;
}
:deep(.el-dialog__body) {
padding: 20px;
}
.action-button {
margin-right: 8px;
}
</style>

View File

@@ -63,6 +63,7 @@
</el-table-column>
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="path" label="路由地址" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template #default="scope">

View File

@@ -144,10 +144,12 @@ import {
getTenantPage,
saveTenantOptionDetailList
} from "@/api/system/tenant";
import useUserStore from '@/store/modules/user';
const router = useRouter();
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const userStore = useUserStore();
const dynamicFormList = ref([]);
// 当前租户信息
@@ -345,25 +347,42 @@ async function handleSetOption(row) {
currentTenantId.value = row.id;
currentTenantName.value = row.tenantName;
optionTitle.value = `基本配置`;
// 重置表单
resetOption();
optionForm.tenantId = row.id;
// 获取动态表单配置
const formListRes = await getTenantOptionFormList();
console.log('动态表单配置:', formListRes);
dynamicFormList.value = formListRes.data || [];
// 获取租户已有配置
const detailRes = await getTenantOptionDetailList(row.id);
if (detailRes.data) {
dynamicFormList.value.forEach(item => {
const existingConfig = detailRes.data.find(c => c.code === item.code);
item.content = existingConfig ? existingConfig.content : '';
console.log('租户已有配置:', detailRes);
console.log('租户已有配置数据:', detailRes.data);
// 填充已有配置值
if (detailRes.data && Array.isArray(detailRes.data)) {
console.log('开始填充配置值detailRes.data.length:', detailRes.data.length);
console.log('dynamicFormList.value.length:', dynamicFormList.value.length);
// 将已有配置数据转为 Map 方便查找
const configMap = {};
detailRes.data.forEach(config => {
configMap[config.code] = config.content || '';
});
dynamicFormList.value.forEach(item => {
const existingContent = configMap[item.code];
console.log(`配置项 ${item.code}, 找到配置值:`, existingContent);
item.content = existingContent || '';
});
console.log('填充后的dynamicFormList:', dynamicFormList.value);
} else {
console.log('detailRes.data 不是数组或为空,初始化空内容');
// 初始化空内容
dynamicFormList.value.forEach(item => {
item.content = '';
});
}
// 设置表单数据
optionForm.tenantId = row.id;
optionOpen.value = true;
} catch (error) {
console.error('获取配置项失败:', error);
@@ -384,8 +403,14 @@ async function submitOptionForm() {
loading.value = true;
const res = await saveTenantOptionDetailList(submitData);
if (res.code === 200) {
proxy.$modal.msgSuccess("配置保存成功");
optionOpen.value = false;
// 如果修改的是当前登录用户的租户配置,需要刷新用户信息
if (userStore.tenantId === optionForm.tenantId) {
await userStore.getInfo();
proxy.$modal.msgSuccess("配置保存成功,用户信息已刷新");
} else {
proxy.$modal.msgSuccess("配置保存成功");
}
} else {
proxy.$modal.msgError(res.msg || "配置保存失败");
}
@@ -397,9 +422,6 @@ async function submitOptionForm() {
}
/** 重置配置项表单 */
function resetOption() {
dynamicFormList.value.forEach(item => {
item.content = '';
});
if (proxy.$refs["optionRef"]) {
proxy.$refs["optionRef"].resetFields();
}