feat(invoice): 完善发票管理权限控制和检验申请功能

- 超级管理员可以编辑操作员字段,普通用户不可编辑
- 修改权限判断逻辑,只有用户名等于 'admin' 的用户才是超级管理员
- 非超级管理员用户只能查询自己的发票数据
- 添加根据员工ID更新操作员名称功能
- 新增行时根据用户权限填充信息
- 严格检查权限,超级管理员可以删除所有记录,普通用户只能删除自己维护的记录
- 在 bargain 组件中验证患者选择
- 添加检验申请单相关API接口
- 在医生工作站中添加检验申请tab页
- 实现检验申请单的增删改查功能
- 添加公告通知已读记录相关功能
- 实现用户未读公告数量统计和标记已读功能
This commit is contained in:
2025-12-30 13:52:15 +08:00
parent 49b8a975a8
commit 1c16d6ba0f
10 changed files with 443 additions and 41 deletions

View File

@@ -9,6 +9,23 @@ export function listNotice(query) {
})
}
// 获取公开的公告列表(给普通用户使用)
export function getPublicNoticeList(query) {
return request({
url: '/system/notice/public/list',
method: 'get',
params: query
})
}
// 获取当前用户的通知列表
export function getUserNotices() {
return request({
url: '/system/notice/public/notice',
method: 'get'
})
}
// 查询公告详细
export function getNotice(noticeId) {
return request({
@@ -41,4 +58,53 @@ export function delNotice(noticeId) {
url: '/system/notice/' + noticeId,
method: 'delete'
})
}
}
// 发布公告
export function publishNotice(noticeId) {
return request({
url: '/system/notice/publish/' + noticeId,
method: 'put'
})
}
// 取消发布公告
export function unpublishNotice(noticeId) {
return request({
url: '/system/notice/unpublish/' + noticeId,
method: 'put'
})
}
// 获取未读公告/通知数量
export function getUnreadCount() {
return request({
url: '/system/notice/public/unread/count',
method: 'get'
})
}
// 标记公告/通知为已读
export function markAsRead(noticeId) {
return request({
url: '/system/notice/public/read/' + noticeId,
method: 'post'
})
}
// 批量标记公告/通知为已读
export function markAllAsRead(noticeIds) {
return request({
url: '/system/notice/public/read/all',
method: 'post',
data: noticeIds
})
}
// 获取用户已读公告/通知ID列表
export function getReadNoticeIds() {
return request({
url: '/system/notice/public/read/ids',
method: 'get'
})
}

View File

