Merge branch 'master' into tongji-99
This commit is contained in:
Generated
+9731
File diff suppressed because it is too large
Load Diff
@@ -190,6 +190,18 @@
|
|||||||
<span v-if="formData.prescription_type !== '浓缩水丸' && formData.prescription_type !== '饮片'" class="ml-2">{{ formData.dosage_unit }}</span>
|
<span v-if="formData.prescription_type !== '浓缩水丸' && formData.prescription_type !== '饮片'" class="ml-2">{{ formData.dosage_unit }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
|
<el-col v-if="formData.prescription_type === '浓缩水丸'" :span="8">
|
||||||
|
<el-form-item label=" " prop="dosage_bag_count" label-width="12px">
|
||||||
|
<el-select v-model="formData.dosage_bag_count" placeholder="请选择袋数" class="!w-[120px]">
|
||||||
|
<el-option label="1袋" :value="1" />
|
||||||
|
<el-option label="2袋" :value="2" />
|
||||||
|
<el-option label="3袋" :value="3" />
|
||||||
|
<el-option label="4袋" :value="4" />
|
||||||
|
<el-option label="5袋" :value="5" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<!-- 饮片每贴出包数 -->
|
<!-- 饮片每贴出包数 -->
|
||||||
<el-col v-if="formData.prescription_type === '饮片'" :span="8">
|
<el-col v-if="formData.prescription_type === '饮片'" :span="8">
|
||||||
@@ -676,6 +688,7 @@ interface PrescriptionForm {
|
|||||||
prescription_type: string
|
prescription_type: string
|
||||||
dosage_amount: number | undefined // 用量数值
|
dosage_amount: number | undefined // 用量数值
|
||||||
dosage_unit: string // 用量单位 (g 或 ml)
|
dosage_unit: string // 用量单位 (g 或 ml)
|
||||||
|
dosage_bag_count: number // 用量袋数(浓缩水丸,1-5袋)
|
||||||
need_decoction: boolean // 是否代煎(仅饮片)
|
need_decoction: boolean // 是否代煎(仅饮片)
|
||||||
bags_per_dose: number // 每贴出包数(仅饮片,1-9包)
|
bags_per_dose: number // 每贴出包数(仅饮片,1-9包)
|
||||||
patient_name: string
|
patient_name: string
|
||||||
@@ -764,6 +777,7 @@ const formData = reactive<PrescriptionForm>({
|
|||||||
prescription_type: '浓缩水丸',
|
prescription_type: '浓缩水丸',
|
||||||
dosage_amount: 10,
|
dosage_amount: 10,
|
||||||
dosage_unit: 'g',
|
dosage_unit: 'g',
|
||||||
|
dosage_bag_count: 1,
|
||||||
need_decoction: false,
|
need_decoction: false,
|
||||||
bags_per_dose: 1,
|
bags_per_dose: 1,
|
||||||
patient_name: '',
|
patient_name: '',
|
||||||
@@ -954,6 +968,7 @@ const open = async (data: any, options?: { templateId?: number; stationName?: st
|
|||||||
formData.prescription_type = '浓缩水丸'
|
formData.prescription_type = '浓缩水丸'
|
||||||
formData.dosage_unit = 'g'
|
formData.dosage_unit = 'g'
|
||||||
formData.dosage_amount = 10
|
formData.dosage_amount = 10
|
||||||
|
formData.dosage_bag_count = 1
|
||||||
formData.patient_name = data.patient_name || diagnosis.patient_name || ''
|
formData.patient_name = data.patient_name || diagnosis.patient_name || ''
|
||||||
formData.gender = data.patient_gender ?? diagnosis.gender ?? 0
|
formData.gender = data.patient_gender ?? diagnosis.gender ?? 0
|
||||||
formData.gender_desc = formData.gender === 1 ? '男' : '女'
|
formData.gender_desc = formData.gender === 1 ? '男' : '女'
|
||||||
@@ -980,6 +995,8 @@ const open = async (data: any, options?: { templateId?: number; stationName?: st
|
|||||||
formData.doctor_name = userStore.userInfo?.name || ''
|
formData.doctor_name = userStore.userInfo?.name || ''
|
||||||
formData.doctor_signature = ''
|
formData.doctor_signature = ''
|
||||||
formData.is_shared = 0
|
formData.is_shared = 0
|
||||||
|
formData.need_decoction = false
|
||||||
|
formData.bags_per_dose = 1
|
||||||
|
|
||||||
savedPrescription.value = null
|
savedPrescription.value = null
|
||||||
visible.value = true
|
visible.value = true
|
||||||
@@ -1206,16 +1223,19 @@ watch(() => formData.prescription_type, (newType) => {
|
|||||||
if (newType === '浓缩水丸') {
|
if (newType === '浓缩水丸') {
|
||||||
formData.dosage_unit = 'g'
|
formData.dosage_unit = 'g'
|
||||||
formData.dosage_amount = 10
|
formData.dosage_amount = 10
|
||||||
|
formData.dosage_bag_count = 1
|
||||||
formData.need_decoction = false
|
formData.need_decoction = false
|
||||||
formData.bags_per_dose = 1
|
formData.bags_per_dose = 1
|
||||||
} else if (newType === '饮片') {
|
} else if (newType === '饮片') {
|
||||||
formData.dosage_unit = 'ml'
|
formData.dosage_unit = 'ml'
|
||||||
formData.dosage_amount = 50
|
formData.dosage_amount = 50
|
||||||
|
formData.dosage_bag_count = 1
|
||||||
formData.bags_per_dose = 1
|
formData.bags_per_dose = 1
|
||||||
// need_decoction 保持用户选择
|
// need_decoction 保持用户选择
|
||||||
} else {
|
} else {
|
||||||
formData.dosage_unit = 'g'
|
formData.dosage_unit = 'g'
|
||||||
formData.dosage_amount = undefined
|
formData.dosage_amount = undefined
|
||||||
|
formData.dosage_bag_count = 1
|
||||||
formData.need_decoction = false
|
formData.need_decoction = false
|
||||||
formData.bags_per_dose = 1
|
formData.bags_per_dose = 1
|
||||||
}
|
}
|
||||||
@@ -1275,6 +1295,7 @@ const handleSave = async () => {
|
|||||||
dose_unit: formData.dose_unit,
|
dose_unit: formData.dose_unit,
|
||||||
dosage_amount: formData.dosage_amount,
|
dosage_amount: formData.dosage_amount,
|
||||||
dosage_unit: formData.dosage_unit,
|
dosage_unit: formData.dosage_unit,
|
||||||
|
dosage_bag_count: formData.dosage_bag_count,
|
||||||
need_decoction: formData.need_decoction,
|
need_decoction: formData.need_decoction,
|
||||||
bags_per_dose: formData.bags_per_dose,
|
bags_per_dose: formData.bags_per_dose,
|
||||||
usage_days: formData.usage_days,
|
usage_days: formData.usage_days,
|
||||||
@@ -1354,12 +1375,15 @@ const handleNewPrescription = async () => {
|
|||||||
if (formData.prescription_type === '浓缩水丸') {
|
if (formData.prescription_type === '浓缩水丸') {
|
||||||
formData.dosage_unit = 'g'
|
formData.dosage_unit = 'g'
|
||||||
formData.dosage_amount = 10
|
formData.dosage_amount = 10
|
||||||
|
formData.dosage_bag_count = 1
|
||||||
} else if (formData.prescription_type === '饮片') {
|
} else if (formData.prescription_type === '饮片') {
|
||||||
formData.dosage_unit = 'ml'
|
formData.dosage_unit = 'ml'
|
||||||
formData.dosage_amount = 50
|
formData.dosage_amount = 50
|
||||||
|
formData.dosage_bag_count = 1
|
||||||
} else {
|
} else {
|
||||||
formData.dosage_unit = 'g'
|
formData.dosage_unit = 'g'
|
||||||
formData.dosage_amount = undefined
|
formData.dosage_amount = undefined
|
||||||
|
formData.dosage_bag_count = 1
|
||||||
}
|
}
|
||||||
formData.patient_name = saved.patient_name || ''
|
formData.patient_name = saved.patient_name || ''
|
||||||
formData.gender = saved.gender ?? 0
|
formData.gender = saved.gender ?? 0
|
||||||
|
|||||||
@@ -798,6 +798,17 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col v-if="editForm.prescription_type === '浓缩水丸'" :span="8">
|
||||||
|
<el-form-item label=" " prop="dosage_bag_count" label-width="12px">
|
||||||
|
<el-select v-model="editForm.dosage_bag_count" placeholder="请选择袋数" class="w-[120px]">
|
||||||
|
<el-option label="1袋" :value="1" />
|
||||||
|
<el-option label="2袋" :value="2" />
|
||||||
|
<el-option label="3袋" :value="3" />
|
||||||
|
<el-option label="4袋" :value="4" />
|
||||||
|
<el-option label="5袋" :value="5" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<!-- 饮片代煎选项 -->
|
<!-- 饮片代煎选项 -->
|
||||||
<el-col v-if="editForm.prescription_type === '饮片'" :span="8">
|
<el-col v-if="editForm.prescription_type === '饮片'" :span="8">
|
||||||
@@ -2077,15 +2088,19 @@ const rxUsageText = computed(() => {
|
|||||||
if (!v) return '—'
|
if (!v) return '—'
|
||||||
if (v.usage_text) return v.usage_text
|
if (v.usage_text) return v.usage_text
|
||||||
const times = Number(v.times_per_day) > 0 ? Number(v.times_per_day) : 3
|
const times = Number(v.times_per_day) > 0 ? Number(v.times_per_day) : 3
|
||||||
const bags = Number(v.bags_per_dose) > 0 ? Number(v.bags_per_dose) : 1
|
|
||||||
const amount = v.dosage_amount != null ? Number(v.dosage_amount) : 10
|
const amount = v.dosage_amount != null ? Number(v.dosage_amount) : 10
|
||||||
const unit = v.dosage_unit || 'g'
|
const unit = v.dosage_unit || 'g'
|
||||||
const usageWay = v.usage_way || '温水送服'
|
const usageWay = v.usage_way || '温水送服'
|
||||||
const usageTime = v.usage_time || ''
|
const usageTime = v.usage_time || ''
|
||||||
const seg: string[] = []
|
const seg: string[] = []
|
||||||
seg.push(`每天${times}次`)
|
seg.push(`每天${times}次`)
|
||||||
seg.push(`一次${bags}包(约${amount}${unit})`)
|
if ((v.prescription_type || '浓缩水丸') === '浓缩水丸') {
|
||||||
seg.push(`每包${amount}${unit}`)
|
const bags = Number(v.dosage_bag_count) > 0 ? Number(v.dosage_bag_count) : 1
|
||||||
|
seg.push(`一次${bags}袋`)
|
||||||
|
seg.push(`每袋${amount}${unit}`)
|
||||||
|
} else {
|
||||||
|
seg.push(`一次${amount}${unit}`)
|
||||||
|
}
|
||||||
seg.push(usageWay)
|
seg.push(usageWay)
|
||||||
if (usageTime) seg.push(usageTime)
|
if (usageTime) seg.push(usageTime)
|
||||||
return seg.join(', ')
|
return seg.join(', ')
|
||||||
@@ -2254,6 +2269,7 @@ const editForm = reactive({
|
|||||||
prescription_type: '浓缩水丸',
|
prescription_type: '浓缩水丸',
|
||||||
dosage_amount: 1 as number | undefined,
|
dosage_amount: 1 as number | undefined,
|
||||||
dosage_unit: 'g',
|
dosage_unit: 'g',
|
||||||
|
dosage_bag_count: 1,
|
||||||
need_decoction: false,
|
need_decoction: false,
|
||||||
bags_per_dose: 1,
|
bags_per_dose: 1,
|
||||||
patient_name: '',
|
patient_name: '',
|
||||||
@@ -2367,16 +2383,19 @@ watch(() => editForm.prescription_type, (newType) => {
|
|||||||
if (newType === '浓缩水丸') {
|
if (newType === '浓缩水丸') {
|
||||||
editForm.dosage_unit = 'g'
|
editForm.dosage_unit = 'g'
|
||||||
editForm.dosage_amount = 1
|
editForm.dosage_amount = 1
|
||||||
|
editForm.dosage_bag_count = 1
|
||||||
editForm.need_decoction = false
|
editForm.need_decoction = false
|
||||||
editForm.bags_per_dose = 1
|
editForm.bags_per_dose = 1
|
||||||
} else if (newType === '饮片') {
|
} else if (newType === '饮片') {
|
||||||
editForm.dosage_unit = 'ml'
|
editForm.dosage_unit = 'ml'
|
||||||
editForm.dosage_amount = 50
|
editForm.dosage_amount = 50
|
||||||
|
editForm.dosage_bag_count = 1
|
||||||
editForm.bags_per_dose = 1
|
editForm.bags_per_dose = 1
|
||||||
// need_decoction 保持用户选择
|
// need_decoction 保持用户选择
|
||||||
} else {
|
} else {
|
||||||
editForm.dosage_unit = 'g'
|
editForm.dosage_unit = 'g'
|
||||||
editForm.dosage_amount = undefined
|
editForm.dosage_amount = undefined
|
||||||
|
editForm.dosage_bag_count = 1
|
||||||
editForm.need_decoction = false
|
editForm.need_decoction = false
|
||||||
editForm.bags_per_dose = 1
|
editForm.bags_per_dose = 1
|
||||||
}
|
}
|
||||||
@@ -2953,6 +2972,11 @@ const removeHerb = (index: number) => {
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
editForm.id = 0
|
editForm.id = 0
|
||||||
editForm.prescription_type = '浓缩水丸'
|
editForm.prescription_type = '浓缩水丸'
|
||||||
|
editForm.dosage_amount = 1
|
||||||
|
editForm.dosage_unit = 'g'
|
||||||
|
editForm.dosage_bag_count = 1
|
||||||
|
editForm.need_decoction = false
|
||||||
|
editForm.bags_per_dose = 1
|
||||||
editForm.patient_name = ''
|
editForm.patient_name = ''
|
||||||
editForm.gender = 1
|
editForm.gender = 1
|
||||||
editForm.age = 0
|
editForm.age = 0
|
||||||
@@ -3070,6 +3094,7 @@ const handleEdit = async (row: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editForm.dosage_bag_count = src.dosage_bag_count ? Number(src.dosage_bag_count) : 1
|
||||||
editForm.need_decoction = src.need_decoction === 1 || src.need_decoction === true
|
editForm.need_decoction = src.need_decoction === 1 || src.need_decoction === true
|
||||||
editForm.bags_per_dose = src.bags_per_dose ? Number(src.bags_per_dose) : 1
|
editForm.bags_per_dose = src.bags_per_dose ? Number(src.bags_per_dose) : 1
|
||||||
editForm.patient_name = src.patient_name || ''
|
editForm.patient_name = src.patient_name || ''
|
||||||
|
|||||||
@@ -801,6 +801,9 @@
|
|||||||
<el-descriptions-item label="用量">
|
<el-descriptions-item label="用量">
|
||||||
<template v-if="detailPrescription.dosage_amount">
|
<template v-if="detailPrescription.dosage_amount">
|
||||||
{{ detailPrescription.dosage_amount }}{{ detailPrescription.dosage_unit || 'g' }}
|
{{ detailPrescription.dosage_amount }}{{ detailPrescription.dosage_unit || 'g' }}
|
||||||
|
<template v-if="detailPrescription.prescription_type === '浓缩水丸'">
|
||||||
|
· {{ Number(detailPrescription.dosage_bag_count) > 0 ? Number(detailPrescription.dosage_bag_count) : 1 }}袋
|
||||||
|
</template>
|
||||||
<span v-if="detailPrescription.prescription_type === '饮片' && detailPrescription.need_decoction !== null" class="ml-2 text-gray-500">
|
<span v-if="detailPrescription.prescription_type === '饮片' && detailPrescription.need_decoction !== null" class="ml-2 text-gray-500">
|
||||||
({{ detailPrescription.need_decoction ? '代煎' : '不代煎' }})
|
({{ detailPrescription.need_decoction ? '代煎' : '不代煎' }})
|
||||||
</span>
|
</span>
|
||||||
@@ -4459,7 +4462,8 @@ const slipPerBagDosageText = computed(() => {
|
|||||||
const d = prescriptionViewData.value
|
const d = prescriptionViewData.value
|
||||||
if (!d || (d.prescription_type || '浓缩水丸') !== '浓缩水丸') return '—'
|
if (!d || (d.prescription_type || '浓缩水丸') !== '浓缩水丸') return '—'
|
||||||
if (d.dosage_amount == null || d.dosage_amount === '') return '—'
|
if (d.dosage_amount == null || d.dosage_amount === '') return '—'
|
||||||
return `${d.dosage_amount}${d.dosage_unit || 'g'}`
|
const bags = Number(d.dosage_bag_count) > 0 ? Number(d.dosage_bag_count) : 1
|
||||||
|
return `${d.dosage_amount}${d.dosage_unit || 'g'} · ${bags}袋`
|
||||||
})
|
})
|
||||||
|
|
||||||
const slipPillGrams = computed(() => {
|
const slipPillGrams = computed(() => {
|
||||||
@@ -4564,15 +4568,19 @@ const rxUsageText = computed(() => {
|
|||||||
if (!v) return '—'
|
if (!v) return '—'
|
||||||
if (v.usage_text) return v.usage_text
|
if (v.usage_text) return v.usage_text
|
||||||
const times = Number(v.times_per_day) > 0 ? Number(v.times_per_day) : 3
|
const times = Number(v.times_per_day) > 0 ? Number(v.times_per_day) : 3
|
||||||
const bags = Number(v.bags_per_dose) > 0 ? Number(v.bags_per_dose) : 1
|
|
||||||
const amount = v.dosage_amount != null ? Number(v.dosage_amount) : 10
|
const amount = v.dosage_amount != null ? Number(v.dosage_amount) : 10
|
||||||
const unit = v.dosage_unit || 'g'
|
const unit = v.dosage_unit || 'g'
|
||||||
const usageWay = v.usage_way || '温水送服'
|
const usageWay = v.usage_way || '温水送服'
|
||||||
const usageTime = v.usage_time || ''
|
const usageTime = v.usage_time || ''
|
||||||
const seg: string[] = []
|
const seg: string[] = []
|
||||||
seg.push(`每天${times}次`)
|
seg.push(`每天${times}次`)
|
||||||
seg.push(`一次${bags}包(约${amount}${unit})`)
|
if ((v.prescription_type || '浓缩水丸') === '浓缩水丸') {
|
||||||
seg.push(`每包${amount}${unit}`)
|
const bags = Number(v.dosage_bag_count) > 0 ? Number(v.dosage_bag_count) : 1
|
||||||
|
seg.push(`一次${bags}袋`)
|
||||||
|
seg.push(`每袋${amount}${unit}`)
|
||||||
|
} else {
|
||||||
|
seg.push(`一次${amount}${unit}`)
|
||||||
|
}
|
||||||
seg.push(usageWay)
|
seg.push(usageWay)
|
||||||
if (usageTime) seg.push(usageTime)
|
if (usageTime) seg.push(usageTime)
|
||||||
return seg.join(', ')
|
return seg.join(', ')
|
||||||
|
|||||||
@@ -819,6 +819,9 @@
|
|||||||
<el-descriptions-item label="用量">
|
<el-descriptions-item label="用量">
|
||||||
<template v-if="detailPrescription.dosage_amount">
|
<template v-if="detailPrescription.dosage_amount">
|
||||||
{{ detailPrescription.dosage_amount }}{{ detailPrescription.dosage_unit || 'g' }}
|
{{ detailPrescription.dosage_amount }}{{ detailPrescription.dosage_unit || 'g' }}
|
||||||
|
<template v-if="detailPrescription.prescription_type === '浓缩水丸'">
|
||||||
|
· {{ Number(detailPrescription.dosage_bag_count) > 0 ? Number(detailPrescription.dosage_bag_count) : 1 }}袋
|
||||||
|
</template>
|
||||||
<span v-if="detailPrescription.prescription_type === '饮片' && detailPrescription.need_decoction !== null" class="ml-2 text-gray-500">
|
<span v-if="detailPrescription.prescription_type === '饮片' && detailPrescription.need_decoction !== null" class="ml-2 text-gray-500">
|
||||||
({{ detailPrescription.need_decoction ? '代煎' : '不代煎' }})
|
({{ detailPrescription.need_decoction ? '代煎' : '不代煎' }})
|
||||||
</span>
|
</span>
|
||||||
@@ -4510,7 +4513,8 @@ const slipPerBagDosageText = computed(() => {
|
|||||||
const d = prescriptionViewData.value
|
const d = prescriptionViewData.value
|
||||||
if (!d || (d.prescription_type || '浓缩水丸') !== '浓缩水丸') return '—'
|
if (!d || (d.prescription_type || '浓缩水丸') !== '浓缩水丸') return '—'
|
||||||
if (d.dosage_amount == null || d.dosage_amount === '') return '—'
|
if (d.dosage_amount == null || d.dosage_amount === '') return '—'
|
||||||
return `${d.dosage_amount}${d.dosage_unit || 'g'}`
|
const bags = Number(d.dosage_bag_count) > 0 ? Number(d.dosage_bag_count) : 1
|
||||||
|
return `${d.dosage_amount}${d.dosage_unit || 'g'} · ${bags}袋`
|
||||||
})
|
})
|
||||||
|
|
||||||
const slipPillGrams = computed(() => {
|
const slipPillGrams = computed(() => {
|
||||||
@@ -4615,15 +4619,19 @@ const rxUsageText = computed(() => {
|
|||||||
if (!v) return '—'
|
if (!v) return '—'
|
||||||
if (v.usage_text) return v.usage_text
|
if (v.usage_text) return v.usage_text
|
||||||
const times = Number(v.times_per_day) > 0 ? Number(v.times_per_day) : 3
|
const times = Number(v.times_per_day) > 0 ? Number(v.times_per_day) : 3
|
||||||
const bags = Number(v.bags_per_dose) > 0 ? Number(v.bags_per_dose) : 1
|
|
||||||
const amount = v.dosage_amount != null ? Number(v.dosage_amount) : 10
|
const amount = v.dosage_amount != null ? Number(v.dosage_amount) : 10
|
||||||
const unit = v.dosage_unit || 'g'
|
const unit = v.dosage_unit || 'g'
|
||||||
const usageWay = v.usage_way || '温水送服'
|
const usageWay = v.usage_way || '温水送服'
|
||||||
const usageTime = v.usage_time || ''
|
const usageTime = v.usage_time || ''
|
||||||
const seg: string[] = []
|
const seg: string[] = []
|
||||||
seg.push(`每天${times}次`)
|
seg.push(`每天${times}次`)
|
||||||
seg.push(`一次${bags}包(约${amount}${unit})`)
|
if ((v.prescription_type || '浓缩水丸') === '浓缩水丸') {
|
||||||
seg.push(`每包${amount}${unit}`)
|
const bags = Number(v.dosage_bag_count) > 0 ? Number(v.dosage_bag_count) : 1
|
||||||
|
seg.push(`一次${bags}袋`)
|
||||||
|
seg.push(`每袋${amount}${unit}`)
|
||||||
|
} else {
|
||||||
|
seg.push(`一次${amount}${unit}`)
|
||||||
|
}
|
||||||
seg.push(usageWay)
|
seg.push(usageWay)
|
||||||
if (usageTime) seg.push(usageTime)
|
if (usageTime) seg.push(usageTime)
|
||||||
return seg.join(', ')
|
return seg.join(', ')
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,9 +3,9 @@
|
|||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
:disabled="!props.diagnosisId"
|
:disabled="!props.diagnosisId || !!props.readOnly || !hasDailyRecordPermission"
|
||||||
@click="handleAdd"
|
@click="handleAdd"
|
||||||
v-perms="['tcm.diagnosisTodo/add']"
|
v-perms="DAILY_RECORD_PERMS"
|
||||||
>
|
>
|
||||||
+ 新增待办
|
+ 新增待办
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -51,11 +51,11 @@
|
|||||||
<el-table-column label="操作" width="120" fixed="right" align="center">
|
<el-table-column label="操作" width="120" fixed="right" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button
|
<el-button
|
||||||
v-if="row.status === 0 && row.can_cancel"
|
v-if="!props.readOnly && row.status === 0 && row.can_cancel"
|
||||||
link
|
link
|
||||||
type="danger"
|
type="danger"
|
||||||
@click="handleCancel(row)"
|
@click="handleCancel(row)"
|
||||||
v-perms="['tcm.diagnosisTodo/cancel']"
|
v-perms="DAILY_RECORD_PERMS"
|
||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -114,15 +114,21 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import { diagnosisTodoLists, diagnosisTodoAdd, diagnosisTodoCancel } from '@/api/tcm'
|
import { diagnosisTodoLists, diagnosisTodoAdd, diagnosisTodoCancel } from '@/api/tcm'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { hasPermission } from '@/utils/perm'
|
||||||
import feedback from '@/utils/feedback'
|
import feedback from '@/utils/feedback'
|
||||||
|
|
||||||
|
const DAILY_RECORD_PERMS = ['tcm.diagnosis/dailyRecord']
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
diagnosisId: number | null | undefined
|
diagnosisId: number | null | undefined
|
||||||
patientId?: number | null
|
patientId?: number | null
|
||||||
patientName?: string
|
patientName?: string
|
||||||
|
readOnly?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
const hasDailyRecordPermission = computed(() => hasPermission(DAILY_RECORD_PERMS))
|
||||||
|
|
||||||
// pager 与项目内 <pagination v-model="pager" /> 约定的字段保持一致
|
// pager 与项目内 <pagination v-model="pager" /> 约定的字段保持一致
|
||||||
const pager = reactive({
|
const pager = reactive({
|
||||||
@@ -136,7 +142,7 @@ const pager = reactive({
|
|||||||
const filterStatus = ref<number | ''>('')
|
const filterStatus = ref<number | ''>('')
|
||||||
|
|
||||||
const fetchList = async () => {
|
const fetchList = async () => {
|
||||||
if (!props.diagnosisId || Number(props.diagnosisId) <= 0) {
|
if (!props.diagnosisId || Number(props.diagnosisId) <= 0 || !hasDailyRecordPermission.value) {
|
||||||
pager.lists = []
|
pager.lists = []
|
||||||
pager.count = 0
|
pager.count = 0
|
||||||
return
|
return
|
||||||
@@ -220,7 +226,7 @@ const disablePastDate = (date: Date) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
if (!props.diagnosisId) {
|
if (!props.diagnosisId || props.readOnly || !hasDailyRecordPermission.value) {
|
||||||
feedback.msgWarning('诊单未保存,无法添加待办')
|
feedback.msgWarning('诊单未保存,无法添加待办')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -248,7 +254,6 @@ const handleAddSubmit = async () => {
|
|||||||
content: addForm.content.trim(),
|
content: addForm.content.trim(),
|
||||||
remind_time: Math.floor(remindMs / 1000)
|
remind_time: Math.floor(remindMs / 1000)
|
||||||
})
|
})
|
||||||
feedback.msgSuccess('已创建')
|
|
||||||
addDialogVisible.value = false
|
addDialogVisible.value = false
|
||||||
fetchList()
|
fetchList()
|
||||||
} catch {
|
} catch {
|
||||||
@@ -260,6 +265,7 @@ const handleAddSubmit = async () => {
|
|||||||
|
|
||||||
// ========== 取消 ==========
|
// ========== 取消 ==========
|
||||||
const handleCancel = async (row: any) => {
|
const handleCancel = async (row: any) => {
|
||||||
|
if (!hasDailyRecordPermission.value || props.readOnly) return
|
||||||
try {
|
try {
|
||||||
await feedback.confirm(`确认取消「${row.remind_time_text} · ${truncate(row.content, 30)}」吗?`)
|
await feedback.confirm(`确认取消「${row.remind_time_text} · ${truncate(row.content, 30)}」吗?`)
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -573,54 +573,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<el-empty v-else description="请先保存诊单后查看" />
|
<el-empty v-else description="请先保存诊单后查看" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<!-- 血糖血压记录标签页 -->
|
|
||||||
<el-tab-pane label="血糖血压记录" name="blood" :disabled="!formData.id">
|
|
||||||
<blood-record-list
|
|
||||||
v-if="formData.id"
|
|
||||||
:diagnosis-id="Number(formData.id)"
|
|
||||||
:patient-id="Number(formData.patient_id)"
|
|
||||||
:read-only="viewOnly"
|
|
||||||
/>
|
|
||||||
<el-empty v-else description="请先保存诊单后再添加血糖血压记录" />
|
|
||||||
</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)"
|
|
||||||
:read-only="viewOnly"
|
|
||||||
/>
|
|
||||||
<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)"
|
|
||||||
:read-only="viewOnly"
|
|
||||||
/>
|
|
||||||
<el-empty v-else description="请先保存诊单后再添加运动打卡记录" />
|
|
||||||
</el-tab-pane>
|
|
||||||
|
|
||||||
<!-- 待办事项标签页(T5:企微推送给创建人本人) -->
|
|
||||||
<el-tab-pane
|
<el-tab-pane
|
||||||
label="待办事项"
|
v-if="hasDailyRecordPermission"
|
||||||
name="todo"
|
label="日常记录"
|
||||||
|
name="daily"
|
||||||
:disabled="!formData.id"
|
:disabled="!formData.id"
|
||||||
lazy
|
lazy
|
||||||
v-if="hasPermission(['tcm.diagnosisTodo/lists'])"
|
|
||||||
>
|
>
|
||||||
<diagnosis-todo-list
|
<daily-matrix
|
||||||
v-if="formData.id"
|
v-if="formData.id"
|
||||||
:diagnosis-id="Number(formData.id)"
|
:diagnosis-id="Number(formData.id)"
|
||||||
:patient-id="Number(formData.patient_id)"
|
:patient-id="Number(formData.patient_id)"
|
||||||
|
:age="formData.age"
|
||||||
:patient-name="formData.patient_name"
|
:patient-name="formData.patient_name"
|
||||||
|
:read-only="viewOnly"
|
||||||
/>
|
/>
|
||||||
<el-empty v-else description="请先保存诊单后再添加待办事项" />
|
<el-empty v-else description="请先保存诊单后查看" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<!-- 病历记录标签页(开方后自动显示) -->
|
<!-- 病历记录标签页(开方后自动显示) -->
|
||||||
@@ -746,10 +714,7 @@ import useUserStore from '@/stores/modules/user'
|
|||||||
import useAppStore from '@/stores/modules/app'
|
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 DailyMatrix from './components/DailyMatrix.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 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'
|
||||||
@@ -777,6 +742,7 @@ const submitting = ref(false)
|
|||||||
|
|
||||||
/** 拥有后手机号可正常编辑,失焦不再强制脱敏 */
|
/** 拥有后手机号可正常编辑,失焦不再强制脱敏 */
|
||||||
const hasPhonePlainPermission = computed(() => hasPermission(['tcm.diagnosis/phonePlain']))
|
const hasPhonePlainPermission = computed(() => hasPermission(['tcm.diagnosis/phonePlain']))
|
||||||
|
const hasDailyRecordPermission = computed(() => hasPermission(['tcm.diagnosis/dailyRecord']))
|
||||||
/** 编辑且无明文权限:只读脱敏,点击切换查看完整号 */
|
/** 编辑且无明文权限:只读脱敏,点击切换查看完整号 */
|
||||||
const showPhoneMaskedEdit = computed(() => mode.value === 'edit' && !hasPhonePlainPermission.value)
|
const showPhoneMaskedEdit = computed(() => mode.value === 'edit' && !hasPhonePlainPermission.value)
|
||||||
const phoneRevealUnlocked = ref(false)
|
const phoneRevealUnlocked = ref(false)
|
||||||
@@ -831,6 +797,9 @@ watch([visible, activeTab], () => {
|
|||||||
if (activeTab.value === 'appointmentRecords' && !hasPermission(['doctor.appointment/lists'])) {
|
if (activeTab.value === 'appointmentRecords' && !hasPermission(['doctor.appointment/lists'])) {
|
||||||
activeTab.value = 'basic'
|
activeTab.value = 'basic'
|
||||||
}
|
}
|
||||||
|
if (activeTab.value === 'daily' && !hasDailyRecordPermission.value) {
|
||||||
|
activeTab.value = 'basic'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -1857,4 +1826,3 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class AuthMiddleware
|
|||||||
$AdminUris = $adminAuthCache->getAdminUri() ?? [];
|
$AdminUris = $adminAuthCache->getAdminUri() ?? [];
|
||||||
$AdminUris = $this->formatUrl($AdminUris);
|
$AdminUris = $this->formatUrl($AdminUris);
|
||||||
|
|
||||||
if (in_array($accessUri, $AdminUris)) {
|
if (in_array($accessUri, $AdminUris) || $this->matchPermissionAlias($accessUri, $AdminUris)) {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
return JsonService::fail('权限不足,无法访问或操作');
|
return JsonService::fail('权限不足,无法访问或操作');
|
||||||
@@ -103,6 +103,25 @@ class AuthMiddleware
|
|||||||
}, $data);
|
}, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日常记录权限域:前端统一收口到 tcm.diagnosis/dailyRecord,
|
||||||
|
* 但待办/跟踪备注接口仍保留历史路由名,故在鉴权层做精确别名映射。
|
||||||
|
*/
|
||||||
|
private function matchPermissionAlias(string $accessUri, array $adminUris): bool
|
||||||
|
{
|
||||||
|
if (!in_array('tcm.diagnosis/dailyrecord', $adminUris, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_array($accessUri, [
|
||||||
|
'tcm.diagnosistodo/lists',
|
||||||
|
'tcm.diagnosistodo/add',
|
||||||
|
'tcm.diagnosistodo/cancel',
|
||||||
|
'tcm.diagnosis/trackingnotes',
|
||||||
|
'tcm.diagnosis/addtrackingnote',
|
||||||
|
], true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 面诊进度专用:auth.admin/lists、doctor.appointment/lists + progress_board=1,不校验菜单权限
|
* 面诊进度专用:auth.admin/lists、doctor.appointment/lists + progress_board=1,不校验菜单权限
|
||||||
*/
|
*/
|
||||||
@@ -118,4 +137,4 @@ class AuthMiddleware
|
|||||||
|
|
||||||
return in_array($c, ['auth.admin', 'doctor.appointment'], true);
|
return in_array($c, ['auth.admin', 'doctor.appointment'], true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use app\adminapi\logic\tcm\DiagnosisLogic;
|
|||||||
use app\common\model\finance\AccountCost;
|
use app\common\model\finance\AccountCost;
|
||||||
use app\common\service\DataScope\DataScopeService;
|
use app\common\service\DataScope\DataScopeService;
|
||||||
use app\common\service\qywx\MediaChannelService;
|
use app\common\service\qywx\MediaChannelService;
|
||||||
|
use think\db\Query;
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
|
|
||||||
class ConversionLogic
|
class ConversionLogic
|
||||||
@@ -68,8 +69,6 @@ class ConversionLogic
|
|||||||
|
|
||||||
$entities = self::loadEntities($dimension, $params, $visibleAdminIds);
|
$entities = self::loadEntities($dimension, $params, $visibleAdminIds);
|
||||||
$entityIds = array_keys($entities);
|
$entityIds = array_keys($entities);
|
||||||
$allocationEntities = self::loadEntities($dimension, $params, $visibleAdminIds);
|
|
||||||
$allocationEntityIds = array_keys($allocationEntities);
|
|
||||||
|
|
||||||
if ($entityIds === []) {
|
if ($entityIds === []) {
|
||||||
$result = [
|
$result = [
|
||||||
@@ -96,8 +95,9 @@ class ConversionLogic
|
|||||||
}
|
}
|
||||||
|
|
||||||
$adminToDeptIds = self::loadAdminDeptMap();
|
$adminToDeptIds = self::loadAdminDeptMap();
|
||||||
self::hydrateFanStats($allocationEntities, $dimension, $allocationEntityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds);
|
|
||||||
self::hydrateFanStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds);
|
self::hydrateFanStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds);
|
||||||
|
$allocationEntities = $entities;
|
||||||
|
$allocationEntityIds = $entityIds;
|
||||||
self::hydrateAppointmentStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $startDate, $endDate, $mediaChannel, $visibleAdminIds);
|
self::hydrateAppointmentStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $startDate, $endDate, $mediaChannel, $visibleAdminIds);
|
||||||
self::hydrateOrderAndAmountStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds);
|
self::hydrateOrderAndAmountStats($entities, $dimension, $entityIds, $adminToDeptIds, $startTimestamp, $endTimestamp, $mediaChannel, $visibleAdminIds);
|
||||||
// 数据隔离:可见部门 = 可见 admin 所属部门并集;用于 account_cost 与下游 cost 分摊。
|
// 数据隔离:可见部门 = 可见 admin 所属部门并集;用于 account_cost 与下游 cost 分摊。
|
||||||
@@ -257,11 +257,13 @@ class ConversionLogic
|
|||||||
?array $adminInfo = null
|
?array $adminInfo = null
|
||||||
): array
|
): array
|
||||||
{
|
{
|
||||||
|
$allowedDeptIds = self::resolveFilterAllowedDeptIds($visibleAdminIds, $eligibleDeptIds);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'departments' => self::buildDepartmentOptions($visibleAdminIds, $eligibleDeptIds),
|
'departments' => self::buildDepartmentOptions($visibleAdminIds, $eligibleDeptIds, $allowedDeptIds),
|
||||||
'assistants' => DiagnosisLogic::getAssistants($adminId, $adminInfo),
|
'assistants' => DiagnosisLogic::getAssistants($adminId, $adminInfo),
|
||||||
'doctors' => self::buildDoctorOptions($visibleAdminIds),
|
'doctors' => self::buildDoctorOptions($visibleAdminIds),
|
||||||
'media_channels' => self::buildMediaChannelOptions($visibleAdminIds, $eligibleDeptIds),
|
'media_channels' => self::buildMediaChannelOptions($visibleAdminIds, $eligibleDeptIds, $allowedDeptIds),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,36 +274,19 @@ class ConversionLogic
|
|||||||
*
|
*
|
||||||
* @return array<int, array<string, mixed>>
|
* @return array<int, array<string, mixed>>
|
||||||
*/
|
*/
|
||||||
private static function buildDepartmentOptions(?array $visibleAdminIds, array $eligibleDeptIds): array
|
private static function buildDepartmentOptions(?array $visibleAdminIds, array $eligibleDeptIds, ?array $allowedDeptIds = null): array
|
||||||
{
|
{
|
||||||
$allTree = DeptLogic::getAllData();
|
$allTree = DeptLogic::getAllData();
|
||||||
if ($visibleAdminIds === null) {
|
if ($visibleAdminIds === null) {
|
||||||
return $allTree;
|
return $allTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
$allowedDeptIds = [];
|
$allowedDeptIds ??= self::resolveFilterAllowedDeptIds($visibleAdminIds, $eligibleDeptIds);
|
||||||
if ($visibleAdminIds !== []) {
|
|
||||||
$deptIds = Db::name('admin_dept')
|
|
||||||
->whereIn('admin_id', $visibleAdminIds)
|
|
||||||
->column('dept_id');
|
|
||||||
foreach ($deptIds as $deptId) {
|
|
||||||
$deptId = (int)$deptId;
|
|
||||||
if ($deptId > 0) {
|
|
||||||
$allowedDeptIds[$deptId] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach ($eligibleDeptIds as $deptId) {
|
|
||||||
$deptId = (int)$deptId;
|
|
||||||
if ($deptId > 0) {
|
|
||||||
$allowedDeptIds[$deptId] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($allowedDeptIds === []) {
|
if ($allowedDeptIds === []) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::filterDeptTreeByIds($allTree, array_keys($allowedDeptIds));
|
return self::filterDeptTreeByIds($allTree, $allowedDeptIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -340,7 +325,7 @@ class ConversionLogic
|
|||||||
*
|
*
|
||||||
* @return array<int, array<string, mixed>>
|
* @return array<int, array<string, mixed>>
|
||||||
*/
|
*/
|
||||||
private static function buildMediaChannelOptions(?array $visibleAdminIds, array $eligibleDeptIds): array
|
private static function buildMediaChannelOptions(?array $visibleAdminIds, array $eligibleDeptIds, ?array $allowedDeptIds = null): array
|
||||||
{
|
{
|
||||||
$allOptions = MediaChannelService::getOptions();
|
$allOptions = MediaChannelService::getOptions();
|
||||||
if ($visibleAdminIds === null) {
|
if ($visibleAdminIds === null) {
|
||||||
@@ -350,30 +335,13 @@ class ConversionLogic
|
|||||||
return $allOptions;
|
return $allOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
$allowedDeptIds = [];
|
$allowedDeptIds ??= self::resolveFilterAllowedDeptIds($visibleAdminIds, $eligibleDeptIds);
|
||||||
if ($visibleAdminIds !== []) {
|
|
||||||
$deptIds = Db::name('admin_dept')
|
|
||||||
->whereIn('admin_id', $visibleAdminIds)
|
|
||||||
->column('dept_id');
|
|
||||||
foreach ($deptIds as $deptId) {
|
|
||||||
$deptId = (int)$deptId;
|
|
||||||
if ($deptId > 0) {
|
|
||||||
$allowedDeptIds[$deptId] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach ($eligibleDeptIds as $deptId) {
|
|
||||||
$deptId = (int)$deptId;
|
|
||||||
if ($deptId > 0) {
|
|
||||||
$allowedDeptIds[$deptId] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($allowedDeptIds === []) {
|
if ($allowedDeptIds === []) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$allowedCodes = Db::name('account_cost')
|
$allowedCodes = Db::name('account_cost')
|
||||||
->whereIn('dept_id', array_keys($allowedDeptIds))
|
->whereIn('dept_id', $allowedDeptIds)
|
||||||
->where('media_channel_code', '<>', '')
|
->where('media_channel_code', '<>', '')
|
||||||
->distinct(true)
|
->distinct(true)
|
||||||
->column('media_channel_code');
|
->column('media_channel_code');
|
||||||
@@ -831,8 +799,14 @@ class ConversionLogic
|
|||||||
->leftJoin('admin a', 'a.work_wechat_userid = e.user_id AND a.delete_time IS NULL')
|
->leftJoin('admin a', 'a.work_wechat_userid = e.user_id AND a.delete_time IS NULL')
|
||||||
->where('e.change_type', 'add_external_contact')
|
->where('e.change_type', 'add_external_contact')
|
||||||
->where('e.event_time', 'between', [$startTimestamp, $endTimestamp])
|
->where('e.event_time', 'between', [$startTimestamp, $endTimestamp])
|
||||||
->fieldRaw('e.user_id, a.id AS admin_id, COUNT(*) AS add_fans_count')
|
->fieldRaw('a.id AS admin_id, COUNT(*) AS add_fans_count')
|
||||||
->group('e.user_id, a.id');
|
->group('a.id');
|
||||||
|
|
||||||
|
if ($visibleAdminIds !== null) {
|
||||||
|
$query->whereIn('a.id', $visibleAdminIds);
|
||||||
|
} elseif ($dimension !== 'dept' && $entityIds !== []) {
|
||||||
|
$query->whereIn('a.id', $entityIds);
|
||||||
|
}
|
||||||
|
|
||||||
if ($mediaChannel !== null) {
|
if ($mediaChannel !== null) {
|
||||||
$query->leftJoin('qywx_external_contact q', 'q.external_userid = e.external_userid');
|
$query->leftJoin('qywx_external_contact q', 'q.external_userid = e.external_userid');
|
||||||
@@ -904,10 +878,16 @@ class ConversionLogic
|
|||||||
->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id')
|
->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id')
|
||||||
->where('a.appointment_date', '>=', $startDate)
|
->where('a.appointment_date', '>=', $startDate)
|
||||||
->where('a.appointment_date', '<=', $endDate)
|
->where('a.appointment_date', '<=', $endDate)
|
||||||
->whereRaw('(u.id IS NULL OR u.delete_time IS NULL)')
|
|
||||||
->fieldRaw("{$sourceExpr} AS source_admin_id, a.patient_id AS diagnosis_id, COUNT(*) AS appointment_count, SUM(CASE WHEN a.status = 3 THEN 1 ELSE 0 END) AS interview_count")
|
->fieldRaw("{$sourceExpr} AS source_admin_id, a.patient_id AS diagnosis_id, COUNT(*) AS appointment_count, SUM(CASE WHEN a.status = 3 THEN 1 ELSE 0 END) AS interview_count")
|
||||||
->group("{$sourceExpr}, a.patient_id");
|
->group("{$sourceExpr}, a.patient_id");
|
||||||
|
|
||||||
|
$query->where(static function (Query $subQuery): void {
|
||||||
|
$subQuery->whereNull('u.id')
|
||||||
|
->whereOr(static function (Query $orQuery): void {
|
||||||
|
$orQuery->whereNull('u.delete_time');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if ($mediaChannel !== null) {
|
if ($mediaChannel !== null) {
|
||||||
$legacyChannelValues = MediaChannelService::getLegacyAppointmentChannelValues($mediaChannel);
|
$legacyChannelValues = MediaChannelService::getLegacyAppointmentChannelValues($mediaChannel);
|
||||||
if ($legacyChannelValues !== []) {
|
if ($legacyChannelValues !== []) {
|
||||||
@@ -976,7 +956,9 @@ class ConversionLogic
|
|||||||
->where('o.status', 2)
|
->where('o.status', 2)
|
||||||
->where('o.order_type', 1)
|
->where('o.order_type', 1)
|
||||||
->where('o.amount', 5)
|
->where('o.amount', 5)
|
||||||
->whereRaw('(o.payment_time IS NOT NULL AND o.payment_time <> "" AND o.payment_time >= ? AND o.payment_time <= ?)', [$startDateTime, $endDateTime])
|
->whereNotNull('o.payment_time')
|
||||||
|
->where('o.payment_time', '<>', '')
|
||||||
|
->whereBetweenTime('o.payment_time', $startDateTime, $endDateTime)
|
||||||
->fieldRaw('o.creator_id AS source_admin_id, COUNT(*) AS paid_appointment_count')
|
->fieldRaw('o.creator_id AS source_admin_id, COUNT(*) AS paid_appointment_count')
|
||||||
->group('o.creator_id');
|
->group('o.creator_id');
|
||||||
|
|
||||||
@@ -1896,7 +1878,8 @@ class ConversionLogic
|
|||||||
// 单条 LIKE 没命中再退化全表(量大时会慢,因此仅在极少数员工场景下兜底)。
|
// 单条 LIKE 没命中再退化全表(量大时会慢,因此仅在极少数员工场景下兜底)。
|
||||||
$followRows = Db::name('qywx_external_contact')
|
$followRows = Db::name('qywx_external_contact')
|
||||||
->whereNull('delete_time')
|
->whereNull('delete_time')
|
||||||
->whereRaw('follow_users IS NOT NULL AND follow_users <> ""')
|
->whereNotNull('follow_users')
|
||||||
|
->where('follow_users', '<>', '')
|
||||||
->limit(2000)
|
->limit(2000)
|
||||||
->field('follow_users')
|
->field('follow_users')
|
||||||
->select()
|
->select()
|
||||||
@@ -2385,4 +2368,38 @@ class ConversionLogic
|
|||||||
|
|
||||||
return round($numerator / $denominator, 2);
|
return round($numerator / $denominator, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int[]|null $visibleAdminIds
|
||||||
|
* @param int[] $eligibleDeptIds
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
private static function resolveFilterAllowedDeptIds(?array $visibleAdminIds, array $eligibleDeptIds): array
|
||||||
|
{
|
||||||
|
if ($visibleAdminIds === null) {
|
||||||
|
return array_values(array_unique(array_filter(array_map('intval', $eligibleDeptIds), static fn (int $deptId): bool => $deptId > 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowedDeptIds = [];
|
||||||
|
if ($visibleAdminIds !== []) {
|
||||||
|
$deptIds = Db::name('admin_dept')
|
||||||
|
->whereIn('admin_id', $visibleAdminIds)
|
||||||
|
->column('dept_id');
|
||||||
|
foreach ($deptIds as $deptId) {
|
||||||
|
$deptId = (int)$deptId;
|
||||||
|
if ($deptId > 0) {
|
||||||
|
$allowedDeptIds[$deptId] = $deptId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($eligibleDeptIds as $deptId) {
|
||||||
|
$deptId = (int)$deptId;
|
||||||
|
if ($deptId > 0) {
|
||||||
|
$allowedDeptIds[$deptId] = $deptId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values($allowedDeptIds);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ use app\common\model\tcm\DiagnosisTodo;
|
|||||||
* cancel() → status=2 (已取消,仅 status=0 可取消)
|
* cancel() → status=2 (已取消,仅 status=0 可取消)
|
||||||
*
|
*
|
||||||
* 鉴权:
|
* 鉴权:
|
||||||
* add:诊单需存在;数据权限交由路由层「tcm.diagnosisTodo/add」节点 + 前端 tab disabled 控制。
|
* add:诊单需存在;数据权限交由路由层统一「tcm.diagnosis/dailyRecord」权限域控制,
|
||||||
|
* 并兼容历史 diagnosisTodo/* 接口路由。
|
||||||
* cancel:仅创建人本人或超级管理员 (role_id=1) 可取消,且仅 status=0 时。
|
* cancel:仅创建人本人或超级管理员 (role_id=1) 可取消,且仅 status=0 时。
|
||||||
*
|
*
|
||||||
* @package app\adminapi\logic\tcm
|
* @package app\adminapi\logic\tcm
|
||||||
|
|||||||
@@ -152,6 +152,19 @@ class PrescriptionLogic
|
|||||||
return $ts ? date('Y-m-d', $ts) : date('Y-m-d');
|
return $ts ? date('Y-m-d', $ts) : date('Y-m-d');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function normalizeDosageBagCount($raw): int
|
||||||
|
{
|
||||||
|
$count = (int) $raw;
|
||||||
|
if ($count < 1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ($count > 5) {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同一诊单、同一开方人、同一处方日期:仅允许一张「未作废」的未删除记录;已作废的可再新开一张。
|
* 同一诊单、同一开方人、同一处方日期:仅允许一张「未作废」的未删除记录;已作废的可再新开一张。
|
||||||
*
|
*
|
||||||
@@ -230,6 +243,7 @@ class PrescriptionLogic
|
|||||||
'prescription_type' => $params['prescription_type'] ?? '浓缩水丸',
|
'prescription_type' => $params['prescription_type'] ?? '浓缩水丸',
|
||||||
'dosage_amount' => isset($params['dosage_amount']) ? (float)$params['dosage_amount'] : null,
|
'dosage_amount' => isset($params['dosage_amount']) ? (float)$params['dosage_amount'] : null,
|
||||||
'dosage_unit' => $params['dosage_unit'] ?? '',
|
'dosage_unit' => $params['dosage_unit'] ?? '',
|
||||||
|
'dosage_bag_count' => self::normalizeDosageBagCount($params['dosage_bag_count'] ?? 1),
|
||||||
'need_decoction' => (int)($params['need_decoction'] ?? 0),
|
'need_decoction' => (int)($params['need_decoction'] ?? 0),
|
||||||
'bags_per_dose' => isset($params['bags_per_dose']) ? (int)$params['bags_per_dose'] : 1,
|
'bags_per_dose' => isset($params['bags_per_dose']) ? (int)$params['bags_per_dose'] : 1,
|
||||||
'diagnosis_id' => (int)($params['diagnosis_id'] ?? 0),
|
'diagnosis_id' => (int)($params['diagnosis_id'] ?? 0),
|
||||||
@@ -359,6 +373,7 @@ class PrescriptionLogic
|
|||||||
'prescription_type' => $params['prescription_type'] ?? $prescription->prescription_type,
|
'prescription_type' => $params['prescription_type'] ?? $prescription->prescription_type,
|
||||||
'dosage_amount' => isset($params['dosage_amount']) ? (float)$params['dosage_amount'] : $prescription->dosage_amount,
|
'dosage_amount' => isset($params['dosage_amount']) ? (float)$params['dosage_amount'] : $prescription->dosage_amount,
|
||||||
'dosage_unit' => $params['dosage_unit'] ?? $prescription->dosage_unit,
|
'dosage_unit' => $params['dosage_unit'] ?? $prescription->dosage_unit,
|
||||||
|
'dosage_bag_count' => self::normalizeDosageBagCount($params['dosage_bag_count'] ?? ($prescription->dosage_bag_count ?? 1)),
|
||||||
'need_decoction' => isset($params['need_decoction']) ? (int)$params['need_decoction'] : (int)($prescription->need_decoction ?? 0),
|
'need_decoction' => isset($params['need_decoction']) ? (int)$params['need_decoction'] : (int)($prescription->need_decoction ?? 0),
|
||||||
'bags_per_dose' => isset($params['bags_per_dose']) ? (int)$params['bags_per_dose'] : (int)($prescription->bags_per_dose ?? 1),
|
'bags_per_dose' => isset($params['bags_per_dose']) ? (int)$params['bags_per_dose'] : (int)($prescription->bags_per_dose ?? 1),
|
||||||
'patient_name' => $params['patient_name'] ?? $prescription->patient_name,
|
'patient_name' => $params['patient_name'] ?? $prescription->patient_name,
|
||||||
@@ -811,6 +826,7 @@ class PrescriptionLogic
|
|||||||
'prescription_type' => '浓缩水丸',
|
'prescription_type' => '浓缩水丸',
|
||||||
'dosage_amount' => 1.0,
|
'dosage_amount' => 1.0,
|
||||||
'dosage_unit' => 'g',
|
'dosage_unit' => 'g',
|
||||||
|
'dosage_bag_count' => 1,
|
||||||
'need_decoction' => 0,
|
'need_decoction' => 0,
|
||||||
'bags_per_dose' => 1,
|
'bags_per_dose' => 1,
|
||||||
'diagnosis_id' => $diagnosisId,
|
'diagnosis_id' => $diagnosisId,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class PrescriptionValidate extends BaseValidate
|
|||||||
'id' => 'require',
|
'id' => 'require',
|
||||||
'diagnosis_id' => 'number',
|
'diagnosis_id' => 'number',
|
||||||
'appointment_id' => 'number',
|
'appointment_id' => 'number',
|
||||||
|
'dosage_bag_count' => 'integer|between:1,5',
|
||||||
'patient_name' => 'require',
|
'patient_name' => 'require',
|
||||||
'clinical_diagnosis' => 'require',
|
'clinical_diagnosis' => 'require',
|
||||||
'herbs' => 'require|array',
|
'herbs' => 'require|array',
|
||||||
@@ -20,6 +21,8 @@ class PrescriptionValidate extends BaseValidate
|
|||||||
];
|
];
|
||||||
|
|
||||||
protected $message = [
|
protected $message = [
|
||||||
|
'dosage_bag_count.integer' => '用量袋数必须为整数',
|
||||||
|
'dosage_bag_count.between' => '用量袋数必须在1到5袋之间',
|
||||||
'patient_name.require' => '患者姓名不能为空',
|
'patient_name.require' => '患者姓名不能为空',
|
||||||
'clinical_diagnosis.require' => '临床诊断不能为空',
|
'clinical_diagnosis.require' => '临床诊断不能为空',
|
||||||
'herbs.require' => '请添加中药',
|
'herbs.require' => '请添加中药',
|
||||||
@@ -28,7 +31,7 @@ class PrescriptionValidate extends BaseValidate
|
|||||||
public function sceneAdd()
|
public function sceneAdd()
|
||||||
{
|
{
|
||||||
return $this->only([
|
return $this->only([
|
||||||
'prescription_type', 'dosage_amount', 'dosage_unit', 'need_decoction', 'bags_per_dose',
|
'prescription_type', 'dosage_amount', 'dosage_unit', 'dosage_bag_count', 'need_decoction', 'bags_per_dose',
|
||||||
'patient_name', 'gender', 'age',
|
'patient_name', 'gender', 'age',
|
||||||
'visit_no', 'prescription_date', 'tongue', 'tongue_image', 'pulse',
|
'visit_no', 'prescription_date', 'tongue', 'tongue_image', 'pulse',
|
||||||
'pulse_condition', 'clinical_diagnosis', 'herbs', 'dose_count', 'dose_unit',
|
'pulse_condition', 'clinical_diagnosis', 'herbs', 'dose_count', 'dose_unit',
|
||||||
@@ -41,7 +44,7 @@ class PrescriptionValidate extends BaseValidate
|
|||||||
public function sceneEdit()
|
public function sceneEdit()
|
||||||
{
|
{
|
||||||
return $this->only([
|
return $this->only([
|
||||||
'id', 'prescription_type', 'dosage_amount', 'dosage_unit', 'need_decoction', 'bags_per_dose',
|
'id', 'prescription_type', 'dosage_amount', 'dosage_unit', 'dosage_bag_count', 'need_decoction', 'bags_per_dose',
|
||||||
'patient_name', 'gender', 'age',
|
'patient_name', 'gender', 'age',
|
||||||
'visit_no', 'prescription_date', 'tongue', 'tongue_image', 'pulse',
|
'visit_no', 'prescription_date', 'tongue', 'tongue_image', 'pulse',
|
||||||
'pulse_condition', 'clinical_diagnosis', 'herbs', 'dose_count', 'dose_unit',
|
'pulse_condition', 'clinical_diagnosis', 'herbs', 'dose_count', 'dose_unit',
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class Prescription extends BaseModel
|
|||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'dosage_amount' => 'float',
|
'dosage_amount' => 'float',
|
||||||
|
'dosage_bag_count' => 'integer',
|
||||||
'need_decoction' => 'integer',
|
'need_decoction' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# 诊单编辑:日常记录统一权限(2026-05-07)
|
||||||
|
# 挂在「中医诊单」(perms=tcm.diagnosis/lists) 菜单下,按钮型权限节点:
|
||||||
|
# tcm.diagnosis/dailyRecord 日常记录(统一控制血糖/饮食/运动/跟踪备注/待办)
|
||||||
|
|
||||||
|
SET @diag_menu_id := (SELECT id FROM zyt_system_menu WHERE perms = 'tcm.diagnosis/lists' LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO zyt_system_menu (
|
||||||
|
pid, type, name, icon, sort, perms, paths, component,
|
||||||
|
selected, params, is_cache, is_show, is_disable, create_time, update_time
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
@diag_menu_id, 'A', '日常记录', '', 59,
|
||||||
|
'tcm.diagnosis/dailyRecord', '', '',
|
||||||
|
'', '', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
|
||||||
|
FROM DUAL
|
||||||
|
WHERE @diag_menu_id IS NOT NULL
|
||||||
|
AND NOT EXISTS (SELECT 1 FROM zyt_system_menu WHERE perms = 'tcm.diagnosis/dailyRecord');
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- 添加处方用量袋数字段(浓缩水丸等开方场景,1-5袋)
|
||||||
|
ALTER TABLE `zyt_tcm_prescription`
|
||||||
|
ADD COLUMN `dosage_bag_count` TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '用量袋数(1-5袋)' AFTER `dosage_unit`;
|
||||||
Reference in New Issue
Block a user