feat(router): 添加医生工作站等功能模块路由配置
- 新增医生工作站路由,包含待写病历功能 - 添加全部功能模块路由,支持功能列表和配置页面 - 集成待办事项模块路由,完善工作流功能 - 配置相关API接口和服务类,实现用户配置管理 - 实现待写病历列表展示和相关业务逻辑 - 完善首页统计数据显示功能
This commit is contained in:
418
openhis-ui-vue3/src/views/todo/index.vue
Normal file
418
openhis-ui-vue3/src/views/todo/index.vue
Normal file
@@ -0,0 +1,418 @@
|
||||
<template>
|
||||
<div class="todo-container">
|
||||
<div class="page-header">
|
||||
<h2>全部待办事项</h2>
|
||||
<p>这里展示了您的所有待办事项</p>
|
||||
</div>
|
||||
|
||||
<div class="filter-section">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true">
|
||||
<el-form-item label="优先级" prop="priority">
|
||||
<el-select v-model="queryParams.priority" placeholder="请选择优先级" clearable>
|
||||
<el-option label="高" value="high"></el-option>
|
||||
<el-option label="中" value="medium"></el-option>
|
||||
<el-option label="低" value="low"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
|
||||
<el-option label="未处理" value="pending"></el-option>
|
||||
<el-option label="处理中" value="processing"></el-option>
|
||||
<el-option label="已完成" value="completed"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="todo-list">
|
||||
<el-card
|
||||
v-for="todo in todoList"
|
||||
:key="todo.id"
|
||||
class="todo-item"
|
||||
:class="`priority-${todo.priority} status-${todo.status}`"
|
||||
@click="handleTodoClick(todo)"
|
||||
>
|
||||
<div class="todo-header">
|
||||
<div class="todo-title">
|
||||
<el-icon :size="16" :color="getPriorityColor(todo.priority)">
|
||||
<component :is="todo.icon" />
|
||||
</el-icon>
|
||||
<span class="title-text">{{ todo.title }}</span>
|
||||
</div>
|
||||
<div class="todo-status">
|
||||
<el-tag :type="getStatusTagType(todo.status)">{{ getStatusText(todo.status) }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="todo-content">
|
||||
<p class="todo-desc">{{ todo.desc }}</p>
|
||||
<div class="todo-meta">
|
||||
<span class="todo-time">{{ todo.time }}</span>
|
||||
<span class="todo-priority" :style="{ color: getPriorityColor(todo.priority) }">
|
||||
{{ getPriorityText(todo.priority) }}优先级
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="todo-actions">
|
||||
<el-button type="primary" size="small" @click.stop="handleProcess(todo)">立即处理</el-button>
|
||||
<el-button size="small" @click.stop="handleDetails(todo)">查看详情</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<div v-if="todoList.length === 0 && !loading" class="empty-state">
|
||||
<el-empty description="暂无待办事项" />
|
||||
</div>
|
||||
<div v-if="loading" class="loading-state">
|
||||
<el-skeleton :rows="6" animated />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryParams.pageNum"
|
||||
:page-sizes="[5, 10, 20, 50]"
|
||||
:page-size="queryParams.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
>
|
||||
</el-pagination>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { listTodo } from '@/api/workflow/task.js'
|
||||
import { markRaw } from 'vue'
|
||||
import {
|
||||
Document,
|
||||
User,
|
||||
ChatDotRound,
|
||||
Warning,
|
||||
Files,
|
||||
DataLine,
|
||||
Operation,
|
||||
Setting
|
||||
} from '@element-plus/icons-vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 待办事项数据
|
||||
const todoList = ref([])
|
||||
const loading = ref(true)
|
||||
|
||||
// 查询参数
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
priority: '',
|
||||
status: ''
|
||||
})
|
||||
|
||||
// 分页参数
|
||||
const total = ref(0)
|
||||
|
||||
// 获取待办事项列表
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const response = await listTodo(queryParams.value)
|
||||
if (response.code === 200) {
|
||||
// 将工作流任务数据转换为待办事项格式
|
||||
const rows = response.rows || [];
|
||||
todoList.value = rows.map((task, index) => ({
|
||||
id: task.id || index,
|
||||
title: task.taskName || task.name || '待办事项',
|
||||
desc: task.description || '暂无描述',
|
||||
priority: getPriorityFromTask(task),
|
||||
status: getTaskStatus(task.status || task.state),
|
||||
icon: getTaskIcon(task.category),
|
||||
time: formatDate(task.createTime || task.createTimeStr),
|
||||
taskInfo: task // 保存原始任务信息,便于后续处理
|
||||
}))
|
||||
total.value = response.total || 0
|
||||
} else {
|
||||
console.error('获取待办事项失败:', response.msg)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取待办事项异常:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 根据任务信息确定优先级
|
||||
const getPriorityFromTask = (task) => {
|
||||
// 根据任务的某些属性来确定优先级,这里可以根据实际业务调整
|
||||
if (task.priority && task.priority > 50) return 'high'
|
||||
if (task.priority && task.priority > 20) return 'medium'
|
||||
return 'low'
|
||||
}
|
||||
|
||||
// 获取任务状态
|
||||
const getTaskStatus = (status) => {
|
||||
// 根据实际返回的状态值映射
|
||||
if (status === 'completed' || status === 'finish') return 'completed'
|
||||
if (status === 'processing' || status === 'active') return 'processing'
|
||||
return 'pending'
|
||||
}
|
||||
|
||||
// 获取任务图标
|
||||
const getTaskIcon = (category) => {
|
||||
// 根据任务分类确定图标
|
||||
if (category && category.includes('approval')) return markRaw(Document)
|
||||
if (category && category.includes('patient')) return markRaw(User)
|
||||
if (category && category.includes('feedback')) return markRaw(ChatDotRound)
|
||||
if (category && category.includes('warning')) return markRaw(Warning)
|
||||
if (category && category.includes('report')) return markRaw(Files)
|
||||
if (category && category.includes('data')) return markRaw(DataLine)
|
||||
if (category && category.includes('operation')) return markRaw(Operation)
|
||||
if (category && category.includes('system')) return markRaw(Setting)
|
||||
return markRaw(Document) // 默认图标
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return '刚刚'
|
||||
|
||||
const date = new Date(dateStr)
|
||||
const now = new Date()
|
||||
const diffMs = now - date
|
||||
const diffMins = Math.floor(diffMs / 60000)
|
||||
const diffHours = Math.floor(diffMins / 60)
|
||||
const diffDays = Math.floor(diffHours / 24)
|
||||
|
||||
if (diffMins < 1) return '刚刚'
|
||||
if (diffMins < 60) return `${diffMins}分钟前`
|
||||
if (diffHours < 24) return `${diffHours}小时前`
|
||||
if (diffDays < 7) return `${diffDays}天前`
|
||||
|
||||
// 返回具体日期
|
||||
return `${date.getFullYear()}-${(date.getMonth()+1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
// 重置查询
|
||||
const resetQuery = () => {
|
||||
queryParams.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
priority: '',
|
||||
status: ''
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
// 分页大小改变
|
||||
const handleSizeChange = (size) => {
|
||||
queryParams.value.pageSize = size
|
||||
getList()
|
||||
}
|
||||
|
||||
// 当前页改变
|
||||
const handleCurrentChange = (page) => {
|
||||
queryParams.value.pageNum = page
|
||||
getList()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
// 获取优先级颜色
|
||||
const getPriorityColor = (priority) => {
|
||||
switch (priority) {
|
||||
case 'high': return '#F56C6C'
|
||||
case 'medium': return '#E6A23C'
|
||||
case 'low': return '#67C23A'
|
||||
default: return '#909399'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取优先级文本
|
||||
const getPriorityText = (priority) => {
|
||||
switch (priority) {
|
||||
case 'high': return '高'
|
||||
case 'medium': return '中'
|
||||
case 'low': return '低'
|
||||
default: return ''
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusTagType = (status) => {
|
||||
switch (status) {
|
||||
case 'pending': return 'info'
|
||||
case 'processing': return 'warning'
|
||||
case 'completed': return 'success'
|
||||
default: return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
switch (status) {
|
||||
case 'pending': return '未处理'
|
||||
case 'processing': return '处理中'
|
||||
case 'completed': return '已完成'
|
||||
default: return ''
|
||||
}
|
||||
}
|
||||
|
||||
// 处理待办事项点击
|
||||
const handleTodoClick = (todo) => {
|
||||
handleDetails(todo)
|
||||
}
|
||||
|
||||
// 处理立即处理按钮
|
||||
const handleProcess = (todo) => {
|
||||
console.log('处理待办事项:', todo)
|
||||
// 这里可以添加具体的处理逻辑
|
||||
router.push(`/todo/process/${todo.id}`)
|
||||
}
|
||||
|
||||
// 处理查看详情按钮
|
||||
const handleDetails = (todo) => {
|
||||
console.log('查看详情:', todo)
|
||||
// 这里可以添加查看详细信息的逻辑
|
||||
router.push(`/todo/detail/${todo.id}`)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.todo-container {
|
||||
padding: 20px;
|
||||
background: #f5f7fa;
|
||||
min-height: calc(100vh - 120px);
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.todo-list {
|
||||
.todo-item {
|
||||
margin-bottom: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border-left: 4px solid #409EFF;
|
||||
|
||||
&:hover {
|
||||
transform: translateX(4px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&.priority-high {
|
||||
border-left-color: #F56C6C;
|
||||
}
|
||||
|
||||
&.priority-medium {
|
||||
border-left-color: #E6A23C;
|
||||
}
|
||||
|
||||
&.priority-low {
|
||||
border-left-color: #67C23A;
|
||||
}
|
||||
|
||||
&.status-completed {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.todo-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.todo-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.title-text {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.todo-content {
|
||||
.todo-desc {
|
||||
color: #606266;
|
||||
margin-bottom: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.todo-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
|
||||
.todo-priority {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.todo-actions {
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
.loading-state {
|
||||
padding: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user