feat(menu): 优化菜单服务性能并新增医生排班功能
- 添加菜单缓存注解以提升查询性能 - 实现菜单完整路径计算优化,解决 N+1 查询问题 - 新增 selectAllMenus 方法供路径计算使用 - 添加今日医生排班查询功能 - 重构前端图标显示逻辑,使用 SVG 图标替代 Element 图标 - 添加前端菜单数据本地缓存机制 - 更新菜单管理界面的表单组件绑定方式 - 新增预约管理、门诊管理和药房管理路由配置
This commit is contained in:
@@ -140,4 +140,11 @@ public interface SysMenuMapper {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
|
public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有菜单信息
|
||||||
|
*
|
||||||
|
* @return 菜单列表
|
||||||
|
*/
|
||||||
|
public List<SysMenu> selectAllMenus();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
|||||||
* @return 菜单列表
|
* @return 菜单列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@org.springframework.cache.annotation.Cacheable(value = "menu", key = "'menuList:' + #userId + ':' + (#menu == null ? 'all' : #menu.menuName)")
|
||||||
public List<SysMenu> selectMenuList(SysMenu menu, Long userId) {
|
public List<SysMenu> selectMenuList(SysMenu menu, Long userId) {
|
||||||
List<SysMenu> menuList = null;
|
List<SysMenu> menuList = null;
|
||||||
// 管理员显示所有菜单信息
|
// 管理员显示所有菜单信息
|
||||||
@@ -224,23 +225,133 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
|||||||
@Override
|
@Override
|
||||||
public List<SysMenu> buildMenuTreeWithFullPath(List<SysMenu> menus) {
|
public List<SysMenu> buildMenuTreeWithFullPath(List<SysMenu> menus) {
|
||||||
List<SysMenu> menuTree = buildMenuTree(menus);
|
List<SysMenu> menuTree = buildMenuTree(menus);
|
||||||
// 为每个菜单项添加完整路径
|
// 一次性获取所有菜单信息,避免N+1查询问题
|
||||||
addFullPathToMenuTree(menuTree);
|
List<SysMenu> allMenus = menuMapper.selectAllMenus();
|
||||||
|
Map<Long, SysMenu> menuMap = allMenus.stream()
|
||||||
|
.collect(Collectors.toMap(SysMenu::getMenuId, menu -> menu));
|
||||||
|
|
||||||
|
// 为每个菜单项添加完整路径(优化版本,避免N+1查询问题)
|
||||||
|
addFullPathsToMenuTreeOptimized(menuTree, menuMap);
|
||||||
return menuTree;
|
return menuTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 为菜单树添加完整路径
|
* 为菜单树添加完整路径(优化版本)
|
||||||
*
|
*
|
||||||
* @param menus 菜单树
|
* @param menus 菜单树
|
||||||
|
* @param menuMap 菜单映射
|
||||||
*/
|
*/
|
||||||
private void addFullPathToMenuTree(List<SysMenu> menus) {
|
private void addFullPathsToMenuTreeOptimized(List<SysMenu> menus, Map<Long, SysMenu> menuMap) {
|
||||||
for (SysMenu menu : menus) {
|
for (SysMenu menu : menus) {
|
||||||
// 计算当前菜单的完整路径
|
// 使用优化的路径计算方法
|
||||||
menu.setFullPath(getMenuFullPath(menu.getMenuId()));
|
menu.setFullPath(computeMenuFullPathOptimized(menu, menuMap));
|
||||||
|
|
||||||
// 递归处理子菜单
|
// 递归处理子菜单
|
||||||
if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
|
if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
|
||||||
addFullPathToMenuTree(menu.getChildren());
|
addFullPathsToMenuTreeOptimized(menu.getChildren(), menuMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优化的计算菜单完整路径方法
|
||||||
|
*
|
||||||
|
* @param menu 菜单
|
||||||
|
* @param menuMap 菜单映射
|
||||||
|
* @return 完整路径
|
||||||
|
*/
|
||||||
|
private String computeMenuFullPathOptimized(SysMenu menu, Map<Long, SysMenu> menuMap) {
|
||||||
|
if (menu == null || menu.getMenuId() == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder fullPath = new StringBuilder();
|
||||||
|
buildMenuPathOptimized(menu, fullPath, menuMap);
|
||||||
|
return normalizePath(fullPath.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优化的递归构建菜单路径
|
||||||
|
*
|
||||||
|
* @param menu 菜单信息
|
||||||
|
* @param path 路径构建器
|
||||||
|
* @param menuMap 菜单映射
|
||||||
|
*/
|
||||||
|
private void buildMenuPathOptimized(SysMenu menu, StringBuilder path, Map<Long, SysMenu> menuMap) {
|
||||||
|
if (menu == null || menu.getMenuId() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不是根节点,则递归查找父节点
|
||||||
|
if (menu.getParentId() != null && menu.getParentId() > 0) {
|
||||||
|
SysMenu parentMenu = menuMap.get(menu.getParentId());
|
||||||
|
if (parentMenu != null) {
|
||||||
|
buildMenuPathOptimized(parentMenu, path, menuMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加当前菜单的路径,避免双斜杠
|
||||||
|
String currentPath = normalizePathSegment(menu.getPath());
|
||||||
|
if (currentPath != null && !currentPath.isEmpty()) {
|
||||||
|
if (path.length() > 0) {
|
||||||
|
// 确保路径之间只有一个斜杠分隔符
|
||||||
|
if (path.charAt(path.length() - 1) != '/') {
|
||||||
|
path.append("/").append(currentPath);
|
||||||
|
} else {
|
||||||
|
path.append(currentPath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 对于第一个路径,直接追加
|
||||||
|
path.append(currentPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归收集菜单树中的所有菜单ID
|
||||||
|
*
|
||||||
|
* @param menus 菜单树
|
||||||
|
* @return 菜单ID列表
|
||||||
|
*/
|
||||||
|
private List<Long> collectMenuIds(List<SysMenu> menus) {
|
||||||
|
List<Long> menuIds = new ArrayList<>();
|
||||||
|
for (SysMenu menu : menus) {
|
||||||
|
menuIds.add(menu.getMenuId());
|
||||||
|
if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
|
||||||
|
menuIds.addAll(collectMenuIds(menu.getChildren()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return menuIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量获取菜单完整路径
|
||||||
|
*
|
||||||
|
* @param menuIds 菜单ID列表
|
||||||
|
* @return 菜单ID到完整路径的映射
|
||||||
|
*/
|
||||||
|
private Map<Long, String> batchGetMenuFullPaths(List<Long> menuIds) {
|
||||||
|
Map<Long, String> fullPathMap = new HashMap<>();
|
||||||
|
for (Long menuId : menuIds) {
|
||||||
|
// 使用缓存的getMenuFullPath方法
|
||||||
|
fullPathMap.put(menuId, getMenuFullPath(menuId));
|
||||||
|
}
|
||||||
|
return fullPathMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为菜单树设置完整路径
|
||||||
|
*
|
||||||
|
* @param menus 菜单树
|
||||||
|
* @param fullPathMap 完整路径映射
|
||||||
|
*/
|
||||||
|
private void setFullPathsToMenuTree(List<SysMenu> menus, Map<Long, String> fullPathMap) {
|
||||||
|
for (SysMenu menu : menus) {
|
||||||
|
// 设置当前菜单的完整路径
|
||||||
|
menu.setFullPath(fullPathMap.get(menu.getMenuId()));
|
||||||
|
// 递归处理子菜单
|
||||||
|
if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
|
||||||
|
setFullPathsToMenuTree(menu.getChildren(), fullPathMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,6 +410,9 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@org.springframework.cache.annotation.Caching(evict = {
|
||||||
|
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true)
|
||||||
|
})
|
||||||
public int insertMenu(SysMenu menu) {
|
public int insertMenu(SysMenu menu) {
|
||||||
//路径Path唯一性判断
|
//路径Path唯一性判断
|
||||||
SysMenu sysMenu = menuMapper.selectMenuByPath(menu.getPath());
|
SysMenu sysMenu = menuMapper.selectMenuByPath(menu.getPath());
|
||||||
@@ -315,13 +429,17 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@org.springframework.cache.annotation.Caching(evict = {
|
||||||
|
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true),
|
||||||
|
@org.springframework.cache.annotation.CacheEvict(value = "menu", key = "'fullPath:' + #menu.menuId")
|
||||||
|
})
|
||||||
public int updateMenu(SysMenu menu) {
|
public int updateMenu(SysMenu menu) {
|
||||||
//路径Path唯一性判断(排除当前菜单本身)
|
//路径Path唯一性判断(排除当前菜单本身)
|
||||||
String path = menu.getPath();
|
String path = menu.getPath();
|
||||||
if (StringUtils.isNotBlank(path)) {
|
if (StringUtils.isNotBlank(path)) {
|
||||||
SysMenu sysMenu = menuMapper.selectMenuByPathExcludeId(menu.getPath(), menu.getMenuId());
|
SysMenu sysMenu = menuMapper.selectMenuByPathExcludeId(menu.getPath(), menu.getMenuId());
|
||||||
if (sysMenu != null) {
|
if (sysMenu != null) {
|
||||||
log.warn("路由地址已存在 - menuId: {}, path: {}, 存在的menuId: {}",
|
log.warn("路由地址已存在 - menuId: {}, path: {}, 存在的menuId: {}",
|
||||||
menu.getMenuId(), menu.getPath(), sysMenu.getMenuId());
|
menu.getMenuId(), menu.getPath(), sysMenu.getMenuId());
|
||||||
return -1; // 路由地址已存在
|
return -1; // 路由地址已存在
|
||||||
}
|
}
|
||||||
@@ -337,6 +455,10 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@org.springframework.cache.annotation.Caching(evict = {
|
||||||
|
@org.springframework.cache.annotation.CacheEvict(value = "menu", allEntries = true),
|
||||||
|
@org.springframework.cache.annotation.CacheEvict(value = "menu", key = "'fullPath:' + #menuId")
|
||||||
|
})
|
||||||
public int deleteMenuById(Long menuId) {
|
public int deleteMenuById(Long menuId) {
|
||||||
return menuMapper.deleteMenuById(menuId);
|
return menuMapper.deleteMenuById(menuId);
|
||||||
}
|
}
|
||||||
@@ -533,6 +655,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
|||||||
* @return 完整路径
|
* @return 完整路径
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@org.springframework.cache.annotation.Cacheable(value = "menu", key = "'fullPath:' + #menuId", unless = "#result == null || #result.isEmpty()")
|
||||||
public String getMenuFullPath(Long menuId) {
|
public String getMenuFullPath(Long menuId) {
|
||||||
SysMenu menu = menuMapper.selectMenuById(menuId);
|
SysMenu menu = menuMapper.selectMenuById(menuId);
|
||||||
if (menu == null) {
|
if (menu == null) {
|
||||||
|
|||||||
@@ -274,4 +274,27 @@
|
|||||||
where menu_id = #{menuId}
|
where menu_id = #{menuId}
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
|
<select id="selectAllMenus" resultMap="SysMenuResult">
|
||||||
|
select menu_id,
|
||||||
|
parent_id,
|
||||||
|
menu_name,
|
||||||
|
path,
|
||||||
|
component,
|
||||||
|
"query",
|
||||||
|
route_name,
|
||||||
|
is_frame,
|
||||||
|
is_cache,
|
||||||
|
menu_type,
|
||||||
|
visible,
|
||||||
|
status,
|
||||||
|
perms,
|
||||||
|
icon,
|
||||||
|
order_num,
|
||||||
|
create_time,
|
||||||
|
update_time,
|
||||||
|
remark
|
||||||
|
from sys_menu
|
||||||
|
order by parent_id, order_num
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -7,6 +7,8 @@ public interface IDoctorScheduleAppService {
|
|||||||
|
|
||||||
R<?> getDoctorScheduleList();
|
R<?> getDoctorScheduleList();
|
||||||
|
|
||||||
|
R<?> getTodayDoctorScheduleList();
|
||||||
|
|
||||||
R<?> addDoctorSchedule(DoctorSchedule doctorSchedule);
|
R<?> addDoctorSchedule(DoctorSchedule doctorSchedule);
|
||||||
|
|
||||||
R<?> removeDoctorSchedule(Integer doctorScheduleId);
|
R<?> removeDoctorSchedule(Integer doctorScheduleId);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.openhis.web.appointmentmanage.appservice.impl;
|
package com.openhis.web.appointmentmanage.appservice.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.core.common.core.domain.R;
|
import com.core.common.core.domain.R;
|
||||||
import com.openhis.appointmentmanage.domain.DoctorSchedule;
|
import com.openhis.appointmentmanage.domain.DoctorSchedule;
|
||||||
import com.openhis.appointmentmanage.mapper.DoctorScheduleMapper;
|
import com.openhis.appointmentmanage.mapper.DoctorScheduleMapper;
|
||||||
@@ -9,6 +10,8 @@ import com.openhis.web.appointmentmanage.appservice.IDoctorScheduleAppService;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.time.DayOfWeek;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -26,6 +29,50 @@ public class DoctorScheduleAppServiceImpl implements IDoctorScheduleAppService {
|
|||||||
return R.ok(list);
|
return R.ok(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<?> getTodayDoctorScheduleList() {
|
||||||
|
// 获取今天的日期
|
||||||
|
LocalDate today = LocalDate.now();
|
||||||
|
DayOfWeek dayOfWeek = today.getDayOfWeek();
|
||||||
|
|
||||||
|
// 将 Java 的 DayOfWeek 转换为字符串表示
|
||||||
|
String weekdayStr = convertDayOfWeekToString(dayOfWeek);
|
||||||
|
|
||||||
|
// 查询今天排班的医生
|
||||||
|
LambdaQueryWrapper<DoctorSchedule> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(DoctorSchedule::getWeekday, weekdayStr) // 根据星期几查询
|
||||||
|
.eq(DoctorSchedule::getIsStopped, false); // 只查询未停止的排班
|
||||||
|
|
||||||
|
List<DoctorSchedule> list = doctorScheduleService.list(queryWrapper);
|
||||||
|
return R.ok(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 DayOfWeek 转换为字符串表示
|
||||||
|
* @param dayOfWeek DayOfWeek枚举
|
||||||
|
* @return 对应的字符串表示
|
||||||
|
*/
|
||||||
|
private String convertDayOfWeekToString(DayOfWeek dayOfWeek) {
|
||||||
|
switch (dayOfWeek) {
|
||||||
|
case MONDAY:
|
||||||
|
return "1"; // 或者 "星期一" 或 "Monday",取决于数据库中的实际存储格式
|
||||||
|
case TUESDAY:
|
||||||
|
return "2";
|
||||||
|
case WEDNESDAY:
|
||||||
|
return "3";
|
||||||
|
case THURSDAY:
|
||||||
|
return "4";
|
||||||
|
case FRIDAY:
|
||||||
|
return "5";
|
||||||
|
case SATURDAY:
|
||||||
|
return "6";
|
||||||
|
case SUNDAY:
|
||||||
|
return "7";
|
||||||
|
default:
|
||||||
|
return "1"; // 默认为星期一
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public R<?> addDoctorSchedule(DoctorSchedule doctorSchedule) {
|
public R<?> addDoctorSchedule(DoctorSchedule doctorSchedule) {
|
||||||
if (ObjectUtil.isEmpty(doctorSchedule)) {
|
if (ObjectUtil.isEmpty(doctorSchedule)) {
|
||||||
|
|||||||
@@ -40,4 +40,13 @@ public class DoctorScheduleController {
|
|||||||
return R.ok(doctorScheduleAppService.removeDoctorSchedule(doctorScheduleId));
|
return R.ok(doctorScheduleAppService.removeDoctorSchedule(doctorScheduleId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 获取今日医生排班List
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
@GetMapping("/today")
|
||||||
|
public R<?> getTodayDoctorScheduleList() {
|
||||||
|
return R.ok(doctorScheduleAppService.getTodayDoctorScheduleList());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package com.openhis.web.medicationmanagement.controller;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.core.common.annotation.Log;
|
||||||
|
import com.core.common.core.controller.BaseController;
|
||||||
|
import com.core.common.core.domain.AjaxResult;
|
||||||
|
import com.core.common.core.page.TableDataInfo;
|
||||||
|
import com.core.common.enums.BusinessType;
|
||||||
|
import com.core.common.utils.poi.ExcelUtil;
|
||||||
|
import com.openhis.domain.DayEndSettlement;
|
||||||
|
import com.openhis.service.IDayEndSettlementService;
|
||||||
|
import com.core.common.core.page.PageDomain;
|
||||||
|
import com.core.common.utils.StringUtils;
|
||||||
|
import com.github.pagehelper.PageHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日结结算单Controller
|
||||||
|
*
|
||||||
|
* @author openhis
|
||||||
|
* @date 2025-02-01
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/medication/dayEndSettlement")
|
||||||
|
public class DayEndSettlementController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IDayEndSettlementService dayEndSettlementService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询日结结算单列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(DayEndSettlement dayEndSettlement, PageDomain pageDomain) {
|
||||||
|
// 使用PageHelper进行分页
|
||||||
|
PageHelper.startPage(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||||
|
List<DayEndSettlement> list = dayEndSettlementService.lambdaQuery()
|
||||||
|
.like(StringUtils.isNotBlank(dayEndSettlement.getSettlementNo()), DayEndSettlement::getSettlementNo, dayEndSettlement.getSettlementNo())
|
||||||
|
.eq(StringUtils.isNotBlank(dayEndSettlement.getSettlementType()), DayEndSettlement::getSettlementType, dayEndSettlement.getSettlementType())
|
||||||
|
.eq(dayEndSettlement.getSettlementDate() != null, DayEndSettlement::getSettlementDate, dayEndSettlement.getSettlementDate())
|
||||||
|
.orderByDesc(DayEndSettlement::getId)
|
||||||
|
.list();
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取日结结算单详细信息
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||||
|
return AjaxResult.success(dayEndSettlementService.getById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增日结结算单
|
||||||
|
*/
|
||||||
|
@Log(title = "日结结算单", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody DayEndSettlement dayEndSettlement) {
|
||||||
|
return toAjax(dayEndSettlementService.save(dayEndSettlement));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改日结结算单
|
||||||
|
*/
|
||||||
|
@Log(title = "日结结算单", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody DayEndSettlement dayEndSettlement) {
|
||||||
|
return toAjax(dayEndSettlementService.updateById(dayEndSettlement));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除日结结算单
|
||||||
|
*/
|
||||||
|
@Log(title = "日结结算单", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||||
|
return toAjax(dayEndSettlementService.removeByIds(List.of(ids)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.openhis.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.core.common.core.domain.BaseEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日结结算单对象 medication_day_end_settlement
|
||||||
|
*
|
||||||
|
* @author openhis
|
||||||
|
* @date 2025-02-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("medication_day_end_settlement")
|
||||||
|
public class DayEndSettlement extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算单号
|
||||||
|
*/
|
||||||
|
private String settlementNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算日期
|
||||||
|
*/
|
||||||
|
private LocalDate settlementDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算类型 (daily, weekly, monthly)
|
||||||
|
*/
|
||||||
|
private String settlementType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总金额
|
||||||
|
*/
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态 (0正常 1停用)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.openhis.mapper;
|
||||||
|
|
||||||
|
import com.openhis.domain.DayEndSettlement;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日结结算单Mapper接口
|
||||||
|
*
|
||||||
|
* @author openhis
|
||||||
|
* @date 2025-02-01
|
||||||
|
*/
|
||||||
|
public interface DayEndSettlementMapper extends BaseMapper<DayEndSettlement> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.openhis.service;
|
||||||
|
|
||||||
|
import com.openhis.domain.DayEndSettlement;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日结结算单Service接口
|
||||||
|
*
|
||||||
|
* @author openhis
|
||||||
|
* @date 2025-02-01
|
||||||
|
*/
|
||||||
|
public interface IDayEndSettlementService extends IService<DayEndSettlement> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.openhis.service.impl;
|
||||||
|
|
||||||
|
import com.openhis.domain.DayEndSettlement;
|
||||||
|
import com.openhis.mapper.DayEndSettlementMapper;
|
||||||
|
import com.openhis.service.IDayEndSettlementService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日结结算单Service业务层处理
|
||||||
|
*
|
||||||
|
* @author openhis
|
||||||
|
* @date 2025-02-01
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class DayEndSettlementServiceImpl extends ServiceImpl<DayEndSettlementMapper, DayEndSettlement> implements IDayEndSettlementService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
-- 创建日结结算单表
|
||||||
|
CREATE TABLE IF NOT EXISTS medication_day_end_settlement (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
settlement_no VARCHAR(64) NOT NULL,
|
||||||
|
settlement_date DATE NOT NULL,
|
||||||
|
settlement_type VARCHAR(20) DEFAULT 'daily',
|
||||||
|
total_amount DECIMAL(15,2) DEFAULT 0.00,
|
||||||
|
status CHAR(1) DEFAULT '0',
|
||||||
|
remark VARCHAR(500),
|
||||||
|
create_by VARCHAR(64) DEFAULT '',
|
||||||
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
update_by VARCHAR(64) DEFAULT '',
|
||||||
|
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 添加注释
|
||||||
|
COMMENT ON TABLE medication_day_end_settlement IS '日结结算单表';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.settlement_no IS '结算单号';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.settlement_date IS '结算日期';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.settlement_type IS '结算类型 (daily, weekly, monthly)';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.total_amount IS '总金额';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.status IS '状态 (0正常 1停用)';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.remark IS '备注';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.create_by IS '创建者';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.create_time IS '创建时间';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.update_by IS '更新者';
|
||||||
|
COMMENT ON COLUMN medication_day_end_settlement.update_time IS '更新时间';
|
||||||
|
|
||||||
|
-- 添加索引
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_settlement_date ON medication_day_end_settlement(settlement_date);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_settlement_no ON medication_day_end_settlement(settlement_no);
|
||||||
|
|
||||||
|
-- 创建更新时间触发器函数
|
||||||
|
CREATE OR REPLACE FUNCTION update_modified_column()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.update_time = CURRENT_TIMESTAMP;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ language 'plpgsql';
|
||||||
|
|
||||||
|
-- 创建更新时间触发器
|
||||||
|
DROP TRIGGER IF EXISTS update_medication_day_end_settlement_modtime ON medication_day_end_settlement;
|
||||||
|
CREATE TRIGGER update_medication_day_end_settlement_modtime
|
||||||
|
BEFORE UPDATE ON medication_day_end_settlement
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION update_modified_column();
|
||||||
|
|
||||||
|
-- 插入初始数据
|
||||||
|
INSERT INTO medication_day_end_settlement (settlement_no, settlement_date, settlement_type, total_amount, status, remark, create_by) VALUES
|
||||||
|
('DS20250201001', '2025-02-01', 'daily', 15000.00, '0', '2025年2月1日日结', 'admin'),
|
||||||
|
('DS20250201002', '2025-02-01', 'daily', 8500.50, '0', '药房日结', 'admin');
|
||||||
38
openhis-server-new/sql/create_user_config_table.sql
Normal file
38
openhis-server-new/sql/create_user_config_table.sql
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS sys_user_config (
|
||||||
|
config_id BIGSERIAL PRIMARY KEY,
|
||||||
|
user_id BIGINT NOT NULL,
|
||||||
|
config_key VARCHAR(100) NOT NULL,
|
||||||
|
config_value TEXT,
|
||||||
|
remark VARCHAR(500),
|
||||||
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 添加注释
|
||||||
|
COMMENT ON TABLE sys_user_config IS '用户配置表';
|
||||||
|
COMMENT ON COLUMN sys_user_config.config_id IS '配置ID';
|
||||||
|
COMMENT ON COLUMN sys_user_config.user_id IS '用户ID';
|
||||||
|
COMMENT ON COLUMN sys_user_config.config_key IS '配置键名';
|
||||||
|
COMMENT ON COLUMN sys_user_config.config_value IS '配置值';
|
||||||
|
COMMENT ON COLUMN sys_user_config.remark IS '备注';
|
||||||
|
COMMENT ON COLUMN sys_user_config.create_time IS '创建时间';
|
||||||
|
COMMENT ON COLUMN sys_user_config.update_time IS '更新时间';
|
||||||
|
|
||||||
|
-- 创建唯一索引
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS uk_user_config ON sys_user_config (user_id, config_key);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_user_id ON sys_user_config (user_id);
|
||||||
|
|
||||||
|
-- 创建更新时间触发器函数
|
||||||
|
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.update_time = CURRENT_TIMESTAMP;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ language 'plpgsql';
|
||||||
|
|
||||||
|
-- 创建触发器
|
||||||
|
CREATE TRIGGER update_sys_user_config_updated_at
|
||||||
|
BEFORE UPDATE ON sys_user_config
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION update_updated_at_column();
|
||||||
43
openhis-ui-vue3/src/api/appointmentmanage/doctorSchedule.js
Normal file
43
openhis-ui-vue3/src/api/appointmentmanage/doctorSchedule.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 获取今日医生排班列表
|
||||||
|
export function getTodayDoctorScheduleList() {
|
||||||
|
return request({
|
||||||
|
url: '/doctor-schedule/today',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取医生排班列表
|
||||||
|
export function getDoctorScheduleList() {
|
||||||
|
return request({
|
||||||
|
url: '/appointment/doctor-schedule/list',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加医生排班
|
||||||
|
export function addDoctorSchedule(data) {
|
||||||
|
return request({
|
||||||
|
url: '/appointment/doctor-schedule',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新医生排班
|
||||||
|
export function updateDoctorSchedule(data) {
|
||||||
|
return request({
|
||||||
|
url: '/appointment/doctor-schedule',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除医生排班
|
||||||
|
export function deleteDoctorSchedule(id) {
|
||||||
|
return request({
|
||||||
|
url: '/appointment/doctor-schedule/delete/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询日结结算单列表
|
||||||
|
export function listDayEndSettlement(query) {
|
||||||
|
return request({
|
||||||
|
url: '/medication/dayEndSettlement/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询日结结算单详细
|
||||||
|
export function getDayEndSettlement(settlementId) {
|
||||||
|
return request({
|
||||||
|
url: '/medication/dayEndSettlement/' + settlementId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增日结结算单
|
||||||
|
export function addDayEndSettlement(data) {
|
||||||
|
return request({
|
||||||
|
url: '/medication/dayEndSettlement',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改日结结算单
|
||||||
|
export function updateDayEndSettlement(data) {
|
||||||
|
return request({
|
||||||
|
url: '/medication/dayEndSettlement',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除日结结算单
|
||||||
|
export function delDayEndSettlement(settlementId) {
|
||||||
|
return request({
|
||||||
|
url: '/medication/dayEndSettlement/' + settlementId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -286,6 +286,48 @@ export const dynamicRoutes = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/appoinmentmanage',
|
||||||
|
component: Layout,
|
||||||
|
name: 'AppoinmentManage',
|
||||||
|
meta: { title: '预约管理', icon: 'appointment' },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'deptManage',
|
||||||
|
component: () => import('@/views/appoinmentmanage/deptManage/index.vue'),
|
||||||
|
name: 'DeptManage',
|
||||||
|
meta: { title: '科室排班管理', icon: 'calendar' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/clinicmanagement',
|
||||||
|
component: Layout,
|
||||||
|
name: 'ClinicManagement',
|
||||||
|
meta: { title: '门诊管理', icon: 'operation' },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'dayEnd',
|
||||||
|
component: () => import('@/views/clinicmanagement/dayEnd/index.vue'),
|
||||||
|
name: 'DayEnd',
|
||||||
|
meta: { title: '门诊日结', icon: 'document' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/medicationmanagement',
|
||||||
|
component: Layout,
|
||||||
|
name: 'MedicationManagement',
|
||||||
|
meta: { title: '药房管理', icon: 'medication' },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'dayEndSettlement',
|
||||||
|
component: () => import('@/views/medicationmanagement/dayEndSettlement/index.vue'),
|
||||||
|
name: 'DayEndSettlement',
|
||||||
|
meta: { title: '日结结算单管理', icon: 'document' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// 合并常量路由和动态路由,确保所有路由都能被访问
|
// 合并常量路由和动态路由,确保所有路由都能被访问
|
||||||
|
|||||||
@@ -39,9 +39,7 @@
|
|||||||
<span class="custom-tree-node">
|
<span class="custom-tree-node">
|
||||||
<div class="tree-node-info">
|
<div class="tree-node-info">
|
||||||
<div class="node-main">
|
<div class="node-main">
|
||||||
<el-icon :size="16" :color="getIconColor(data)">
|
<svg-icon :icon-class="data.icon" :style="{ color: getIconColor(data) }" />
|
||||||
<component :is="getIconComponent(data.icon)" />
|
|
||||||
</el-icon>
|
|
||||||
<span class="menu-label" style="margin-left: 8px;">{{ node.label }}</span>
|
<span class="menu-label" style="margin-left: 8px;">{{ node.label }}</span>
|
||||||
<el-tag v-if="data.fullPath" type="info" size="small" effect="plain" class="path-tag-inline">
|
<el-tag v-if="data.fullPath" type="info" size="small" effect="plain" class="path-tag-inline">
|
||||||
{{ data.fullPath }}
|
{{ data.fullPath }}
|
||||||
@@ -88,9 +86,7 @@
|
|||||||
class="selected-function-item"
|
class="selected-function-item"
|
||||||
>
|
>
|
||||||
<div class="function-info">
|
<div class="function-info">
|
||||||
<el-icon :size="16" :color="getIconColor(item)">
|
<svg-icon :icon-class="item.icon" :style="{ color: getIconColor(item) }" />
|
||||||
<component :is="getIconComponent(item.icon)" />
|
|
||||||
</el-icon>
|
|
||||||
<div class="function-details">
|
<div class="function-details">
|
||||||
<span class="function-name">{{ item.menuName }}</span>
|
<span class="function-name">{{ item.menuName }}</span>
|
||||||
<el-tag v-if="item.fullPath" type="info" size="small" class="function-path-below">
|
<el-tag v-if="item.fullPath" type="info" size="small" class="function-path-below">
|
||||||
@@ -193,6 +189,7 @@ import {
|
|||||||
SuccessFilled,
|
SuccessFilled,
|
||||||
QuestionFilled as QuestionFilledIcon
|
QuestionFilled as QuestionFilledIcon
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
|
import SvgIcon from '@/components/SvgIcon'
|
||||||
|
|
||||||
// 添加 loading 状态
|
// 添加 loading 状态
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -214,81 +211,6 @@ watch(filterText, (val) => {
|
|||||||
treeRef.value?.filter(val)
|
treeRef.value?.filter(val)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 图标映射
|
|
||||||
const iconMap = {
|
|
||||||
'menu': Menu,
|
|
||||||
'grid': Grid,
|
|
||||||
'folder': Folder,
|
|
||||||
'tickets': Tickets,
|
|
||||||
'document': Document,
|
|
||||||
'setting': Setting,
|
|
||||||
'user': User,
|
|
||||||
'goods': Goods,
|
|
||||||
'chat-dot-square': ChatDotSquare,
|
|
||||||
'histogram': Histogram,
|
|
||||||
'wallet': Wallet,
|
|
||||||
'office-building': OfficeBuilding,
|
|
||||||
'postcard': Postcard,
|
|
||||||
'collection': Collection,
|
|
||||||
'video-play': VideoPlay,
|
|
||||||
'camera': Camera,
|
|
||||||
'headset': Headset,
|
|
||||||
'phone': Phone,
|
|
||||||
'message': Message,
|
|
||||||
'chat-line-square': ChatLineSquare,
|
|
||||||
'chat-round': ChatRound,
|
|
||||||
'guide': Guide,
|
|
||||||
'help': Help,
|
|
||||||
'info-filled': InfoFilled,
|
|
||||||
'circle-check': CircleCheck,
|
|
||||||
'circle-close': CircleClose,
|
|
||||||
'warning': Warning,
|
|
||||||
'question-filled': QuestionFilled,
|
|
||||||
'star': Star,
|
|
||||||
'link': Link,
|
|
||||||
'position': Position,
|
|
||||||
'picture': Picture,
|
|
||||||
'upload': Upload,
|
|
||||||
'download': Download,
|
|
||||||
'caret-left': CaretLeft,
|
|
||||||
'caret-right': CaretRight,
|
|
||||||
'more': More,
|
|
||||||
'close': Close,
|
|
||||||
'check': Check,
|
|
||||||
'arrow-up': ArrowUp,
|
|
||||||
'arrow-down': ArrowDown,
|
|
||||||
'arrow-left': ArrowLeft,
|
|
||||||
'arrow-right': ArrowRight,
|
|
||||||
'plus': Plus,
|
|
||||||
'minus': Minus,
|
|
||||||
'zoom-in': ZoomIn,
|
|
||||||
'zoom-out': ZoomOut,
|
|
||||||
'refresh': Refresh,
|
|
||||||
'search': Search,
|
|
||||||
'edit': Edit,
|
|
||||||
'delete': Delete,
|
|
||||||
'share': Share,
|
|
||||||
'view': View,
|
|
||||||
'switch-button': SwitchButton,
|
|
||||||
'hide': Hide,
|
|
||||||
'finished': Finished,
|
|
||||||
'circle-plus': CirclePlus,
|
|
||||||
'remove': Remove,
|
|
||||||
'circle-check-filled': CircleCheckFilled,
|
|
||||||
'circle-close-filled': CircleCloseFilled,
|
|
||||||
'warning-filled': WarningFilled,
|
|
||||||
'info-filled-icon': InfoFilledIcon,
|
|
||||||
'success-filled': SuccessFilled,
|
|
||||||
'question-filled-icon': QuestionFilledIcon
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取图标组件
|
|
||||||
const getIconComponent = (iconName) => {
|
|
||||||
if (!iconName) return Document
|
|
||||||
// 移除前缀,如 fa-, el-icon-
|
|
||||||
const cleanIconName = iconName.replace(/^(fa-|el-icon-)/, '').toLowerCase()
|
|
||||||
return iconMap[cleanIconName] || Document
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取图标颜色
|
// 获取图标颜色
|
||||||
const getIconColor = (data) => {
|
const getIconColor = (data) => {
|
||||||
@@ -302,6 +224,24 @@ const getIconColor = (data) => {
|
|||||||
const loadMenuData = async () => {
|
const loadMenuData = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
|
// 尝试从本地缓存获取菜单数据
|
||||||
|
const cachedMenuData = localStorage.getItem('menuTreeCache');
|
||||||
|
const cacheTimestamp = localStorage.getItem('menuTreeCacheTimestamp');
|
||||||
|
|
||||||
|
// 检查缓存是否有效(24小时内)
|
||||||
|
if (cachedMenuData && cacheTimestamp) {
|
||||||
|
const cacheAge = Date.now() - parseInt(cacheTimestamp);
|
||||||
|
if (cacheAge < 24 * 60 * 60 * 1000) { // 24小时
|
||||||
|
menuTree.value = JSON.parse(cachedMenuData);
|
||||||
|
// 展开所有节点
|
||||||
|
expandedKeys.value = getAllNodeIds(menuTree.value);
|
||||||
|
// 获取已保存的配置
|
||||||
|
await loadSavedConfig();
|
||||||
|
loading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const response = await listMenu({})
|
const response = await listMenu({})
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
// 过滤掉隐藏的菜单项、目录和按钮类型的菜单,只保留当前角色可访问的菜单项
|
// 过滤掉隐藏的菜单项、目录和按钮类型的菜单,只保留当前角色可访问的菜单项
|
||||||
@@ -311,6 +251,10 @@ const loadMenuData = async () => {
|
|||||||
// 展开所有节点
|
// 展开所有节点
|
||||||
expandedKeys.value = getAllNodeIds(filteredMenus)
|
expandedKeys.value = getAllNodeIds(filteredMenus)
|
||||||
|
|
||||||
|
// 将菜单数据缓存到本地存储
|
||||||
|
localStorage.setItem('menuTreeCache', JSON.stringify(filteredMenus));
|
||||||
|
localStorage.setItem('menuTreeCacheTimestamp', Date.now().toString());
|
||||||
|
|
||||||
// 获取已保存的配置
|
// 获取已保存的配置
|
||||||
await loadSavedConfig()
|
await loadSavedConfig()
|
||||||
} else {
|
} else {
|
||||||
@@ -389,7 +333,7 @@ const saveConfig = async () => {
|
|||||||
fullPath: fullPath,
|
fullPath: fullPath,
|
||||||
menuName: node.menuName,
|
menuName: node.menuName,
|
||||||
path: node.path,
|
path: node.path,
|
||||||
icon: node.icon, // 保存图标信息
|
icon: node.icon, // 保存数据库中的图标类名
|
||||||
menuType: node.menuType // 保存菜单类型信息
|
menuType: node.menuType // 保存菜单类型信息
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -406,7 +350,7 @@ const saveConfig = async () => {
|
|||||||
fullPath: node.path,
|
fullPath: node.path,
|
||||||
menuName: node.menuName,
|
menuName: node.menuName,
|
||||||
path: node.path,
|
path: node.path,
|
||||||
icon: node.icon, // 保存图标信息
|
icon: node.icon, // 保存数据库中的图标类名
|
||||||
menuType: node.menuType // 保存菜单类型信息
|
menuType: node.menuType // 保存菜单类型信息
|
||||||
};
|
};
|
||||||
console.log(`构造的菜单项对象(错误处理):`, menuItem);
|
console.log(`构造的菜单项对象(错误处理):`, menuItem);
|
||||||
@@ -435,6 +379,9 @@ const saveConfig = async () => {
|
|||||||
if (saveResult.code === 200) {
|
if (saveResult.code === 200) {
|
||||||
// 只有在数据库保存成功后,才保存到本地存储
|
// 只有在数据库保存成功后,才保存到本地存储
|
||||||
localStorage.setItem('homeFeaturesConfig', JSON.stringify(menuDataWithPaths))
|
localStorage.setItem('homeFeaturesConfig', JSON.stringify(menuDataWithPaths))
|
||||||
|
// 清除菜单树缓存,以便下次加载最新数据
|
||||||
|
localStorage.removeItem('menuTreeCache');
|
||||||
|
localStorage.removeItem('menuTreeCacheTimestamp');
|
||||||
ElMessage.success('配置保存成功')
|
ElMessage.success('配置保存成功')
|
||||||
// 触发全局事件,通知首页更新快捷功能
|
// 触发全局事件,通知首页更新快捷功能
|
||||||
window.dispatchEvent(new Event('homeFeaturesConfigUpdated'));
|
window.dispatchEvent(new Event('homeFeaturesConfigUpdated'));
|
||||||
@@ -493,6 +440,36 @@ const filterNode = (value, data) => {
|
|||||||
// 加载已保存的配置
|
// 加载已保存的配置
|
||||||
const loadSavedConfig = async () => {
|
const loadSavedConfig = async () => {
|
||||||
try {
|
try {
|
||||||
|
// 尝试从本地缓存获取配置
|
||||||
|
const cachedConfig = localStorage.getItem('homeFeaturesConfigCache');
|
||||||
|
const cacheTimestamp = localStorage.getItem('homeFeaturesConfigCacheTimestamp');
|
||||||
|
|
||||||
|
// 检查缓存是否有效(1小时内)
|
||||||
|
if (cachedConfig && cacheTimestamp) {
|
||||||
|
const cacheAge = Date.now() - parseInt(cacheTimestamp);
|
||||||
|
if (cacheAge < 60 * 60 * 1000) { // 1小时
|
||||||
|
const parsedConfig = JSON.parse(cachedConfig);
|
||||||
|
// 检查数据格式,如果是包含对象的数组(新格式),提取菜单ID
|
||||||
|
if (parsedConfig && Array.isArray(parsedConfig)) {
|
||||||
|
if (parsedConfig.length > 0 && typeof parsedConfig[0] === 'object' && parsedConfig[0].hasOwnProperty('menuId')) {
|
||||||
|
// 新格式:[{menuId: 1, fullPath: "...", ...}, ...]
|
||||||
|
checkedKeys.value = parsedConfig.map(item => item.menuId);
|
||||||
|
} else {
|
||||||
|
// 旧格式:[1, 2, 3, ...]
|
||||||
|
checkedKeys.value = parsedConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据保存的配置初始化已选择的功能
|
||||||
|
const allNodes = getAllNodes(menuTree.value)
|
||||||
|
const checkedNodes = allNodes.filter(node =>
|
||||||
|
checkedKeys.value.includes(node.menuId) && node.menuType === 'C'
|
||||||
|
)
|
||||||
|
selectedFunctions.value = checkedNodes
|
||||||
|
}
|
||||||
|
return; // 使用缓存数据,直接返回
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 优先从数据库获取已保存的配置
|
// 优先从数据库获取已保存的配置
|
||||||
const response = await getCurrentUserConfig('homeFeaturesConfig')
|
const response = await getCurrentUserConfig('homeFeaturesConfig')
|
||||||
let savedConfig = null;
|
let savedConfig = null;
|
||||||
@@ -539,6 +516,10 @@ const loadSavedConfig = async () => {
|
|||||||
checkedKeys.value.includes(node.menuId) && node.menuType === 'C'
|
checkedKeys.value.includes(node.menuId) && node.menuType === 'C'
|
||||||
)
|
)
|
||||||
selectedFunctions.value = checkedNodes
|
selectedFunctions.value = checkedNodes
|
||||||
|
|
||||||
|
// 将配置缓存到本地存储
|
||||||
|
localStorage.setItem('homeFeaturesConfigCache', JSON.stringify(parsedConfig));
|
||||||
|
localStorage.setItem('homeFeaturesConfigCacheTimestamp', Date.now().toString());
|
||||||
} else {
|
} else {
|
||||||
// 如果解析失败,使用默认配置
|
// 如果解析失败,使用默认配置
|
||||||
const defaultSelections = getDefaultSelections(menuTree.value)
|
const defaultSelections = getDefaultSelections(menuTree.value)
|
||||||
|
|||||||
@@ -59,9 +59,7 @@
|
|||||||
@click="handleQuickAccess(func)"
|
@click="handleQuickAccess(func)"
|
||||||
>
|
>
|
||||||
<div class="quick-icon">
|
<div class="quick-icon">
|
||||||
<el-icon :size="28" :color="func.iconColor">
|
<svg-icon :icon-class="func.icon" :style="{ fontSize: '28px', color: func.iconColor }" />
|
||||||
<component :is="func.icon" />
|
|
||||||
</el-icon>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="quick-label">{{ func.label }}</div>
|
<div class="quick-label">{{ func.label }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -138,6 +136,7 @@ import { getHomeStatistics, getPendingEmrCount } from '@/api/home'
|
|||||||
import { listTodo } from '@/api/workflow/task.js'
|
import { listTodo } from '@/api/workflow/task.js'
|
||||||
import { getCurrentUserConfig } from '@/api/system/userConfig'
|
import { getCurrentUserConfig } from '@/api/system/userConfig'
|
||||||
import { listMenu, getMenuFullPath } from '@/api/system/menu'
|
import { listMenu, getMenuFullPath } from '@/api/system/menu'
|
||||||
|
import { getTodayDoctorScheduleList } from '@/api/appointmentmanage/doctorSchedule'
|
||||||
import { ElDivider } from 'element-plus'
|
import { ElDivider } from 'element-plus'
|
||||||
import {
|
import {
|
||||||
User,
|
User,
|
||||||
@@ -220,6 +219,7 @@ import {
|
|||||||
|
|
||||||
// 为别名单独导入
|
// 为别名单独导入
|
||||||
import { InfoFilled as InfoFilledIcon, QuestionFilled as QuestionFilledIcon, SuccessFilled } from '@element-plus/icons-vue'
|
import { InfoFilled as InfoFilledIcon, QuestionFilled as QuestionFilledIcon, SuccessFilled } from '@element-plus/icons-vue'
|
||||||
|
import SvgIcon from '@/components/SvgIcon'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -400,8 +400,8 @@ const convertMenuIdsToQuickAccess = async (menuIds) => {
|
|||||||
return {
|
return {
|
||||||
key: menuItem.menuId,
|
key: menuItem.menuId,
|
||||||
label: menuItem.menuName,
|
label: menuItem.menuName,
|
||||||
icon: getIconComponent(menuItem.icon || 'Document'), // 使用菜单项的图标,如果没有则使用默认图标
|
icon: menuItem.icon || 'document', // 使用数据库中的图标类名
|
||||||
iconColor: getIconColorByMenuType(menuItem.menuType) || '#67C23A', // 使用菜单类型的颜色,如果没有则使用默认颜色
|
iconColor: menuItem.iconColor || getIconColorByMenuType(menuItem.menuType) || '#67C23A', // 优先使用数据库中的颜色,否则使用菜单类型的颜色
|
||||||
route: route
|
route: route
|
||||||
};
|
};
|
||||||
}).filter(item => item.route); // 过滤掉 route 为空的项
|
}).filter(item => item.route); // 过滤掉 route 为空的项
|
||||||
@@ -436,8 +436,8 @@ const convertMenuIdsToQuickAccess = async (menuIds) => {
|
|||||||
return {
|
return {
|
||||||
key: matchedMenu.perms || matchedMenu.path || `menu_${matchedMenu.menuId}`,
|
key: matchedMenu.perms || matchedMenu.path || `menu_${matchedMenu.menuId}`,
|
||||||
label: matchedMenu.menuName,
|
label: matchedMenu.menuName,
|
||||||
icon: getIconComponent(matchedMenu.icon),
|
icon: matchedMenu.icon || 'document', // 使用数据库中的图标类名
|
||||||
iconColor: getIconColorByMenuType(matchedMenu.menuType),
|
iconColor: matchedMenu.iconColor || getIconColorByMenuType(matchedMenu.menuType),
|
||||||
route: fullPath || matchedMenu.path // 确保 route 不为空
|
route: fullPath || matchedMenu.path // 确保 route 不为空
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -446,8 +446,8 @@ const convertMenuIdsToQuickAccess = async (menuIds) => {
|
|||||||
return {
|
return {
|
||||||
key: matchedMenu.perms || matchedMenu.path || `menu_${matchedMenu.menuId}`,
|
key: matchedMenu.perms || matchedMenu.path || `menu_${matchedMenu.menuId}`,
|
||||||
label: matchedMenu.menuName,
|
label: matchedMenu.menuName,
|
||||||
icon: getIconComponent(matchedMenu.icon),
|
icon: matchedMenu.icon || 'document', // 使用数据库中的图标类名
|
||||||
iconColor: getIconColorByMenuType(matchedMenu.menuType),
|
iconColor: matchedMenu.iconColor || getIconColorByMenuType(matchedMenu.menuType),
|
||||||
route: matchedMenu.path || matchedMenu.fullPath || '/' // 确保 route 不为空
|
route: matchedMenu.path || matchedMenu.fullPath || '/' // 确保 route 不为空
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -490,81 +490,6 @@ const flattenMenuTree = (menuTree) => {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取图标组件
|
|
||||||
const getIconComponent = (iconName) => {
|
|
||||||
if (!iconName) return Document;
|
|
||||||
// 移除前缀,如 fa-, el-icon-
|
|
||||||
const cleanIconName = iconName.replace(/^(fa-|el-icon-)/, '').toLowerCase();
|
|
||||||
|
|
||||||
const iconMap = {
|
|
||||||
'menu': markRaw(Menu),
|
|
||||||
'grid': markRaw(Grid),
|
|
||||||
'folder': markRaw(Folder),
|
|
||||||
'tickets': markRaw(Tickets),
|
|
||||||
'document': markRaw(Document),
|
|
||||||
'setting': markRaw(Setting),
|
|
||||||
'user': markRaw(User),
|
|
||||||
'goods': markRaw(Goods),
|
|
||||||
'chat-dot-square': markRaw(ChatDotSquare),
|
|
||||||
'histogram': markRaw(Histogram),
|
|
||||||
'wallet': markRaw(Wallet),
|
|
||||||
'office-building': markRaw(OfficeBuilding),
|
|
||||||
'postcard': markRaw(Postcard),
|
|
||||||
'collection': markRaw(Collection),
|
|
||||||
'video-play': markRaw(VideoPlay),
|
|
||||||
'camera': markRaw(Camera),
|
|
||||||
'headset': markRaw(Headset),
|
|
||||||
'phone': markRaw(Phone),
|
|
||||||
'message': markRaw(Message),
|
|
||||||
'chat-line-square': markRaw(ChatLineSquare),
|
|
||||||
'chat-round': markRaw(ChatRound),
|
|
||||||
'guide': markRaw(Guide),
|
|
||||||
'help': markRaw(Help),
|
|
||||||
'info-filled': markRaw(InfoFilled),
|
|
||||||
'circle-check': markRaw(CircleCheck),
|
|
||||||
'circle-close': markRaw(CircleClose),
|
|
||||||
'warning': markRaw(Warning),
|
|
||||||
'question-filled': markRaw(QuestionFilled),
|
|
||||||
'star': markRaw(Star),
|
|
||||||
'link': markRaw(Link),
|
|
||||||
'position': markRaw(Position),
|
|
||||||
'picture': markRaw(Picture),
|
|
||||||
'upload': markRaw(Upload),
|
|
||||||
'download': markRaw(Download),
|
|
||||||
'caret-left': markRaw(CaretLeft),
|
|
||||||
'caret-right': markRaw(CaretRight),
|
|
||||||
'more': markRaw(More),
|
|
||||||
'close': markRaw(Close),
|
|
||||||
'check': markRaw(Check),
|
|
||||||
'arrow-up': markRaw(ArrowUp),
|
|
||||||
'arrow-down': markRaw(ArrowDown),
|
|
||||||
'arrow-left': markRaw(ArrowLeft),
|
|
||||||
'arrow-right': markRaw(ArrowRight),
|
|
||||||
'plus': markRaw(Plus),
|
|
||||||
'minus': markRaw(Minus),
|
|
||||||
'zoom-in': markRaw(ZoomIn),
|
|
||||||
'zoom-out': markRaw(ZoomOut),
|
|
||||||
'refresh': markRaw(Refresh),
|
|
||||||
'search': markRaw(Search),
|
|
||||||
'edit': markRaw(Edit),
|
|
||||||
'delete': markRaw(Delete),
|
|
||||||
'share': markRaw(Share),
|
|
||||||
'view': markRaw(View),
|
|
||||||
'switch-button': markRaw(SwitchButton),
|
|
||||||
'hide': markRaw(Hide),
|
|
||||||
'finished': markRaw(Finished),
|
|
||||||
'circle-plus': markRaw(CirclePlus),
|
|
||||||
'remove': markRaw(Remove),
|
|
||||||
'circle-check-filled': markRaw(CircleCheckFilled),
|
|
||||||
'circle-close-filled': markRaw(CircleCloseFilled),
|
|
||||||
'warning-filled': markRaw(WarningFilled),
|
|
||||||
'info-filled-icon': markRaw(InfoFilledIcon),
|
|
||||||
'success-filled': markRaw(SuccessFilled),
|
|
||||||
'question-filled-icon': markRaw(QuestionFilledIcon)
|
|
||||||
};
|
|
||||||
|
|
||||||
return iconMap[cleanIconName] || markRaw(Document);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 根据菜单类型获取图标颜色
|
// 根据菜单类型获取图标颜色
|
||||||
const getIconColorByMenuType = (menuType) => {
|
const getIconColorByMenuType = (menuType) => {
|
||||||
@@ -581,48 +506,48 @@ const getDefaultQuickAccessConfig = () => {
|
|||||||
switch (role) {
|
switch (role) {
|
||||||
case 'doctor':
|
case 'doctor':
|
||||||
return [
|
return [
|
||||||
{ key: 'outpatient', label: '门诊接诊', icon: markRaw(ChatDotRound), iconColor: '#409eff', route: '/doctorstation' },
|
{ key: 'outpatient', label: '门诊接诊', icon: 'chat-dot-round', iconColor: '#409eff', route: '/doctorstation' },
|
||||||
{ key: 'emr', label: '病历管理', icon: markRaw(Document), iconColor: '#67c23a', route: '/doctorstation/doctorphrase' },
|
{ key: 'emr', label: '病历管理', icon: 'document', iconColor: '#67c23a', route: '/doctorstation/doctorphrase' },
|
||||||
{ key: 'prescription', label: '开立处方', icon: markRaw(Box), iconColor: '#e6a23c', route: '/clinicmanagement/ePrescribing' },
|
{ key: 'prescription', label: '开立处方', icon: 'box', iconColor: '#e6a23c', route: '/clinicmanagement/ePrescribing' },
|
||||||
{ key: 'history', label: '历史处方', icon: markRaw(Clock), iconColor: '#f56c6c', route: '/clinicmanagement/historicalPrescription' },
|
{ key: 'history', label: '历史处方', icon: 'clock', iconColor: '#f56c6c', route: '/clinicmanagement/historicalPrescription' },
|
||||||
{ key: 'schedule', label: '排班管理', icon: markRaw(Calendar), iconColor: '#909399', route: '/appoinmentmanage/deptManage' },
|
{ key: 'schedule', label: '排班管理', icon: 'calendar', iconColor: '#909399', route: '/appoinmentmanage/deptManage' },
|
||||||
{ key: 'inquiry', label: '患者查询', icon: markRaw(Search), iconColor: '#409eff', route: '/patientmanagement' }
|
{ key: 'inquiry', label: '患者查询', icon: 'search', iconColor: '#409eff', route: '/patientmanagement' }
|
||||||
];
|
];
|
||||||
case 'nurse':
|
case 'nurse':
|
||||||
return [
|
return [
|
||||||
{ key: 'ward', label: '病房管理', icon: markRaw(User), iconColor: '#409eff', route: '/inpatientNurse/inpatientNurseStation' },
|
{ key: 'ward', label: '病房管理', icon: 'user', iconColor: '#409eff', route: '/inpatientNurse/inpatientNurseStation' },
|
||||||
{ key: 'execution', label: '医嘱执行', icon: markRaw(Operation), iconColor: '#67c23a', route: '/inpatientNurse/medicalOrderExecution' },
|
{ key: 'execution', label: '医嘱执行', icon: 'operation', iconColor: '#67c23a', route: '/inpatientNurse/medicalOrderExecution' },
|
||||||
{ key: 'proofread', label: '医嘱核对', icon: markRaw(Document), iconColor: '#e6a23c', route: '/inpatientNurse/medicalOrderProofread' },
|
{ key: 'proofread', label: '医嘱核对', icon: 'document', iconColor: '#e6a23c', route: '/inpatientNurse/medicalOrderProofread' },
|
||||||
{ key: 'drugCollect', label: '领药管理', icon: markRaw(Box), iconColor: '#f56c6c', route: '/inpatientNurse/medicineCollect' },
|
{ key: 'drugCollect', label: '领药管理', icon: 'box', iconColor: '#f56c6c', route: '/inpatientNurse/medicineCollect' },
|
||||||
{ key: 'tpr', label: '体温单', icon: markRaw(Monitor), iconColor: '#909399', route: '/inpatientNurse/tprsheet' },
|
{ key: 'tpr', label: '体温单', icon: 'monitor', iconColor: '#909399', route: '/inpatientNurse/tprsheet' },
|
||||||
{ key: 'nursing', label: '护理记录', icon: markRaw(ChatDotRound), iconColor: '#409eff', route: '/inpatientNurse/nursingRecord' }
|
{ key: 'nursing', label: '护理记录', icon: 'chat-dot-round', iconColor: '#409eff', route: '/inpatientNurse/nursingRecord' }
|
||||||
];
|
];
|
||||||
case 'pharmacist':
|
case 'pharmacist':
|
||||||
return [
|
return [
|
||||||
{ key: 'dispensing', label: '发药管理', icon: markRaw(Box), iconColor: '#409eff', route: '/pharmacymanagement' },
|
{ key: 'dispensing', label: '发药管理', icon: 'box', iconColor: '#409eff', route: '/pharmacymanagement' },
|
||||||
{ key: 'prescription', label: '处方审核', icon: markRaw(Document), iconColor: '#67c23a', route: '/pharmacymanagement' },
|
{ key: 'prescription', label: '处方审核', icon: 'document', iconColor: '#67c23a', route: '/pharmacymanagement' },
|
||||||
{ key: 'inventory', label: '库存管理', icon: markRaw(Van), iconColor: '#e6a23c', route: '/medicineStorage' },
|
{ key: 'inventory', label: '库存管理', icon: 'van', iconColor: '#e6a23c', route: '/medicineStorage' },
|
||||||
{ key: 'purchase', label: '采购管理', icon: markRaw(ShoppingCart), iconColor: '#f56c6c', route: '/medicineStorage' },
|
{ key: 'purchase', label: '采购管理', icon: 'shopping-cart', iconColor: '#f56c6c', route: '/medicineStorage' },
|
||||||
{ key: 'warning', label: '效期预警', icon: markRaw(Warning), iconColor: '#f56c6c', route: '/medicationmanagement/statisticalManagement/statisticalManagement' },
|
{ key: 'warning', label: '效期预警', icon: 'warning', iconColor: '#f56c6c', route: '/medicationmanagement/statisticalManagement/statisticalManagement' },
|
||||||
{ key: 'statistics', label: '用药统计', icon: markRaw(DataLine), iconColor: '#909399', route: '/monitor' }
|
{ key: 'statistics', label: '用药统计', icon: 'data-line', iconColor: '#909399', route: '/monitor' }
|
||||||
];
|
];
|
||||||
case 'cashier':
|
case 'cashier':
|
||||||
return [
|
return [
|
||||||
{ key: 'registration', label: '挂号收费', icon: markRaw(Money), iconColor: '#409eff', route: '/charge/outpatientregistration' },
|
{ key: 'registration', label: '挂号收费', icon: 'money', iconColor: '#409eff', route: '/charge/outpatientregistration' },
|
||||||
{ key: 'clinicCharge', label: '门诊收费', icon: markRaw(Wallet), iconColor: '#67c23a', route: '/charge/cliniccharge' },
|
{ key: 'clinicCharge', label: '门诊收费', icon: 'wallet', iconColor: '#67c23a', route: '/charge/cliniccharge' },
|
||||||
{ key: 'refund', label: '退费管理', icon: markRaw(Document), iconColor: '#e6a23c', route: '/charge/clinicrefund' },
|
{ key: 'refund', label: '退费管理', icon: 'document', iconColor: '#e6a23c', route: '/charge/clinicrefund' },
|
||||||
{ key: 'invoice', label: '发票打印', icon: markRaw(Files), iconColor: '#f56c6c', route: '/basicmanage/InvoiceManagement' },
|
{ key: 'invoice', label: '发票打印', icon: 'files', iconColor: '#f56c6c', route: '/basicmanage/InvoiceManagement' },
|
||||||
{ key: 'record', label: '收费记录', icon: markRaw(Clock), iconColor: '#909399', route: '/charge/clinicRecord' },
|
{ key: 'record', label: '收费记录', icon: 'clock', iconColor: '#909399', route: '/charge/clinicRecord' },
|
||||||
{ key: 'insurance', label: '医保结算', icon: markRaw(Bell), iconColor: '#409eff', route: '/ybmanagement' }
|
{ key: 'insurance', label: '医保结算', icon: 'bell', iconColor: '#409eff', route: '/ybmanagement' }
|
||||||
];
|
];
|
||||||
default: // admin
|
default: // admin
|
||||||
return [
|
return [
|
||||||
{ key: 'patient', label: '患者管理', icon: markRaw(User), iconColor: '#409eff', route: '/patient/patientmgr' },
|
{ key: 'patient', label: '患者管理', icon: 'user', iconColor: '#409eff', route: '/patient/patientmgr' },
|
||||||
{ key: 'appointment', label: '预约管理', icon: markRaw(Calendar), iconColor: '#67c23a', route: '/appoinmentmanage' },
|
{ key: 'appointment', label: '预约管理', icon: 'calendar', iconColor: '#67c23a', route: '/appoinmentmanage' },
|
||||||
{ key: 'doctor', label: '医生管理', icon: markRaw(User), iconColor: '#e6a23c', route: '/doctorstation' },
|
{ key: 'doctor', label: '医生管理', icon: 'user', iconColor: '#e6a23c', route: '/doctorstation' },
|
||||||
{ key: 'surgery', label: '手术管理', icon: markRaw(Operation), iconColor: '#f56c6c', route: '/surgerymanage' },
|
{ key: 'surgery', label: '手术管理', icon: 'operation', iconColor: '#f56c6c', route: '/surgerymanage' },
|
||||||
{ key: 'drug', label: '药品管理', icon: markRaw(Box), iconColor: '#909399', route: '/pharmacymanagement' },
|
{ key: 'drug', label: '药品管理', icon: 'box', iconColor: '#909399', route: '/pharmacymanagement' },
|
||||||
{ key: 'statistic', label: '数据统计', icon: markRaw(TrendCharts), iconColor: '#409eff', route: '/monitor' }
|
{ key: 'statistic', label: '数据统计', icon: 'trend-charts', iconColor: '#409eff', route: '/monitor' }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -639,12 +564,7 @@ const updatePendingEmrTodo = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 今日日程
|
// 今日日程
|
||||||
const scheduleList = ref([
|
const scheduleList = ref([])
|
||||||
{ id: 1, time: '09:00', title: '科室晨会', location: '第一会议室', type: 'info', tag: '日常' },
|
|
||||||
{ id: 2, time: '10:30', title: '病例讨论', location: '第二会议室', type: 'primary', tag: '会议' },
|
|
||||||
{ id: 3, time: '14:00', title: '专家查房', location: '住院部3楼', type: 'warning', tag: '重要' },
|
|
||||||
{ id: 4, time: '16:00', title: '新药培训', location: '培训中心', type: 'success', tag: '培训' }
|
|
||||||
])
|
|
||||||
|
|
||||||
// 获取问候语
|
// 获取问候语
|
||||||
const getGreeting = () => {
|
const getGreeting = () => {
|
||||||
@@ -980,8 +900,58 @@ const getTaskIcon = (category) => {
|
|||||||
|
|
||||||
// 获取日程数据(实际应用中应该从API获取)
|
// 获取日程数据(实际应用中应该从API获取)
|
||||||
const fetchScheduleList = async () => {
|
const fetchScheduleList = async () => {
|
||||||
// TODO: 调用API获取真实数据
|
try {
|
||||||
console.log('Fetching schedule list...')
|
console.log('Fetching schedule list...')
|
||||||
|
const response = await getTodayDoctorScheduleList()
|
||||||
|
if (response.code === 200) {
|
||||||
|
// 将API返回的数据转换为前端所需的格式
|
||||||
|
const scheduleData = response.data.map((schedule, index) => {
|
||||||
|
// 根据排班类型设置标签类型
|
||||||
|
let tagType = 'info'
|
||||||
|
if (schedule.weekday) {
|
||||||
|
tagType = schedule.weekday.toLowerCase()
|
||||||
|
} else if (schedule.timePeriod) {
|
||||||
|
tagType = schedule.timePeriod.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确定标题
|
||||||
|
const title = schedule.doctor ? `${schedule.doctor}医生排班` : '医生排班'
|
||||||
|
|
||||||
|
// 确定位置
|
||||||
|
const location = schedule.clinic || schedule.deptId || '未知科室'
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: schedule.id || index,
|
||||||
|
time: schedule.startTime || '未知时间',
|
||||||
|
title: title,
|
||||||
|
location: location,
|
||||||
|
type: tagType,
|
||||||
|
tag: schedule.timePeriod || '排班'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新日程列表
|
||||||
|
scheduleList.value = scheduleData
|
||||||
|
} else {
|
||||||
|
console.error('获取排班信息失败:', response.msg)
|
||||||
|
// 如果API调用失败,使用默认数据
|
||||||
|
scheduleList.value = [
|
||||||
|
{ id: 1, time: '09:00', title: '科室晨会', location: '第一会议室', type: 'info', tag: '日常' },
|
||||||
|
{ id: 2, time: '10:30', title: '病例讨论', location: '第二会议室', type: 'primary', tag: '会议' },
|
||||||
|
{ id: 3, time: '14:00', title: '专家查房', location: '住院部3楼', type: 'warning', tag: '重要' },
|
||||||
|
{ id: 4, time: '16:00', title: '新药培训', location: '培训中心', type: 'success', tag: '培训' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取排班信息异常:', error)
|
||||||
|
// 如果出现异常,使用默认数据
|
||||||
|
scheduleList.value = [
|
||||||
|
{ id: 1, time: '09:00', title: '科室晨会', location: '第一会议室', type: 'info', tag: '日常' },
|
||||||
|
{ id: 2, time: '10:30', title: '病例讨论', location: '第二会议室', type: 'primary', tag: '会议' },
|
||||||
|
{ id: 3, time: '14:00', title: '专家查房', location: '住院部3楼', type: 'warning', tag: '重要' },
|
||||||
|
{ id: 4, time: '16:00', title: '新药培训', location: '培训中心', type: 'success', tag: '培训' }
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听本地存储变化,以便在其他标签页或窗口中修改配置后更新当前页面
|
// 监听本地存储变化,以便在其他标签页或窗口中修改配置后更新当前页面
|
||||||
|
|||||||
@@ -0,0 +1,335 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-form
|
||||||
|
:model="queryParams"
|
||||||
|
ref="queryRef"
|
||||||
|
:inline="true"
|
||||||
|
v-show="showSearch"
|
||||||
|
label-width="90px"
|
||||||
|
>
|
||||||
|
<el-form-item label="查询日期:">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryTime"
|
||||||
|
type="daterange"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
style="width: 300px; margin-right: 20px"
|
||||||
|
@change="handleQuery"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="结算类型:">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.settlementType"
|
||||||
|
placeholder="结算类型"
|
||||||
|
clearable
|
||||||
|
style="width: 150px; margin-right: 30px"
|
||||||
|
>
|
||||||
|
<el-option label="日结" value="daily" />
|
||||||
|
<el-option label="周结" value="weekly" />
|
||||||
|
<el-option label="月结" value="monthly" />
|
||||||
|
</el-select>
|
||||||
|
<el-button type="primary" plain icon="Search" @click="handleQuery">查询</el-button>
|
||||||
|
<el-button type="primary" plain icon="Printer" @click="handlePrint">打印</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="Plus"
|
||||||
|
@click="handleAdd"
|
||||||
|
v-hasPermi="['medication:dayEndSettlement:add']"
|
||||||
|
>新增</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
plain
|
||||||
|
icon="Edit"
|
||||||
|
:disabled="single"
|
||||||
|
@click="handleUpdate"
|
||||||
|
v-hasPermi="['medication:dayEndSettlement:edit']"
|
||||||
|
>修改</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
icon="Delete"
|
||||||
|
:disabled="multiple"
|
||||||
|
@click="handleDelete"
|
||||||
|
v-hasPermi="['medication:dayEndSettlement:remove']"
|
||||||
|
>删除</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
plain
|
||||||
|
icon="Download"
|
||||||
|
@click="handleExport"
|
||||||
|
v-hasPermi="['medication:dayEndSettlement:export']"
|
||||||
|
>导出</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="dayEndSettlementList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="结算单号" align="center" prop="settlementNo" />
|
||||||
|
<el-table-column label="结算日期" align="center" prop="settlementDate" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ parseTime(scope.row.settlementDate, '{y}-{m}-{d}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="结算类型" align="center" prop="settlementType" />
|
||||||
|
<el-table-column label="结算状态" align="center" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="总金额" align="center" prop="totalAmount" />
|
||||||
|
<el-table-column label="操作人" align="center" prop="operator" />
|
||||||
|
<el-table-column label="操作时间" align="center" prop="createTime" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['medication:dayEndSettlement:query']">查看</el-button>
|
||||||
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['medication:dayEndSettlement:edit']">修改</el-button>
|
||||||
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['medication:dayEndSettlement:remove']">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
v-show="total > 0"
|
||||||
|
:total="total"
|
||||||
|
v-model:page="queryParams.pageNum"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@size-change="getList"
|
||||||
|
@current-change="getList"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 添加或修改日结结算单对话框 -->
|
||||||
|
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||||
|
<el-form ref="dayEndSettlementRef" :model="form" :rules="rules" label-width="100px">
|
||||||
|
<el-form-item label="结算单号" prop="settlementNo">
|
||||||
|
<el-input v-model="form.settlementNo" placeholder="请输入结算单号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="结算日期" prop="settlementDate">
|
||||||
|
<el-date-picker clearable
|
||||||
|
v-model="form.settlementDate"
|
||||||
|
type="date"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
placeholder="请选择结算日期">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="结算类型" prop="settlementType">
|
||||||
|
<el-select v-model="form.settlementType" placeholder="请选择结算类型">
|
||||||
|
<el-option label="日结" value="daily" />
|
||||||
|
<el-option label="周结" value="weekly" />
|
||||||
|
<el-option label="月结" value="monthly" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="结算状态" prop="status">
|
||||||
|
<el-radio-group v-model="form.status">
|
||||||
|
<el-radio
|
||||||
|
v-for="dict in sys_normal_disable"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.value"
|
||||||
|
>{{ dict.label }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="总金额" prop="totalAmount">
|
||||||
|
<el-input-number v-model="form.totalAmount" placeholder="请输入总金额" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="DayEndSettlement">
|
||||||
|
import { listDayEndSettlement, getDayEndSettlement, delDayEndSettlement, addDayEndSettlement, updateDayEndSettlement } from "@/api/medicationmanagement/dayEndSettlement";
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const loading = ref(true);
|
||||||
|
const showSearch = ref(true);
|
||||||
|
const ids = ref([]);
|
||||||
|
const single = ref(true);
|
||||||
|
const multiple = ref(true);
|
||||||
|
const total = ref(0);
|
||||||
|
const title = ref("");
|
||||||
|
const open = ref(false);
|
||||||
|
const queryTime = ref([]);
|
||||||
|
|
||||||
|
const dayEndSettlementList = ref([]);
|
||||||
|
const queryFormRef = ref();
|
||||||
|
const dayEndSettlementRef = ref();
|
||||||
|
|
||||||
|
const queryParams = ref({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
settlementNo: null,
|
||||||
|
settlementDate: null,
|
||||||
|
settlementType: null,
|
||||||
|
status: null
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = ref({});
|
||||||
|
const rules = ref({
|
||||||
|
settlementNo: [
|
||||||
|
{ required: true, message: "结算单号不能为空", trigger: "blur" }
|
||||||
|
],
|
||||||
|
settlementDate: [
|
||||||
|
{ required: true, message: "结算日期不能为空", trigger: "blur" }
|
||||||
|
],
|
||||||
|
settlementType: [
|
||||||
|
{ required: true, message: "结算类型不能为空", trigger: "change" }
|
||||||
|
],
|
||||||
|
totalAmount: [
|
||||||
|
{ required: true, message: "总金额不能为空", trigger: "blur" }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
|
||||||
|
|
||||||
|
/** 查询日结结算单列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const response = await listDayEndSettlement(queryParams.value);
|
||||||
|
dayEndSettlementList.value = response.rows;
|
||||||
|
total.value = response.total;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取日结结算单列表失败:', error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
open.value = false;
|
||||||
|
reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = {
|
||||||
|
id: null,
|
||||||
|
settlementNo: null,
|
||||||
|
settlementDate: null,
|
||||||
|
settlementType: null,
|
||||||
|
status: "0",
|
||||||
|
totalAmount: null,
|
||||||
|
remark: null
|
||||||
|
};
|
||||||
|
proxy.resetForm("dayEndSettlementRef");
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryTime.value = [];
|
||||||
|
proxy.resetForm("queryRef");
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 多择框多选 */
|
||||||
|
const handleSelectionChange = (selection) => {
|
||||||
|
ids.value = selection.map(item => item.id);
|
||||||
|
single.value = selection.length !== 1;
|
||||||
|
multiple.value = !selection.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
const handleAdd = () => {
|
||||||
|
reset();
|
||||||
|
open.value = true;
|
||||||
|
title.value = "添加日结结算单";
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = (row) => {
|
||||||
|
reset();
|
||||||
|
const settlementId = row.id || ids.value[0];
|
||||||
|
getDayEndSettlement(settlementId).then(response => {
|
||||||
|
form.value = response.data;
|
||||||
|
open.value = true;
|
||||||
|
title.value = "修改日结结算单";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
proxy.$refs["dayEndSettlementRef"].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
if (form.value.id != null) {
|
||||||
|
updateDayEndSettlement(form.value).then(response => {
|
||||||
|
proxy.$modal.msgSuccess("修改成功");
|
||||||
|
open.value = false;
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
addDayEndSettlement(form.value).then(response => {
|
||||||
|
proxy.$modal.msgSuccess("新增成功");
|
||||||
|
open.value = false;
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = (row) => {
|
||||||
|
const settlementIds = row.id || ids.value;
|
||||||
|
proxy.$modal.confirm('是否确认删除日结结算单编号为"' + settlementIds + '"的数据项?').then(function() {
|
||||||
|
return delDayEndSettlement(settlementIds);
|
||||||
|
}).then(() => {
|
||||||
|
getList();
|
||||||
|
proxy.$modal.msgSuccess("删除成功");
|
||||||
|
}).catch(() => {});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = () => {
|
||||||
|
proxy.download("medication/dayEndSettlement/export", {
|
||||||
|
...queryParams.value
|
||||||
|
}, `dayEndSettlement_${new Date().getTime()}.xlsx`);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 打印按钮操作 */
|
||||||
|
const handlePrint = () => {
|
||||||
|
// TODO: 实现打印功能
|
||||||
|
proxy.$modal.msgSuccess("打印功能待实现");
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 查看按钮操作 */
|
||||||
|
const handleView = (row) => {
|
||||||
|
// TODO: 实现查看功能
|
||||||
|
proxy.$modal.msgSuccess("查看功能待实现");
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 初始化数据 */
|
||||||
|
getList();
|
||||||
|
</script>
|
||||||
@@ -124,9 +124,9 @@
|
|||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="菜单类型" prop="menuType">
|
<el-form-item label="菜单类型" prop="menuType">
|
||||||
<el-radio-group v-model="form.menuType">
|
<el-radio-group v-model="form.menuType">
|
||||||
<el-radio label="M">目录</el-radio>
|
<el-radio value="M">目录</el-radio>
|
||||||
<el-radio label="C">菜单</el-radio>
|
<el-radio value="C">菜单</el-radio>
|
||||||
<el-radio label="F">按钮</el-radio>
|
<el-radio value="F">按钮</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -174,8 +174,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<el-radio-group v-model="form.isFrame">
|
<el-radio-group v-model="form.isFrame">
|
||||||
<el-radio label="0">是</el-radio>
|
<el-radio value="0">是</el-radio>
|
||||||
<el-radio label="1">否</el-radio>
|
<el-radio value="1">否</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -247,8 +247,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<el-radio-group v-model="form.isCache">
|
<el-radio-group v-model="form.isCache">
|
||||||
<el-radio label="0">缓存</el-radio>
|
<el-radio value="0">缓存</el-radio>
|
||||||
<el-radio label="1">不缓存</el-radio>
|
<el-radio value="1">不缓存</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -266,7 +266,7 @@
|
|||||||
<el-radio
|
<el-radio
|
||||||
v-for="dict in sys_show_hide"
|
v-for="dict in sys_show_hide"
|
||||||
:key="dict.value"
|
:key="dict.value"
|
||||||
:label="dict.value"
|
:value="dict.value"
|
||||||
>{{ dict.label }}</el-radio>
|
>{{ dict.label }}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -285,7 +285,7 @@
|
|||||||
<el-radio
|
<el-radio
|
||||||
v-for="dict in sys_normal_disable"
|
v-for="dict in sys_normal_disable"
|
||||||
:key="dict.value"
|
:key="dict.value"
|
||||||
:label="dict.value"
|
:value="dict.value"
|
||||||
>{{ dict.label }}</el-radio>
|
>{{ dict.label }}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -303,7 +303,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Menu">
|
<script setup name="Menu">
|
||||||
import {addMenu, delMenu, getMenu, listMenu, updateMenu} from "@/api/system/menu";
|
import {addMenu, delMenu, getMenu, listMenu, updateMenu, treeselect} from "@/api/system/menu";
|
||||||
import SvgIcon from "@/components/SvgIcon";
|
import SvgIcon from "@/components/SvgIcon";
|
||||||
import IconSelect from "@/components/IconSelect";
|
import IconSelect from "@/components/IconSelect";
|
||||||
|
|
||||||
@@ -351,10 +351,28 @@ async function getList() {
|
|||||||
/** 查询菜单下拉树结构 */
|
/** 查询菜单下拉树结构 */
|
||||||
function getTreeselect() {
|
function getTreeselect() {
|
||||||
menuOptions.value = [];
|
menuOptions.value = [];
|
||||||
listMenu().then(response => {
|
// 使用专门的treeselect API,它返回预构建的树形结构
|
||||||
const menu = { menuId: 0, menuName: "主类目", children: [] };
|
treeselect().then(response => {
|
||||||
menu.children = proxy.handleTree(response.data, "menuId");
|
// TreeSelect对象使用id、label、children字段,但el-tree-select组件期望menuId、menuName、children字段
|
||||||
menuOptions.value.push(menu);
|
// 需要将TreeSelect对象转换为el-tree-select组件期望的格式
|
||||||
|
const convertTreeSelectToMenuFormat = (treeSelectList) => {
|
||||||
|
return treeSelectList.map(item => ({
|
||||||
|
menuId: item.id,
|
||||||
|
menuName: item.label,
|
||||||
|
value: item.id,
|
||||||
|
label: item.label,
|
||||||
|
children: item.children ? convertTreeSelectToMenuFormat(item.children) : []
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const rootNode = {
|
||||||
|
menuId: 0,
|
||||||
|
menuName: "主类目",
|
||||||
|
value: 0,
|
||||||
|
label: "主类目",
|
||||||
|
children: convertTreeSelectToMenuFormat(response.data)
|
||||||
|
};
|
||||||
|
menuOptions.value.push(rootNode);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
@@ -426,7 +444,7 @@ async function handleUpdate(row) {
|
|||||||
const response = await getMenu(row.menuId);
|
const response = await getMenu(row.menuId);
|
||||||
form.value = response.data;
|
form.value = response.data;
|
||||||
// 使用后端返回的完整路径
|
// 使用后端返回的完整路径
|
||||||
form.value.fullPath = row.fullPath || row.path;
|
form.value.fullPath = response.data.fullPath || response.data.path;
|
||||||
open.value = true;
|
open.value = true;
|
||||||
title.value = "修改菜单";
|
title.value = "修改菜单";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user