Files
onboard/resources/js/Pages/Report/Components/ReportSectionItem.vue
brusnitsyn 2805e5e4bc * исправление подсчета операций пациентов
* поправил поле выбора даты
* добавил индикатор в контроле
* окно выбора пользователя для сводной
* привязка окна для ввода причины контроля
* добавил привязку историй пациентов для просмотра статистики по дням
* поправил фиксацию фио ответственного, убрал при диапазоне
* отключение ролей адм и зав от реплики
2026-01-30 17:26:16 +09:00

305 lines
7.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import {NIcon, NText, NDataTable, NButton, NBadge, NTabs, NTabPane} from "naive-ui";
import {useReportStore} from "../../../Stores/report.js";
import {computed, h, onMounted, ref, watch} from "vue";
import { VueDraggableNext } from 'vue-draggable-next'
import {storeToRefs} from "pinia";
import {TbGripVertical, TbEye} from "vue-icons-plus/tb";
import MoveModalComment from "./MoveModalComment.vue";
const props = defineProps({
mode: {
type: String,
default: 'fillable' // 'fillable', 'readonly'
},
keys: {
type: Array,
default: ['num', 'fullname', 'age', 'birth_date', 'mkb.ds']
},
status: {
type: String,
default: null // 'plan'
},
isRemovable: {
type: Boolean,
default: false
},
isDraggable: {
type: Boolean,
default: false
},
accentIds: {
type: Array,
default: []
},
})
const isFillableMode = computed(() => props.mode.toLowerCase() === 'fillable')
const isReadonlyMode = computed(() => props.mode.toLowerCase() === 'readonly')
const tableRef = ref()
const emit = defineEmits(['item-dragged', 'item-dropped'])
const reportStore = useReportStore()
const {patientsData} = storeToRefs(reportStore)
// Получаем базовые колонки
const baseColumns = reportStore.getColumnsByKey(props.keys)
const data = ref([])
const isLoading = ref(true)
const showMoveModal = ref(false)
const latestDropItem = ref(null)
const activePatient = ref(null)
// Добавляем drag колонку если режим fillable
const columns = computed(() => {
// if (!isFillableMode.value) return baseColumns
const newColumns = []
const dragColumn = {
title: '',
key: 'drag',
width: 40,
render: (row) => h(
'div',
{
style: {
cursor: 'grab',
textAlign: 'center',
userSelect: 'none'
}
},
[
h(NIcon, {
depth: '2',
component: TbGripVertical
}, [])
]
)
}
const removeColumn = {
title: '',
key: 'remove',
render: (row) => h(
NButton,
{
text: true,
onClick: () => {
axios.post('/api/report/observation/remove', {
id: row.id
}).then(async () => {
await fetchPatients()
})
}
},
[
'Снять с наблюдения'
]
)
}
const expandColumn = {
title: '',
width: '30',
render: (rowData) => {
return h(
NIcon,
{
onClick: () => {
latestDropItem.value = rowData
showMoveModal.value = true
}
},
{
default: h(TbEye)
}
)
}
}
const fillableColumn = {
title: '',
key: 'fillable',
width: '20',
render: (row) => h(
NBadge,
{
dot: true,
color: (row.comment && row.comment.trim()) ? '#7fe7c4' : '#e88080'
}
)
}
if (props.status === 'observation') {
newColumns.push(expandColumn)
newColumns.push(fillableColumn)
}
if (props.isDraggable) newColumns.push(dragColumn)
newColumns.push(...baseColumns)
if (props.isRemovable) newColumns.push(removeColumn)
if (props.status === 'emergency' || props.status === 'plan') {
const operationColumn = {
title: 'Операции',
key: 'operations',
render: (row) => row.operations.length ?
h(
NText,
{},
[
row.operations.map(itm => {
return `${itm.code}; `
})
]
) : h('div', {}, '-'),
ellipsis: {
tooltip: true
}
}
newColumns.push(operationColumn)
}
if (props.status === 'outcome') {
const typeColumn = {
title: 'Причина',
key: 'outcome_type',
ellipsis: {
tooltip: true
}
}
newColumns.push(typeColumn)
}
return newColumns
})
const handleDragStart = (e, row) => {
// Устанавливаем данные о перетаскиваемом элементе
e.dataTransfer.setData('application/json', JSON.stringify({
row: row,
fromStatus: props.status
}))
e.dataTransfer.effectAllowed = 'copy'
const rowElement = e.target
// Эмитим событие для родителя
emit('item-dragged', { row, fromStatus: props.status })
// Добавляем класс для визуальной обратной связи
e.target.classList.add('dragging')
}
const handleDragEnd = (e) => {
if (e.target) {
e.target.classList.remove('dragging')
}
}
const handleDragOver = (e) => {
e.preventDefault()
}
const handleDrop = (e) => {
e.preventDefault()
try {
const dragData = JSON.parse(e.dataTransfer.getData('application/json'))
// Эмитим событие для родителя
emit('item-dropped', {
item: dragData.row,
fromStatus: dragData.fromStatus,
toStatus: props.status
})
latestDropItem.value = dragData.row
showMoveModal.value = true
} catch (error) {
console.error('Drop error:', error)
}
}
const fetchPatients = async () => {
isLoading.value = true
const data = {
status: props.status,
startAt: reportStore.timestampCurrentRange[0],
endAt: reportStore.timestampCurrentRange[1],
}
await axios.post('/api/mis/patients', data).then((res) => {
patientsData.value[props.status] = res.data
}).finally(() => {
isLoading.value = false
})
}
function rowProps(row) {
const style = []
const classes = []
style.push(props.isDraggable ? 'cursor: grab;' : 'cursor: arrow;')
if (props.accentIds.length) {
console.log(props.accentIds.includes(row.id))
if (props.accentIds.includes(row.id)) {
style.push('--n-merged-td-color: #047857')
}
}
return {
draggable: props.isDraggable,
style: style,
onDragstart: (e) => {
if (!props.isDraggable) return
handleDragStart(e, row)
},
onDragend: (e) => {
if (!props.isDraggable) return
handleDragEnd(e)
},
onDragover: (e) => {
if (!props.isDraggable) return
handleDragOver(e)
},
onDrop: (e) => {
if (!props.isDraggable) return
handleDrop(e)
}
}
}
onMounted(async () => {
await fetchPatients()
})
</script>
<template>
<NDataTable :columns="columns"
ref="tableRef"
:data="patientsData[status]"
size="small"
@drop="handleDrop"
@dragover="handleDragOver"
:loading="isLoading"
max-height="200"
min-height="200"
:row-props="rowProps"
:row-key="(row) => row.id"
class="text-sm!">
</NDataTable>
<MoveModalComment v-model:show="showMoveModal" :patient-id="latestDropItem?.id" />
</template>
<style scoped>
:deep(.n-data-table-th),
:deep(.n-data-table-td) {
white-space: nowrap !important;
font-size: var(--n-font-size);
}
</style>