代办任务
This commit is contained in:
+48
-7
@@ -6,7 +6,11 @@ export function tcmDiagnosisLists(params: any) {
|
||||
}
|
||||
|
||||
// 医助理诊单统计(按部门、按人)
|
||||
export function assistantDiagnosisStats(params?: { start_time?: string; end_time?: string; days?: number }) {
|
||||
export function assistantDiagnosisStats(params?: {
|
||||
start_time?: string
|
||||
end_time?: string
|
||||
days?: number
|
||||
}) {
|
||||
return request.get({ url: '/tcm.diagnosis/assistantDiagnosisStats', params })
|
||||
}
|
||||
|
||||
@@ -298,7 +302,11 @@ export function prescriptionVoid(params: { id: number }) {
|
||||
}
|
||||
|
||||
/** 处方审核:action approve | reject(驳回同时作废处方) */
|
||||
export function prescriptionAudit(params: { id: number; action: 'approve' | 'reject'; remark?: string }) {
|
||||
export function prescriptionAudit(params: {
|
||||
id: number
|
||||
action: 'approve' | 'reject'
|
||||
remark?: string
|
||||
}) {
|
||||
return request.post({ url: '/tcm.prescription/audit', params })
|
||||
}
|
||||
|
||||
@@ -401,10 +409,7 @@ export function prescriptionOrderAddPayOrder(params: {
|
||||
}
|
||||
|
||||
/** 为「已发货」订单关联已有支付单并重置支付审核为待审核 */
|
||||
export function prescriptionOrderLinkPayOrder(params: {
|
||||
id: number
|
||||
pay_order_id: number
|
||||
}) {
|
||||
export function prescriptionOrderLinkPayOrder(params: { id: number; pay_order_id: number }) {
|
||||
return request.post({ url: '/tcm.prescriptionOrder/linkPayOrder', params })
|
||||
}
|
||||
|
||||
@@ -419,7 +424,11 @@ export function prescriptionOrderSubmitGancaoRecipel(params: { id: number }) {
|
||||
}
|
||||
|
||||
/** 甘草药管家:预下单测试(仅 CTM_PREVIEW,不提交订单) */
|
||||
export function prescriptionOrderPreviewGancaoRecipel(params: { id: number; dose_count?: number; medication_days?: number }) {
|
||||
export function prescriptionOrderPreviewGancaoRecipel(params: {
|
||||
id: number
|
||||
dose_count?: number
|
||||
medication_days?: number
|
||||
}) {
|
||||
return request.post({ url: '/tcm.prescriptionOrder/previewGancaoRecipel', params })
|
||||
}
|
||||
|
||||
@@ -454,3 +463,35 @@ export function prescriptionLibraryDelete(params: { id: number }) {
|
||||
export function prescriptionLibraryDetail(params: { id: number }) {
|
||||
return request.get({ url: '/tcm.prescriptionLibrary/detail', params })
|
||||
}
|
||||
|
||||
// ========== 诊单待办事项(T5) ==========
|
||||
|
||||
/** 待办列表(按 diagnosis_id) */
|
||||
export function diagnosisTodoLists(params: {
|
||||
diagnosis_id: number
|
||||
page_no?: number
|
||||
page_size?: number
|
||||
status?: number
|
||||
creator_id?: number
|
||||
}) {
|
||||
return request.get({ url: '/tcm.diagnosisTodo/lists', params })
|
||||
}
|
||||
|
||||
/** 新增待办(remind_time 为 unix 秒级时间戳) */
|
||||
export function diagnosisTodoAdd(params: {
|
||||
diagnosis_id: number
|
||||
content: string
|
||||
remind_time: number
|
||||
}) {
|
||||
return request.post({ url: '/tcm.diagnosisTodo/add', params })
|
||||
}
|
||||
|
||||
/** 取消待办(仅 status=0 / 创建人或超管) */
|
||||
export function diagnosisTodoCancel(params: { id: number }) {
|
||||
return request.post({ url: '/tcm.diagnosisTodo/cancel', params })
|
||||
}
|
||||
|
||||
/** 待办详情 */
|
||||
export function diagnosisTodoDetail(params: { id: number }) {
|
||||
return request.get({ url: '/tcm.diagnosisTodo/detail', params })
|
||||
}
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
<template>
|
||||
<div class="diagnosis-todo-list">
|
||||
<div class="toolbar">
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="!props.diagnosisId"
|
||||
@click="handleAdd"
|
||||
v-perms="['tcm.diagnosisTodo/add']"
|
||||
>
|
||||
+ 新增待办
|
||||
</el-button>
|
||||
<el-radio-group v-model="filterStatus" class="ml-3" @change="handleFilterChange">
|
||||
<el-radio-button :value="''">全部</el-radio-button>
|
||||
<el-radio-button :value="0">待执行</el-radio-button>
|
||||
<el-radio-button :value="1">已发送</el-radio-button>
|
||||
<el-radio-button :value="3">失败</el-radio-button>
|
||||
<el-radio-button :value="2">已取消</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-button class="ml-3" @click="fetchList">刷新</el-button>
|
||||
<span class="hint">
|
||||
推送由后端 cron 分钟级触发,需服务器配置
|
||||
<code>tcm:diagnosis-todo-notify</code>。
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="pager.loading"
|
||||
:data="pager.lists"
|
||||
border
|
||||
class="todo-table"
|
||||
empty-text="暂无待办"
|
||||
row-key="id"
|
||||
>
|
||||
<el-table-column label="提醒时间" prop="remind_time_text" width="160" />
|
||||
<el-table-column label="内容" prop="content" min-width="240" show-overflow-tooltip />
|
||||
<el-table-column label="状态" width="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="statusTagType(row.status)" effect="light" size="small">
|
||||
{{ row.status_text }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建人" prop="creator_name" width="120">
|
||||
<template #default="{ row }">{{ row.creator_name || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="推送时间" prop="notified_at_text" width="160">
|
||||
<template #default="{ row }">{{ row.notified_at_text || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="失败原因" prop="error" min-width="200" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.status === 3" class="text-danger">{{ row.error || '未知错误' }}</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="row.status === 0 && row.can_cancel"
|
||||
link
|
||||
type="danger"
|
||||
@click="handleCancel(row)"
|
||||
v-perms="['tcm.diagnosisTodo/cancel']"
|
||||
>
|
||||
取消
|
||||
</el-button>
|
||||
<span v-else class="text-muted">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-wrap">
|
||||
<pagination v-model="pager" @change="fetchList" />
|
||||
</div>
|
||||
|
||||
<!-- 新增弹框 -->
|
||||
<el-dialog
|
||||
v-model="addDialogVisible"
|
||||
title="新增待办"
|
||||
width="520px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form ref="addFormRef" :model="addForm" :rules="addRules" label-width="100px">
|
||||
<el-form-item label="提醒时间" prop="remindAt">
|
||||
<el-date-picker
|
||||
v-model="addForm.remindAt"
|
||||
type="datetime"
|
||||
placeholder="选择提醒时间"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
value-format="x"
|
||||
:disabled-date="disablePastDate"
|
||||
class="w-full"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="提醒内容" prop="content">
|
||||
<el-input
|
||||
v-model="addForm.content"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
:maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="例:3 天后回访患者复测餐后血糖"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="提醒人">
|
||||
<span class="text-muted">企微推送给当前登录账号(创建人本人)</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="addDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="addSubmitting" @click="handleAddSubmit">
|
||||
提交
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { diagnosisTodoLists, diagnosisTodoAdd, diagnosisTodoCancel } from '@/api/tcm'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
interface Props {
|
||||
diagnosisId: number | null | undefined
|
||||
patientId?: number | null
|
||||
patientName?: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
// pager 与项目内 <pagination v-model="pager" /> 约定的字段保持一致
|
||||
const pager = reactive({
|
||||
page: 1,
|
||||
size: 15,
|
||||
count: 0,
|
||||
loading: false,
|
||||
lists: [] as any[]
|
||||
})
|
||||
|
||||
const filterStatus = ref<number | ''>('')
|
||||
|
||||
const fetchList = async () => {
|
||||
if (!props.diagnosisId || Number(props.diagnosisId) <= 0) {
|
||||
pager.lists = []
|
||||
pager.count = 0
|
||||
return
|
||||
}
|
||||
pager.loading = true
|
||||
try {
|
||||
const params: {
|
||||
page_no: number
|
||||
page_size: number
|
||||
diagnosis_id: number
|
||||
status?: number
|
||||
} = {
|
||||
page_no: pager.page,
|
||||
page_size: pager.size,
|
||||
diagnosis_id: Number(props.diagnosisId)
|
||||
}
|
||||
if (filterStatus.value !== '' && filterStatus.value !== undefined) {
|
||||
params.status = Number(filterStatus.value)
|
||||
}
|
||||
const res: any = await diagnosisTodoLists(params)
|
||||
pager.count = Number(res?.count ?? 0)
|
||||
pager.lists = Array.isArray(res?.lists) ? res.lists : []
|
||||
} catch {
|
||||
// request 拦截器已有错误 toast
|
||||
pager.lists = []
|
||||
pager.count = 0
|
||||
} finally {
|
||||
pager.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.diagnosisId,
|
||||
() => {
|
||||
pager.page = 1
|
||||
fetchList()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const handleFilterChange = () => {
|
||||
pager.page = 1
|
||||
fetchList()
|
||||
}
|
||||
|
||||
const statusTagType = (status: number): 'info' | 'success' | 'warning' | 'danger' => {
|
||||
switch (Number(status)) {
|
||||
case 0:
|
||||
return 'info'
|
||||
case 1:
|
||||
return 'success'
|
||||
case 2:
|
||||
return 'warning'
|
||||
case 3:
|
||||
return 'danger'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 新增 ==========
|
||||
const addDialogVisible = ref(false)
|
||||
const addSubmitting = ref(false)
|
||||
const addFormRef = ref<FormInstance>()
|
||||
const addForm = reactive({
|
||||
remindAt: '' as string | number,
|
||||
content: ''
|
||||
})
|
||||
const addRules: FormRules = {
|
||||
remindAt: [{ required: true, message: '请选择提醒时间', trigger: 'change' }],
|
||||
content: [
|
||||
{ required: true, message: '请输入提醒内容', trigger: 'blur' },
|
||||
{ max: 500, message: '内容最多 500 字', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
const disablePastDate = (date: Date) => {
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
return date.getTime() < today.getTime()
|
||||
}
|
||||
|
||||
const handleAdd = () => {
|
||||
if (!props.diagnosisId) {
|
||||
feedback.msgWarning('诊单未保存,无法添加待办')
|
||||
return
|
||||
}
|
||||
addForm.remindAt = ''
|
||||
addForm.content = ''
|
||||
addDialogVisible.value = true
|
||||
nextTick(() => addFormRef.value?.clearValidate())
|
||||
}
|
||||
|
||||
const handleAddSubmit = async () => {
|
||||
if (!addFormRef.value) return
|
||||
const valid = await addFormRef.value.validate().catch(() => false)
|
||||
if (!valid) return
|
||||
|
||||
const remindMs = Number(addForm.remindAt)
|
||||
if (!Number.isFinite(remindMs) || remindMs <= Date.now() + 30 * 1000) {
|
||||
feedback.msgWarning('提醒时间必须晚于当前时间至少 30 秒')
|
||||
return
|
||||
}
|
||||
|
||||
addSubmitting.value = true
|
||||
try {
|
||||
await diagnosisTodoAdd({
|
||||
diagnosis_id: Number(props.diagnosisId),
|
||||
content: addForm.content.trim(),
|
||||
remind_time: Math.floor(remindMs / 1000)
|
||||
})
|
||||
feedback.msgSuccess('已创建')
|
||||
addDialogVisible.value = false
|
||||
fetchList()
|
||||
} catch {
|
||||
// request 拦截器已有错误 toast
|
||||
} finally {
|
||||
addSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 取消 ==========
|
||||
const handleCancel = async (row: any) => {
|
||||
try {
|
||||
await feedback.confirm(`确认取消「${row.remind_time_text} · ${truncate(row.content, 30)}」吗?`)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await diagnosisTodoCancel({ id: Number(row.id) })
|
||||
feedback.msgSuccess('已取消')
|
||||
fetchList()
|
||||
} catch {
|
||||
// request 拦截器已有错误 toast
|
||||
}
|
||||
}
|
||||
|
||||
const truncate = (text: string, len: number) => {
|
||||
if (!text) return ''
|
||||
return text.length > len ? text.slice(0, len) + '...' : text
|
||||
}
|
||||
|
||||
defineExpose({ refresh: fetchList })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.diagnosis-todo-list {
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.hint {
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 12px;
|
||||
margin-left: 12px;
|
||||
|
||||
code {
|
||||
background: var(--el-fill-color-light);
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.todo-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination-wrap {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: var(--el-text-color-placeholder);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -594,7 +594,24 @@
|
||||
/>
|
||||
<el-empty v-else description="请先保存诊单后再添加运动打卡记录" />
|
||||
</el-tab-pane>
|
||||
|
||||
|
||||
<!-- 待办事项标签页(T5:企微推送给创建人本人) -->
|
||||
<el-tab-pane
|
||||
label="待办事项"
|
||||
name="todo"
|
||||
:disabled="!formData.id"
|
||||
lazy
|
||||
v-if="hasPermission(['tcm.diagnosisTodo/lists'])"
|
||||
>
|
||||
<diagnosis-todo-list
|
||||
v-if="formData.id"
|
||||
:diagnosis-id="Number(formData.id)"
|
||||
:patient-id="Number(formData.patient_id)"
|
||||
:patient-name="formData.patient_name"
|
||||
/>
|
||||
<el-empty v-else description="请先保存诊单后再添加待办事项" />
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 病历记录标签页(开方后自动显示) -->
|
||||
<el-tab-pane label="处方" name="bingli" :disabled="!formData.id" v-if="hasPermission(['tcm.diagnosis/chufang'])">
|
||||
<div v-if="formData.id" class="bingli-tab-content">
|
||||
@@ -705,6 +722,7 @@ import { QuestionFilled } from '@element-plus/icons-vue'
|
||||
import BloodRecordList from './components/BloodRecordList.vue'
|
||||
import DietRecordList from './components/DietRecordList.vue'
|
||||
import ExerciseRecordList from './components/ExerciseRecordList.vue'
|
||||
import DiagnosisTodoList from './components/DiagnosisTodoList.vue'
|
||||
import CaseRecordList from './components/CaseRecordList.vue'
|
||||
import CallRecordPanel from './components/CallRecordPanel.vue'
|
||||
import ImChatRecordPanel from './components/ImChatRecordPanel.vue'
|
||||
|
||||
Reference in New Issue
Block a user