@@ -4,6 +4,14 @@
<template v-if="appStore.device !== 'mobile'">
<header-search id="header-search" class="right-menu-item" />
</template>
<!-- 公告和通知按钮 -->
<el-tooltip content="公告/通知" placement="bottom">
<div class="right-menu-item notice-btn" @click="openNoticePanel">
<el-badge :value="unreadCount" :hidden="unreadCount === 0" class="notice-badge">
<el-icon><Bell /></el-icon>
</el-badge>
</div>
</el-tooltip>
<div class="avatar-container">
<div class="avatar-wrapper">
<el-dropdown
@@ -83,22 +91,28 @@
</div>
</template>
</el-dialog>
<!-- 公告/通知面板 -->
<NoticePanel ref="noticePanelRef" @updateUnreadCount="updateUnreadCount" />
</div>
</template>
<script setup>
import { onMounted } from 'vue';
import { onMounted, ref } from 'vue';
import { ElMessageBox } from 'element-plus';
import { Bell } from '@element-plus/icons-vue';
import Breadcrumb from '@/components/Breadcrumb';
import TopNav from '@/components/TopNav';
import Hamburger from '@/components/Hamburger';
import Screenfull from '@/components/Screenfull';
import SizeSelect from '@/components/SizeSelect';
import HeaderSearch from '@/components/HeaderSearch';
import NoticePanel from '@/components/NoticePanel';
import useAppStore from '@/store/modules/app';
import useUserStore from '@/store/modules/user';
import useSettingsStore from '@/store/modules/settings';
import { getOrg, switchOrg } from '@/api/login';
import { getUnreadCount } from '@/api/system/notice';
const appStore = useAppStore();
const userStore = useUserStore();
@@ -106,6 +120,22 @@ const settingsStore = useSettingsStore();
const orgOptions = ref([]);
const showDialog = ref(false);
const orgId = ref('');
const noticePanelRef = ref(null);
const unreadCount = ref(0);
// 加载未读数量
function loadUnreadCount() {
getUnreadCount().then(res => {
unreadCount.value = res.data || 0;
}).catch(() => {
unreadCount.value = 0;
});
}
// 更新未读数量
function updateUnreadCount() {
loadUnreadCount();
}
function loadOrgList() {
getOrg().then((res) => {
@@ -115,6 +145,7 @@ function loadOrgList() {
onMounted(() => {
loadOrgList();
loadUnreadCount();
});
function handleOrgSwitch(selectedOrgId) {
@@ -160,12 +191,12 @@ function logout() {
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
userStore.logOut().then(() => {
location.href = '/index';
});
})
.catch(() => {});
.then(() => {
userStore.logOut().then(() => {
location.href = '/index';
});
})
.catch(() => {});
}
function submit() {
@@ -182,6 +213,13 @@ const emits = defineEmits(['setLayout']);
function setLayout() {
emits('setLayout');
}
// 打开公告/通知面板
function openNoticePanel() {
if (noticePanelRef.value) {
noticePanelRef.value.open();
}
}
</script>
<style lang='scss' scoped>
@@ -222,7 +260,31 @@ function setLayout() {
transition: background 0.3s;
&:hover {
background: rgba(255, 255, 255, 0.1);
background: rgba(255,255,255,0.1);
}
}
}
.notice-btn {
cursor: pointer;
padding: 0 10px;
height: 100%;
display: flex;
align-items: center;
.notice-badge {
:deep(.el-badge__content) {
top: -5px;
right: -5px;
}
}
.el-icon {
font-size: 20px;
color: #606266;
&:hover {
color: #409eff;
}
}
}

View File

@@ -70,11 +70,12 @@
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" prop="noticeId" width="100" />
<el-table-column label="序号" align="center" prop="noticeId" width="80" />
<el-table-column
label="公告标题"
align="center"
prop="noticeTitle"
min-width="200"
:show-overflow-tooltip="true"
/>
<el-table-column label="公告类型" align="center" prop="noticeType" width="100">
@@ -82,20 +83,40 @@
<dict-tag :options="sys_notice_type" :value="scope.row.noticeType" />
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="100">
<el-table-column label="状态" align="center" prop="status" width="90">
<template #default="scope">
<dict-tag :options="sys_notice_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建者" align="center" prop="createBy" width="100" />
<el-table-column label="创建时间" align="center" prop="createTime" width="100">
<el-table-column label="发布状态" align="center" prop="publishStatus" width="90">
<template #default="scope">
<el-tag v-if="scope.row.publishStatus === '1'" type="success">已发布</el-tag>
<el-tag v-else type="info">未发布</el-tag>
</template>
</el-table-column>
<el-table-column label="创建者" align="center" prop="createBy" width="90" />
<el-table-column label="创建时间" align="center" prop="createTime" width="110">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" min-width="280">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']">修改</el-button>
<el-button
v-if="scope.row.publishStatus !== '1'"
link type="success"
icon="Promotion"
@click="handlePublish(scope.row)"
v-hasPermi="['system:notice:edit']"
>发布</el-button>
<el-button
v-else
link type="warning"
icon="RemoveFilled"
@click="handleUnpublish(scope.row)"
v-hasPermi="['system:notice:edit']"
>取消发布</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']" >删除</el-button>
</template>
</el-table-column>
@@ -159,7 +180,7 @@
</template>
<script setup name="Notice">
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
import { listNotice, getNotice, delNotice, addNotice, updateNotice, publishNotice, unpublishNotice } from "@/api/system/notice";
const { proxy } = getCurrentInstance();
const { sys_notice_status, sys_notice_type } = proxy.useDict("sys_notice_status", "sys_notice_type");
@@ -212,7 +233,8 @@ function reset() {
noticeTitle: undefined,
noticeType: undefined,
noticeContent: undefined,
status: "0"
status: "0",
publishStatus: "0"
};
proxy.resetForm("noticeRef");
}
@@ -259,6 +281,8 @@ function submitForm() {
getList();
});
} else {
// 新增时默认为未发布状态
form.value.publishStatus = "0";
addNotice(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
@@ -278,6 +302,24 @@ function handleDelete(row) {
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 发布按钮操作 */
function handlePublish(row) {
proxy.$modal.confirm('确认发布该公告吗?发布后将对所有用户可见。').then(function() {
return publishNotice(row.noticeId);
}).then(() => {
getList();
proxy.$modal.msgSuccess("发布成功");
}).catch(() => {});
}
/** 取消发布按钮操作 */
function handleUnpublish(row) {
proxy.$modal.confirm('确认取消发布该公告吗?取消后将不再对用户可见。').then(function() {
return unpublishNotice(row.noticeId);
}).then(() => {
getList();
proxy.$modal.msgSuccess("已取消发布");
}).catch(() => {});
}
getList();
</script>