!3 增加 血压血糖记录 饮食记录 运动打卡记录
Merge pull request !3 from SkinEast/zyt2026416
This commit is contained in:
@@ -91,6 +91,70 @@ export function getRecordsByPatient(params: any) {
|
|||||||
return request.get({ url: '/tcm.bloodRecord/getRecordsByPatient', params })
|
return request.get({ url: '/tcm.bloodRecord/getRecordsByPatient', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取血糖趋势图数据
|
||||||
|
export function getBloodSugarTrend(params: any) {
|
||||||
|
return request.get({ url: '/tcm.bloodRecord/getBloodSugarTrend', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 饮食记录 ==========
|
||||||
|
|
||||||
|
// 添加饮食记录
|
||||||
|
export function dietRecordAdd(params: any) {
|
||||||
|
return request.post({ url: '/tcm.dietRecord/add', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑饮食记录
|
||||||
|
export function dietRecordEdit(params: any) {
|
||||||
|
return request.post({ url: '/tcm.dietRecord/edit', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除饮食记录
|
||||||
|
export function dietRecordDelete(params: any) {
|
||||||
|
return request.post({ url: '/tcm.dietRecord/delete', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 饮食记录详情
|
||||||
|
export function dietRecordDetail(params: any) {
|
||||||
|
return request.get({ url: '/tcm.dietRecord/detail', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取患者的饮食记录列表
|
||||||
|
export function getDietRecordsByPatient(params: any) {
|
||||||
|
return request.get({ url: '/tcm.dietRecord/getRecordsByPatient', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 运动记录 ==========
|
||||||
|
|
||||||
|
// 添加运动记录
|
||||||
|
export function exerciseRecordAdd(params: any) {
|
||||||
|
return request.post({ url: '/tcm.exerciseRecord/add', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑运动记录
|
||||||
|
export function exerciseRecordEdit(params: any) {
|
||||||
|
return request.post({ url: '/tcm.exerciseRecord/edit', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除运动记录
|
||||||
|
export function exerciseRecordDelete(params: any) {
|
||||||
|
return request.post({ url: '/tcm.exerciseRecord/delete', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 运动记录详情
|
||||||
|
export function exerciseRecordDetail(params: any) {
|
||||||
|
return request.get({ url: '/tcm.exerciseRecord/detail', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取患者的运动记录列表
|
||||||
|
export function getExerciseRecordsByPatient(params: any) {
|
||||||
|
return request.get({ url: '/tcm.exerciseRecord/getRecordsByPatient', params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取运动趋势图数据
|
||||||
|
export function getExerciseTrend(params: any) {
|
||||||
|
return request.get({ url: '/tcm.exerciseRecord/getExerciseTrend', params })
|
||||||
|
}
|
||||||
|
|
||||||
// ========== 音视频通话 ==========
|
// ========== 音视频通话 ==========
|
||||||
|
|
||||||
// 获取通话签名(忽略取消令牌,避免 open + 会话切换 watch 重复请求互斥取消)
|
// 获取通话签名(忽略取消令牌,避免 open + 会话切换 watch 重复请求互斥取消)
|
||||||
|
|||||||
@@ -2,14 +2,53 @@
|
|||||||
<div class="blood-record-list">
|
<div class="blood-record-list">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<el-button type="primary" @click="handleAdd">添加记录</el-button>
|
<el-button type="primary" @click="handleAdd">添加记录</el-button>
|
||||||
|
<el-select v-model="trendDays" @change="handleTrendDaysChange" class="ml-2" style="width: 150px">
|
||||||
|
<el-option label="最近7天" :value="7" />
|
||||||
|
<el-option label="最近30天" :value="30" />
|
||||||
|
<el-option label="最近90天" :value="90" />
|
||||||
|
<el-option label="最近一年" :value="365" />
|
||||||
|
<el-option label="自定义" :value="0" />
|
||||||
|
</el-select>
|
||||||
|
<el-date-picker
|
||||||
|
v-if="trendDays === 0"
|
||||||
|
v-model="customDateRange"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
@change="loadTrendData"
|
||||||
|
class="ml-2"
|
||||||
|
style="width: 300px"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table :data="recordList" border>
|
<div class="mb-4">
|
||||||
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>血糖趋势图</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div ref="chartRef" style="width: 100%; height: 400px"></div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table :data="recordList" border style="width: 100%">
|
||||||
<el-table-column prop="record_date" label="记录日期" width="120" />
|
<el-table-column prop="record_date" label="记录日期" width="120" />
|
||||||
<el-table-column prop="record_time" label="记录时间" width="100" />
|
<el-table-column prop="record_time" label="记录时间" width="100" />
|
||||||
<el-table-column prop="blood_sugar" label="血糖(mmol/L)" width="120">
|
<el-table-column label="空腹血糖(mmol/L)" width="120">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.blood_sugar || '-' }}
|
{{ row.fasting_blood_sugar || '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="餐后2小时血糖(mmol/L)" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.postprandial_blood_sugar || '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="其他血糖(mmol/L)" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.other_blood_sugar || '-' }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="血压(mmHg)" width="150">
|
<el-table-column label="血压(mmHg)" width="150">
|
||||||
@@ -20,6 +59,8 @@
|
|||||||
<span v-else>-</span>
|
<span v-else>-</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column prop="western_medicine" label="西药" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="insulin" label="胰岛素" show-overflow-tooltip />
|
||||||
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
|
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
|
||||||
<el-table-column label="操作" width="150" fixed="right">
|
<el-table-column label="操作" width="150" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
@@ -50,14 +91,36 @@
|
|||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="血糖值">
|
<el-form-item label="空腹血糖">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-model="recordForm.blood_sugar"
|
v-model="recordForm.fasting_blood_sugar"
|
||||||
:precision="2"
|
:precision="2"
|
||||||
:step="0.1"
|
:step="0.1"
|
||||||
:min="0"
|
:min="0"
|
||||||
:max="50"
|
:max="50"
|
||||||
placeholder="请输入血糖值"
|
placeholder="请输入空腹血糖"
|
||||||
|
/>
|
||||||
|
<span class="ml-2">mmol/L</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="餐后2小时血糖">
|
||||||
|
<el-input-number
|
||||||
|
v-model="recordForm.postprandial_blood_sugar"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.1"
|
||||||
|
:min="0"
|
||||||
|
:max="50"
|
||||||
|
placeholder="请输入餐后2小时血糖"
|
||||||
|
/>
|
||||||
|
<span class="ml-2">mmol/L</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="其他血糖">
|
||||||
|
<el-input-number
|
||||||
|
v-model="recordForm.other_blood_sugar"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.1"
|
||||||
|
:min="0"
|
||||||
|
:max="50"
|
||||||
|
placeholder="请输入其他血糖"
|
||||||
/>
|
/>
|
||||||
<span class="ml-2">mmol/L</span>
|
<span class="ml-2">mmol/L</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -79,6 +142,18 @@
|
|||||||
/>
|
/>
|
||||||
<span class="ml-2">mmHg</span>
|
<span class="ml-2">mmHg</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="西药">
|
||||||
|
<el-input
|
||||||
|
v-model="recordForm.western_medicine"
|
||||||
|
placeholder="请输入西药"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="胰岛素">
|
||||||
|
<el-input
|
||||||
|
v-model="recordForm.insulin"
|
||||||
|
placeholder="请输入胰岛素"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="recordForm.remark"
|
v-model="recordForm.remark"
|
||||||
@@ -97,8 +172,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { bloodRecordAdd, bloodRecordEdit, bloodRecordDelete, getRecordsByPatient } from '@/api/tcm'
|
import { bloodRecordAdd, bloodRecordEdit, bloodRecordDelete, getRecordsByPatient, getBloodSugarTrend } from '@/api/tcm'
|
||||||
import feedback from '@/utils/feedback'
|
import feedback from '@/utils/feedback'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import { nextTick } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
diagnosisId: {
|
diagnosisId: {
|
||||||
@@ -115,6 +192,18 @@ const recordList = ref([])
|
|||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
const dialogTitle = computed(() => recordForm.value.id ? '编辑记录' : '添加记录')
|
const dialogTitle = computed(() => recordForm.value.id ? '编辑记录' : '添加记录')
|
||||||
|
const trendDays = ref(7)
|
||||||
|
const customDateRange = ref<[Date, Date] | null>(null)
|
||||||
|
const trendData = ref({
|
||||||
|
dates: [],
|
||||||
|
fasting: [],
|
||||||
|
postprandial_2h: [],
|
||||||
|
other: []
|
||||||
|
})
|
||||||
|
const chartRef = ref()
|
||||||
|
let chartInstance: any = null
|
||||||
|
let renderRetryCount = 0
|
||||||
|
const MAX_RETRY_COUNT = 5
|
||||||
|
|
||||||
const recordForm = ref({
|
const recordForm = ref({
|
||||||
id: '',
|
id: '',
|
||||||
@@ -122,12 +211,144 @@ const recordForm = ref({
|
|||||||
patient_id: props.patientId,
|
patient_id: props.patientId,
|
||||||
record_date: '',
|
record_date: '',
|
||||||
record_time: '',
|
record_time: '',
|
||||||
blood_sugar: null,
|
fasting_blood_sugar: 0,
|
||||||
systolic_pressure: null,
|
postprandial_blood_sugar: 0,
|
||||||
diastolic_pressure: null,
|
other_blood_sugar: 0,
|
||||||
|
systolic_pressure: 0,
|
||||||
|
diastolic_pressure: 0,
|
||||||
|
western_medicine: '',
|
||||||
|
insulin: '',
|
||||||
remark: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const loadTrendData = async () => {
|
||||||
|
if (!props.diagnosisId && !props.patientId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const params: any = {
|
||||||
|
diagnosis_id: props.diagnosisId,
|
||||||
|
patient_id: props.patientId
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trendDays.value === 0 && customDateRange.value) {
|
||||||
|
params.start_date = Math.floor(customDateRange.value[0].getTime() / 1000)
|
||||||
|
params.end_date = Math.floor(customDateRange.value[1].getTime() / 1000)
|
||||||
|
} else {
|
||||||
|
params.days = trendDays.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await getBloodSugarTrend(params)
|
||||||
|
trendData.value = data
|
||||||
|
renderChart()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取趋势图数据失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTrendDaysChange = () => {
|
||||||
|
if (trendDays.value !== 0) {
|
||||||
|
customDateRange.value = null
|
||||||
|
}
|
||||||
|
loadTrendData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderChart = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!chartRef.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = chartRef.value
|
||||||
|
|
||||||
|
if (container.clientWidth === 0 || container.clientHeight === 0) {
|
||||||
|
if (renderRetryCount < MAX_RETRY_COUNT) {
|
||||||
|
renderRetryCount++
|
||||||
|
setTimeout(() => renderChart(), 100)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置重试计数器
|
||||||
|
renderRetryCount = 0
|
||||||
|
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
chartInstance = echarts.init(container)
|
||||||
|
|
||||||
|
// 准备数据,确保每个日期都有对应的值
|
||||||
|
const prepareData = (dataArray: any[], dates: string[]) => {
|
||||||
|
const dataMap = new Map()
|
||||||
|
dataArray.forEach(item => {
|
||||||
|
dataMap.set(item.date, item.value)
|
||||||
|
})
|
||||||
|
return dates.map(date => dataMap.get(date) || null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fastingData = prepareData(trendData.value.fasting, trendData.value.dates)
|
||||||
|
const postprandialData = prepareData(trendData.value.postprandial_2h, trendData.value.dates)
|
||||||
|
const otherData = prepareData(trendData.value.other, trendData.value.dates)
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['空腹血糖', '餐后2小时血糖', '其他血糖']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: trendData.value.dates
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '血糖值 (mmol/L)'
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '空腹血糖',
|
||||||
|
type: 'line',
|
||||||
|
data: fastingData,
|
||||||
|
smooth: true,
|
||||||
|
connectNulls: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '餐后2小时血糖',
|
||||||
|
type: 'line',
|
||||||
|
data: postprandialData,
|
||||||
|
smooth: true,
|
||||||
|
connectNulls: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '其他血糖',
|
||||||
|
type: 'line',
|
||||||
|
data: otherData,
|
||||||
|
smooth: true,
|
||||||
|
connectNulls: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
chartInstance.setOption(option)
|
||||||
|
chartInstance.resize()
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 获取记录列表
|
// 获取记录列表
|
||||||
const getRecords = async () => {
|
const getRecords = async () => {
|
||||||
if (!props.diagnosisId && !props.patientId) {
|
if (!props.diagnosisId && !props.patientId) {
|
||||||
@@ -153,9 +374,13 @@ const handleAdd = () => {
|
|||||||
patient_id: props.patientId,
|
patient_id: props.patientId,
|
||||||
record_date: '',
|
record_date: '',
|
||||||
record_time: '',
|
record_time: '',
|
||||||
blood_sugar: null,
|
fasting_blood_sugar: 0,
|
||||||
systolic_pressure: null,
|
postprandial_blood_sugar: 0,
|
||||||
diastolic_pressure: null,
|
other_blood_sugar: 0,
|
||||||
|
systolic_pressure: 0,
|
||||||
|
diastolic_pressure: 0,
|
||||||
|
western_medicine: '',
|
||||||
|
insulin: '',
|
||||||
remark: ''
|
remark: ''
|
||||||
}
|
}
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
@@ -163,7 +388,14 @@ const handleAdd = () => {
|
|||||||
|
|
||||||
// 编辑记录
|
// 编辑记录
|
||||||
const handleEdit = (row: any) => {
|
const handleEdit = (row: any) => {
|
||||||
recordForm.value = { ...row }
|
recordForm.value = {
|
||||||
|
...row,
|
||||||
|
fasting_blood_sugar: parseFloat(row.fasting_blood_sugar) || 0,
|
||||||
|
postprandial_blood_sugar: parseFloat(row.postprandial_blood_sugar) || 0,
|
||||||
|
other_blood_sugar: parseFloat(row.other_blood_sugar) || 0,
|
||||||
|
systolic_pressure: parseInt(row.systolic_pressure) || 0,
|
||||||
|
diastolic_pressure: parseInt(row.diastolic_pressure) || 0
|
||||||
|
}
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +429,7 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
getRecords()
|
getRecords()
|
||||||
|
loadTrendData()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('提交失败:', error)
|
console.error('提交失败:', error)
|
||||||
} finally {
|
} finally {
|
||||||
@@ -205,12 +438,33 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getRecords()
|
// 延迟加载数据,确保DOM完全渲染
|
||||||
|
setTimeout(() => {
|
||||||
|
getRecords()
|
||||||
|
loadTrendData()
|
||||||
|
}, 500)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.dispose()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听props变化
|
// 监听props变化
|
||||||
watch(() => [props.diagnosisId, props.patientId], () => {
|
watch(() => [props.diagnosisId, props.patientId], () => {
|
||||||
getRecords()
|
getRecords()
|
||||||
|
loadTrendData()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听组件可见性变化(Tab切换时)
|
||||||
|
watch(() => props.diagnosisId, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
// 当组件变为可见时,延迟重新渲染图表
|
||||||
|
setTimeout(() => {
|
||||||
|
renderChart()
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,236 @@
|
|||||||
|
<template>
|
||||||
|
<div class="diet-record-list">
|
||||||
|
<div class="mb-4">
|
||||||
|
<el-button type="primary" @click="handleAdd">添加记录</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table :data="recordList" border>
|
||||||
|
<el-table-column prop="record_date" label="记录日期" width="120" />
|
||||||
|
<el-table-column label="早餐" min-width="200">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div v-if="row.breakfast_foods">{{ row.breakfast_foods }}</div>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="午餐" min-width="200">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div v-if="row.lunch_foods">{{ row.lunch_foods }}</div>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="晚餐" min-width="200">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div v-if="row.dinner_foods">{{ row.dinner_foods }}</div>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="note" label="备注" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="150" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
|
||||||
|
<el-button link type="danger" @click="handleDelete(row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="800px">
|
||||||
|
<el-form :model="recordForm" label-width="100px">
|
||||||
|
<el-form-item label="记录日期" required>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="recordForm.record_date"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-divider content-position="left">早餐</el-divider>
|
||||||
|
<el-form-item label="食物描述">
|
||||||
|
<el-input
|
||||||
|
v-model="recordForm.breakfast_foods"
|
||||||
|
type="textarea"
|
||||||
|
:rows="2"
|
||||||
|
placeholder="请输入早餐食物"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="图片">
|
||||||
|
<material-picker
|
||||||
|
v-model="recordForm.breakfast_images"
|
||||||
|
:limit="3"
|
||||||
|
type="image"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-divider content-position="left">午餐</el-divider>
|
||||||
|
<el-form-item label="食物描述">
|
||||||
|
<el-input
|
||||||
|
v-model="recordForm.lunch_foods"
|
||||||
|
type="textarea"
|
||||||
|
:rows="2"
|
||||||
|
placeholder="请输入午餐食物"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="图片">
|
||||||
|
<material-picker
|
||||||
|
v-model="recordForm.lunch_images"
|
||||||
|
:limit="3"
|
||||||
|
type="image"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-divider content-position="left">晚餐</el-divider>
|
||||||
|
<el-form-item label="食物描述">
|
||||||
|
<el-input
|
||||||
|
v-model="recordForm.dinner_foods"
|
||||||
|
type="textarea"
|
||||||
|
:rows="2"
|
||||||
|
placeholder="请输入晚餐食物"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="图片">
|
||||||
|
<material-picker
|
||||||
|
v-model="recordForm.dinner_images"
|
||||||
|
:limit="3"
|
||||||
|
type="image"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="备注">
|
||||||
|
<el-input
|
||||||
|
v-model="recordForm.note"
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="请输入备注"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit" :loading="submitting">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { dietRecordAdd, dietRecordEdit, dietRecordDelete, getDietRecordsByPatient } from '@/api/tcm'
|
||||||
|
import feedback from '@/utils/feedback'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
diagnosisId: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
patientId: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const recordList = ref([])
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const submitting = ref(false)
|
||||||
|
const dialogTitle = computed(() => recordForm.value.id ? '编辑记录' : '添加记录')
|
||||||
|
|
||||||
|
const recordForm = ref({
|
||||||
|
id: '',
|
||||||
|
diagnosis_id: props.diagnosisId,
|
||||||
|
patient_id: props.patientId,
|
||||||
|
record_date: '',
|
||||||
|
breakfast_foods: '',
|
||||||
|
breakfast_images: [],
|
||||||
|
lunch_foods: '',
|
||||||
|
lunch_images: [],
|
||||||
|
dinner_foods: '',
|
||||||
|
dinner_images: [],
|
||||||
|
note: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const getRecords = async () => {
|
||||||
|
if (!props.diagnosisId && !props.patientId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await getDietRecordsByPatient({
|
||||||
|
diagnosis_id: props.diagnosisId,
|
||||||
|
patient_id: props.patientId
|
||||||
|
})
|
||||||
|
recordList.value = data
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取记录失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
recordForm.value = {
|
||||||
|
id: '',
|
||||||
|
diagnosis_id: props.diagnosisId,
|
||||||
|
patient_id: props.patientId,
|
||||||
|
record_date: '',
|
||||||
|
breakfast_foods: '',
|
||||||
|
breakfast_images: [],
|
||||||
|
lunch_foods: '',
|
||||||
|
lunch_images: [],
|
||||||
|
dinner_foods: '',
|
||||||
|
dinner_images: [],
|
||||||
|
note: ''
|
||||||
|
}
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEdit = (row: any) => {
|
||||||
|
recordForm.value = { ...row }
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = async (row: any) => {
|
||||||
|
await feedback.confirm('确定要删除这条记录吗?')
|
||||||
|
try {
|
||||||
|
await dietRecordDelete({ id: row.id })
|
||||||
|
feedback.msgSuccess('删除成功')
|
||||||
|
getRecords()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('删除失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!recordForm.value.record_date) {
|
||||||
|
feedback.msgWarning('请选择记录日期')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
submitting.value = true
|
||||||
|
try {
|
||||||
|
if (recordForm.value.id) {
|
||||||
|
await dietRecordEdit(recordForm.value)
|
||||||
|
feedback.msgSuccess('编辑成功')
|
||||||
|
} else {
|
||||||
|
await dietRecordAdd(recordForm.value)
|
||||||
|
feedback.msgSuccess('添加成功')
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
getRecords()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error)
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getRecords()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => [props.diagnosisId, props.patientId], () => {
|
||||||
|
getRecords()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.diet-record-list {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
<template>
|
||||||
|
<div class="exercise-record-list">
|
||||||
|
<div class="mb-4">
|
||||||
|
<el-button type="primary" @click="handleAdd">添加记录</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table :data="recordList" border style="width: 100%">
|
||||||
|
<el-table-column prop="record_date" label="记录日期" width="120" />
|
||||||
|
<el-table-column prop="exercise_type" label="运动类型" width="150" />
|
||||||
|
<el-table-column prop="duration" label="运动时长" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.duration }} 分钟
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="运动强度" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ getIntensityText(row.intensity) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="note" label="备注" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="150" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
|
||||||
|
<el-button link type="danger" @click="handleDelete(row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px">
|
||||||
|
<el-form :model="recordForm" label-width="120px">
|
||||||
|
<el-form-item label="记录日期" required>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="recordForm.record_date"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="运动类型" required>
|
||||||
|
<el-select v-model="recordForm.exercise_type" placeholder="请选择运动类型" class="w-full">
|
||||||
|
<el-option label="散步" :value="'散步'" />
|
||||||
|
<el-option label="慢跑" :value="'慢跑'" />
|
||||||
|
<el-option label="游泳" :value="'游泳'" />
|
||||||
|
<el-option label="瑜伽" :value="'瑜伽'" />
|
||||||
|
<el-option label="骑自行车" :value="'骑自行车'" />
|
||||||
|
<el-option label="打太极拳" :value="'打太极拳'" />
|
||||||
|
<el-option label="其他" :value="'其他'" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="运动时长(分钟)" required>
|
||||||
|
<el-input-number
|
||||||
|
v-model="recordForm.duration"
|
||||||
|
:min="0"
|
||||||
|
:max="300"
|
||||||
|
placeholder="请输入运动时长"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="运动强度" required>
|
||||||
|
<el-select v-model="recordForm.intensity" placeholder="请选择运动强度" class="w-full">
|
||||||
|
<el-option label="低强度" :value="1" />
|
||||||
|
<el-option label="中强度" :value="2" />
|
||||||
|
<el-option label="高强度" :value="3" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="运动图片">
|
||||||
|
<material-picker
|
||||||
|
v-model="recordForm.images"
|
||||||
|
:limit="3"
|
||||||
|
type="image"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注">
|
||||||
|
<el-input
|
||||||
|
v-model="recordForm.note"
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="请输入备注"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit" :loading="submitting">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { exerciseRecordAdd, exerciseRecordEdit, exerciseRecordDelete, getExerciseRecordsByPatient } from '@/api/tcm'
|
||||||
|
import feedback from '@/utils/feedback'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
diagnosisId: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
patientId: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const recordList = ref([])
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const submitting = ref(false)
|
||||||
|
const dialogTitle = computed(() => recordForm.value.id ? '编辑记录' : '添加记录')
|
||||||
|
|
||||||
|
const recordForm = ref({
|
||||||
|
id: '',
|
||||||
|
diagnosis_id: props.diagnosisId,
|
||||||
|
patient_id: props.patientId,
|
||||||
|
record_date: '',
|
||||||
|
exercise_type: '',
|
||||||
|
duration: 0,
|
||||||
|
intensity: 1,
|
||||||
|
images: [],
|
||||||
|
note: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const intensityOptions = [
|
||||||
|
{ label: '低强度', value: 1 },
|
||||||
|
{ label: '中强度', value: 2 },
|
||||||
|
{ label: '高强度', value: 3 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const getIntensityText = (intensity: number) => {
|
||||||
|
const option = intensityOptions.find(opt => opt.value === intensity)
|
||||||
|
return option ? option.label : '未知'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRecords = async () => {
|
||||||
|
if (!props.diagnosisId && !props.patientId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await getExerciseRecordsByPatient({
|
||||||
|
diagnosis_id: props.diagnosisId,
|
||||||
|
patient_id: props.patientId
|
||||||
|
})
|
||||||
|
recordList.value = data
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取记录失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
recordForm.value = {
|
||||||
|
id: '',
|
||||||
|
diagnosis_id: props.diagnosisId,
|
||||||
|
patient_id: props.patientId,
|
||||||
|
record_date: '',
|
||||||
|
exercise_type: '',
|
||||||
|
duration: 0,
|
||||||
|
intensity: 1,
|
||||||
|
images: [],
|
||||||
|
note: ''
|
||||||
|
}
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEdit = (row: any) => {
|
||||||
|
recordForm.value = { ...row }
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = async (row: any) => {
|
||||||
|
await feedback.confirm('确定要删除这条记录吗?')
|
||||||
|
try {
|
||||||
|
await exerciseRecordDelete({ id: row.id })
|
||||||
|
feedback.msgSuccess('删除成功')
|
||||||
|
getRecords()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('删除失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!recordForm.value.record_date) {
|
||||||
|
feedback.msgWarning('请选择记录日期')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!recordForm.value.exercise_type) {
|
||||||
|
feedback.msgWarning('请选择运动类型')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!recordForm.value.duration) {
|
||||||
|
feedback.msgWarning('请输入运动时长')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
submitting.value = true
|
||||||
|
try {
|
||||||
|
if (recordForm.value.id) {
|
||||||
|
await exerciseRecordEdit(recordForm.value)
|
||||||
|
feedback.msgSuccess('编辑成功')
|
||||||
|
} else {
|
||||||
|
await exerciseRecordAdd(recordForm.value)
|
||||||
|
feedback.msgSuccess('添加成功')
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
getRecords()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error)
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getRecords()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => [props.diagnosisId, props.patientId], () => {
|
||||||
|
getRecords()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.exercise-record-list {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -513,6 +513,27 @@
|
|||||||
/>
|
/>
|
||||||
<el-empty v-else description="请先保存诊单后再添加血糖血压记录" />
|
<el-empty v-else description="请先保存诊单后再添加血糖血压记录" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<!-- 饮食记录标签页 -->
|
||||||
|
<el-tab-pane label="饮食记录" name="diet" :disabled="!formData.id">
|
||||||
|
<diet-record-list
|
||||||
|
v-if="formData.id"
|
||||||
|
:diagnosis-id="Number(formData.id)"
|
||||||
|
:patient-id="Number(formData.patient_id)"
|
||||||
|
/>
|
||||||
|
<el-empty v-else description="请先保存诊单后再添加饮食记录" />
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<!-- 运动打卡记录标签页 -->
|
||||||
|
<el-tab-pane label="运动打卡记录" name="exercise" :disabled="!formData.id">
|
||||||
|
<exercise-record-list
|
||||||
|
v-if="formData.id"
|
||||||
|
:diagnosis-id="Number(formData.id)"
|
||||||
|
:patient-id="Number(formData.patient_id)"
|
||||||
|
/>
|
||||||
|
<el-empty v-else description="请先保存诊单后再添加运动打卡记录" />
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
<!-- 病历记录标签页(开方后自动显示) -->
|
<!-- 病历记录标签页(开方后自动显示) -->
|
||||||
<el-tab-pane label="处方" name="bingli" :disabled="!formData.id" v-if="hasPermission(['tcm.diagnosis/chufang'])">
|
<el-tab-pane label="处方" name="bingli" :disabled="!formData.id" v-if="hasPermission(['tcm.diagnosis/chufang'])">
|
||||||
<div v-if="formData.id" class="bingli-tab-content">
|
<div v-if="formData.id" class="bingli-tab-content">
|
||||||
@@ -650,6 +671,8 @@ import useAppStore from '@/stores/modules/app'
|
|||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { QuestionFilled } from '@element-plus/icons-vue'
|
import { QuestionFilled } from '@element-plus/icons-vue'
|
||||||
import BloodRecordList from './components/BloodRecordList.vue'
|
import BloodRecordList from './components/BloodRecordList.vue'
|
||||||
|
import DietRecordList from './components/DietRecordList.vue'
|
||||||
|
import ExerciseRecordList from './components/ExerciseRecordList.vue'
|
||||||
import CaseRecordList from './components/CaseRecordList.vue'
|
import CaseRecordList from './components/CaseRecordList.vue'
|
||||||
import CallRecordPanel from './components/CallRecordPanel.vue'
|
import CallRecordPanel from './components/CallRecordPanel.vue'
|
||||||
import ImChatRecordPanel from './components/ImChatRecordPanel.vue'
|
import ImChatRecordPanel from './components/ImChatRecordPanel.vue'
|
||||||
|
|||||||
@@ -78,4 +78,15 @@ class BloodRecordController extends BaseAdminController
|
|||||||
$result = BloodRecordLogic::getRecordsByPatient($params);
|
$result = BloodRecordLogic::getRecordsByPatient($params);
|
||||||
return $this->data($result);
|
return $this->data($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notes 获取血糖趋势图数据
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function getBloodSugarTrend()
|
||||||
|
{
|
||||||
|
$params = $this->request->get();
|
||||||
|
$result = BloodRecordLogic::getBloodSugarTrend($params);
|
||||||
|
return $this->data($result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\adminapi\controller\tcm;
|
||||||
|
|
||||||
|
use app\adminapi\controller\BaseAdminController;
|
||||||
|
use app\adminapi\logic\tcm\DietRecordLogic;
|
||||||
|
|
||||||
|
class DietRecordController extends BaseAdminController
|
||||||
|
{
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
$params = $this->request->post();
|
||||||
|
$result = DietRecordLogic::add($params);
|
||||||
|
if ($result) {
|
||||||
|
return $this->success('添加成功', [], 1, 1);
|
||||||
|
}
|
||||||
|
return $this->fail(DietRecordLogic::getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit()
|
||||||
|
{
|
||||||
|
$params = $this->request->post();
|
||||||
|
$result = DietRecordLogic::edit($params);
|
||||||
|
if ($result) {
|
||||||
|
return $this->success('编辑成功', [], 1, 1);
|
||||||
|
}
|
||||||
|
return $this->fail(DietRecordLogic::getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$params = $this->request->post();
|
||||||
|
$result = DietRecordLogic::delete($params);
|
||||||
|
if ($result) {
|
||||||
|
return $this->success('删除成功', [], 1, 1);
|
||||||
|
}
|
||||||
|
return $this->fail(DietRecordLogic::getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detail()
|
||||||
|
{
|
||||||
|
$params = $this->request->get();
|
||||||
|
$result = DietRecordLogic::detail($params);
|
||||||
|
return $this->data($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRecordsByPatient()
|
||||||
|
{
|
||||||
|
$params = $this->request->get();
|
||||||
|
$result = DietRecordLogic::getRecordsByPatient($params);
|
||||||
|
return $this->data($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\adminapi\controller\tcm;
|
||||||
|
|
||||||
|
use app\adminapi\controller\BaseAdminController;
|
||||||
|
use app\adminapi\logic\tcm\ExerciseRecordLogic;
|
||||||
|
|
||||||
|
class ExerciseRecordController extends BaseAdminController
|
||||||
|
{
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
$params = $this->request->post();
|
||||||
|
$result = ExerciseRecordLogic::add($params);
|
||||||
|
if ($result) {
|
||||||
|
return $this->success('添加成功', [], 1, 1);
|
||||||
|
}
|
||||||
|
return $this->fail(ExerciseRecordLogic::getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit()
|
||||||
|
{
|
||||||
|
$params = $this->request->post();
|
||||||
|
$result = ExerciseRecordLogic::edit($params);
|
||||||
|
if ($result) {
|
||||||
|
return $this->success('编辑成功', [], 1, 1);
|
||||||
|
}
|
||||||
|
return $this->fail(ExerciseRecordLogic::getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$params = $this->request->post();
|
||||||
|
$result = ExerciseRecordLogic::delete($params);
|
||||||
|
if ($result) {
|
||||||
|
return $this->success('删除成功', [], 1, 1);
|
||||||
|
}
|
||||||
|
return $this->fail(ExerciseRecordLogic::getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detail()
|
||||||
|
{
|
||||||
|
$params = $this->request->get();
|
||||||
|
$result = ExerciseRecordLogic::detail($params);
|
||||||
|
return $this->data($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRecordsByPatient()
|
||||||
|
{
|
||||||
|
$params = $this->request->get();
|
||||||
|
$result = ExerciseRecordLogic::getRecordsByPatient($params);
|
||||||
|
return $this->data($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExerciseTrend()
|
||||||
|
{
|
||||||
|
$params = $this->request->get();
|
||||||
|
$result = ExerciseRecordLogic::getExerciseTrend($params);
|
||||||
|
return $this->data($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -96,6 +96,50 @@ class BloodRecordLogic extends BaseLogic
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function getRecordsByPatient(array $params): array
|
public static function getRecordsByPatient(array $params): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$where = [];
|
||||||
|
|
||||||
|
if (isset($params['diagnosis_id'])) {
|
||||||
|
$where[] = ['diagnosis_id', '=', $params['diagnosis_id']];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['patient_id'])) {
|
||||||
|
$where[] = ['patient_id', '=', $params['patient_id']];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有诊断ID或患者ID,返回空数组
|
||||||
|
if (empty($where)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$records = BloodRecord::where($where)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->order('record_date', 'desc')
|
||||||
|
->order('record_time', 'desc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// 格式化日期
|
||||||
|
foreach ($records as &$record) {
|
||||||
|
if (!empty($record['record_date'])) {
|
||||||
|
$record['record_date'] = date('Y-m-d', $record['record_date']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $records;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notes 获取血糖趋势图数据
|
||||||
|
* @param array $params
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getBloodSugarTrend(array $params): array
|
||||||
{
|
{
|
||||||
$where = [];
|
$where = [];
|
||||||
|
|
||||||
@@ -107,20 +151,93 @@ class BloodRecordLogic extends BaseLogic
|
|||||||
$where[] = ['patient_id', '=', $params['patient_id']];
|
$where[] = ['patient_id', '=', $params['patient_id']];
|
||||||
}
|
}
|
||||||
|
|
||||||
$records = BloodRecord::where($where)
|
// 检查是否使用自定义日期范围
|
||||||
->where('delete_time', null)
|
if (isset($params['start_date']) && isset($params['end_date'])) {
|
||||||
->order('record_date', 'desc')
|
$startDate = intval($params['start_date']);
|
||||||
->order('record_time', 'desc')
|
$endDate = intval($params['end_date']);
|
||||||
->select()
|
} else {
|
||||||
->toArray();
|
$days = isset($params['days']) ? intval($params['days']) : 7;
|
||||||
|
$startDate = strtotime("-{$days} days");
|
||||||
|
$endDate = time();
|
||||||
|
}
|
||||||
|
|
||||||
// 格式化日期
|
$query = BloodRecord::where($where)
|
||||||
foreach ($records as &$record) {
|
->where('delete_time', null)
|
||||||
if (!empty($record['record_date'])) {
|
->where('record_date', '>=', $startDate)
|
||||||
$record['record_date'] = date('Y-m-d', $record['record_date']);
|
->order('record_date', 'asc');
|
||||||
|
|
||||||
|
// 如果有结束日期,添加结束日期条件
|
||||||
|
if (isset($endDate)) {
|
||||||
|
$query->where('record_date', '<=', $endDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
$records = $query->select()->toArray();
|
||||||
|
|
||||||
|
// 使用Map来存储每天的数据,确保同一天的多条记录能够正确处理
|
||||||
|
$dateMap = [];
|
||||||
|
|
||||||
|
foreach ($records as $record) {
|
||||||
|
$date = date('Y-m-d', $record['record_date']);
|
||||||
|
|
||||||
|
if (!isset($dateMap[$date])) {
|
||||||
|
$dateMap[$date] = [
|
||||||
|
'fasting' => null,
|
||||||
|
'postprandial_2h' => null,
|
||||||
|
'other' => null
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 空腹血糖(取第一个非空值)
|
||||||
|
if (isset($record['fasting_blood_sugar']) && $record['fasting_blood_sugar'] > 0 && $dateMap[$date]['fasting'] === null) {
|
||||||
|
$dateMap[$date]['fasting'] = $record['fasting_blood_sugar'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 餐后2小时血糖(取第一个非空值)
|
||||||
|
if (isset($record['postprandial_blood_sugar']) && $record['postprandial_blood_sugar'] > 0 && $dateMap[$date]['postprandial_2h'] === null) {
|
||||||
|
$dateMap[$date]['postprandial_2h'] = $record['postprandial_blood_sugar'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他血糖(取第一个非空值)
|
||||||
|
if (isset($record['other_blood_sugar']) && $record['other_blood_sugar'] > 0 && $dateMap[$date]['other'] === null) {
|
||||||
|
$dateMap[$date]['other'] = $record['other_blood_sugar'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $records;
|
// 按日期排序
|
||||||
|
ksort($dateMap);
|
||||||
|
|
||||||
|
$trend = [
|
||||||
|
'dates' => [],
|
||||||
|
'fasting' => [],
|
||||||
|
'postprandial_2h' => [],
|
||||||
|
'other' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($dateMap as $date => $values) {
|
||||||
|
$trend['dates'][] = $date;
|
||||||
|
|
||||||
|
if ($values['fasting'] !== null) {
|
||||||
|
$trend['fasting'][] = [
|
||||||
|
'date' => $date,
|
||||||
|
'value' => $values['fasting']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($values['postprandial_2h'] !== null) {
|
||||||
|
$trend['postprandial_2h'][] = [
|
||||||
|
'date' => $date,
|
||||||
|
'value' => $values['postprandial_2h']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($values['other'] !== null) {
|
||||||
|
$trend['other'][] = [
|
||||||
|
'date' => $date,
|
||||||
|
'value' => $values['other']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $trend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\adminapi\logic\tcm;
|
||||||
|
|
||||||
|
use app\common\logic\BaseLogic;
|
||||||
|
use app\common\model\tcm\DietRecord;
|
||||||
|
|
||||||
|
class DietRecordLogic extends BaseLogic
|
||||||
|
{
|
||||||
|
public static function add(array $params): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (isset($params['record_date'])) {
|
||||||
|
$params['record_date'] = strtotime($params['record_date']);
|
||||||
|
}
|
||||||
|
|
||||||
|
DietRecord::create($params);
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function edit(array $params): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (isset($params['record_date'])) {
|
||||||
|
$params['record_date'] = strtotime($params['record_date']);
|
||||||
|
}
|
||||||
|
|
||||||
|
DietRecord::update($params);
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function delete(array $params): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
DietRecord::destroy($params['id']);
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function detail($params): array
|
||||||
|
{
|
||||||
|
$record = DietRecord::findOrEmpty($params['id'])->toArray();
|
||||||
|
|
||||||
|
if (!empty($record['record_date'])) {
|
||||||
|
$record['record_date'] = date('Y-m-d', $record['record_date']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $record;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRecordsByPatient(array $params): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$where = [];
|
||||||
|
|
||||||
|
if (isset($params['diagnosis_id'])) {
|
||||||
|
$where[] = ['diagnosis_id', '=', $params['diagnosis_id']];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['patient_id'])) {
|
||||||
|
$where[] = ['patient_id', '=', $params['patient_id']];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有诊断ID或患者ID,返回空数组
|
||||||
|
if (empty($where)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$records = DietRecord::where($where)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->order('record_date', 'desc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
foreach ($records as &$record) {
|
||||||
|
if (!empty($record['record_date'])) {
|
||||||
|
$record['record_date'] = date('Y-m-d', $record['record_date']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $records;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\adminapi\logic\tcm;
|
||||||
|
|
||||||
|
use app\common\logic\BaseLogic;
|
||||||
|
use app\common\model\tcm\ExerciseRecord;
|
||||||
|
|
||||||
|
class ExerciseRecordLogic extends BaseLogic
|
||||||
|
{
|
||||||
|
public static function add(array $params): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (isset($params['record_date'])) {
|
||||||
|
$params['record_date'] = strtotime($params['record_date']);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExerciseRecord::create($params);
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function edit(array $params): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (isset($params['record_date'])) {
|
||||||
|
$params['record_date'] = strtotime($params['record_date']);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExerciseRecord::update($params);
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function delete(array $params): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ExerciseRecord::destroy($params['id']);
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function detail($params): array
|
||||||
|
{
|
||||||
|
$record = ExerciseRecord::findOrEmpty($params['id'])->toArray();
|
||||||
|
|
||||||
|
if (!empty($record['record_date'])) {
|
||||||
|
$record['record_date'] = date('Y-m-d', $record['record_date']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $record;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRecordsByPatient(array $params): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$where = [];
|
||||||
|
|
||||||
|
if (isset($params['diagnosis_id'])) {
|
||||||
|
$where[] = ['diagnosis_id', '=', $params['diagnosis_id']];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['patient_id'])) {
|
||||||
|
$where[] = ['patient_id', '=', $params['patient_id']];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有诊断ID或患者ID,返回空数组
|
||||||
|
if (empty($where)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$records = ExerciseRecord::where($where)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->order('record_date', 'desc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
foreach ($records as &$record) {
|
||||||
|
if (!empty($record['record_date'])) {
|
||||||
|
$record['record_date'] = date('Y-m-d', $record['record_date']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $records;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getExerciseTrend(array $params): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$where = [];
|
||||||
|
|
||||||
|
if (isset($params['diagnosis_id'])) {
|
||||||
|
$where[] = ['diagnosis_id', '=', $params['diagnosis_id']];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['patient_id'])) {
|
||||||
|
$where[] = ['patient_id', '=', $params['patient_id']];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有诊断ID或患者ID,返回空数组
|
||||||
|
if (empty($where)) {
|
||||||
|
return [
|
||||||
|
'dates' => [],
|
||||||
|
'duration' => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理日期范围
|
||||||
|
if (isset($params['start_date']) && isset($params['end_date'])) {
|
||||||
|
$startDate = strtotime($params['start_date']);
|
||||||
|
$endDate = strtotime($params['end_date'] . ' 23:59:59');
|
||||||
|
} else {
|
||||||
|
$days = isset($params['days']) ? intval($params['days']) : 7;
|
||||||
|
$startDate = strtotime("-{$days} days");
|
||||||
|
$endDate = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
$records = ExerciseRecord::where($where)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->where('record_date', '>=', $startDate)
|
||||||
|
->where('record_date', '<=', $endDate)
|
||||||
|
->order('record_date', 'asc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
$trend = [
|
||||||
|
'dates' => [],
|
||||||
|
'duration' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($records as $record) {
|
||||||
|
$date = date('Y-m-d', $record['record_date']);
|
||||||
|
|
||||||
|
if (!in_array($date, $trend['dates'])) {
|
||||||
|
$trend['dates'][] = $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
$trend['duration'][] = [
|
||||||
|
'date' => $date,
|
||||||
|
'value' => $record['duration']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $trend;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::setError($e->getMessage());
|
||||||
|
return [
|
||||||
|
'dates' => [],
|
||||||
|
'duration' => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\model\tcm;
|
||||||
|
|
||||||
|
use app\common\model\BaseModel;
|
||||||
|
|
||||||
|
class DietRecord extends BaseModel
|
||||||
|
{
|
||||||
|
protected $name = 'patient_diet_record';
|
||||||
|
|
||||||
|
protected $autoWriteTimestamp = true;
|
||||||
|
protected $createTime = 'create_time';
|
||||||
|
protected $updateTime = 'update_time';
|
||||||
|
protected $deleteTime = 'delete_time';
|
||||||
|
|
||||||
|
protected $dateFormat = false;
|
||||||
|
|
||||||
|
public function getRecordDateTextAttr($value, $data)
|
||||||
|
{
|
||||||
|
return !empty($data['record_date']) ? date('Y-m-d', $data['record_date']) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBreakfastImagesAttr($value)
|
||||||
|
{
|
||||||
|
return $value ? json_decode($value, true) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBreakfastImagesAttr($value)
|
||||||
|
{
|
||||||
|
return is_array($value) ? json_encode($value) : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLunchImagesAttr($value)
|
||||||
|
{
|
||||||
|
return $value ? json_decode($value, true) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLunchImagesAttr($value)
|
||||||
|
{
|
||||||
|
return is_array($value) ? json_encode($value) : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDinnerImagesAttr($value)
|
||||||
|
{
|
||||||
|
return $value ? json_decode($value, true) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDinnerImagesAttr($value)
|
||||||
|
{
|
||||||
|
return is_array($value) ? json_encode($value) : $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\model\tcm;
|
||||||
|
|
||||||
|
use app\common\model\BaseModel;
|
||||||
|
|
||||||
|
class ExerciseRecord extends BaseModel
|
||||||
|
{
|
||||||
|
protected $name = 'patient_exercise_record';
|
||||||
|
|
||||||
|
protected $autoWriteTimestamp = true;
|
||||||
|
protected $createTime = 'create_time';
|
||||||
|
protected $updateTime = 'update_time';
|
||||||
|
protected $deleteTime = 'delete_time';
|
||||||
|
|
||||||
|
protected $dateFormat = false;
|
||||||
|
|
||||||
|
public function getRecordDateTextAttr($value, $data)
|
||||||
|
{
|
||||||
|
return !empty($data['record_date']) ? date('Y-m-d', $data['record_date']) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIntensityTextAttr($value, $data)
|
||||||
|
{
|
||||||
|
$intensities = [
|
||||||
|
1 => '低强度',
|
||||||
|
2 => '中强度',
|
||||||
|
3 => '高强度'
|
||||||
|
];
|
||||||
|
return $intensities[$data['intensity']] ?? '未知';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImagesAttr($value)
|
||||||
|
{
|
||||||
|
return $value ? json_decode($value, true) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setImagesAttr($value)
|
||||||
|
{
|
||||||
|
return is_array($value) ? json_encode($value) : $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user