处方增加禁用修改
This commit is contained in:
@@ -26,10 +26,6 @@ bin-release/
|
|||||||
/.cursor
|
/.cursor
|
||||||
/.codex
|
/.codex
|
||||||
/.agents
|
/.agents
|
||||||
/.claude
|
|
||||||
/.claude
|
|
||||||
/.claude
|
|
||||||
/.kbctx
|
|
||||||
/server/.spool
|
/server/.spool
|
||||||
/server/.claude
|
/server/.claude
|
||||||
/.spool
|
/.spool
|
||||||
|
|||||||
@@ -88,13 +88,17 @@
|
|||||||
共 <strong>{{ formData.herbs.length }}</strong> 味(主方 {{ mainHerbCount }} / 辅方
|
共 <strong>{{ formData.herbs.length }}</strong> 味(主方 {{ mainHerbCount }} / 辅方
|
||||||
{{ auxHerbCount }})· 可手动添加、从处方库或粘贴药方批量录入
|
{{ auxHerbCount }})· 可手动添加、从处方库或粘贴药方批量录入
|
||||||
</p>
|
</p>
|
||||||
|
<p v-if="herbsLocked" class="rp-toolbar__lock-tip">
|
||||||
|
<el-tag type="danger" size="small" effect="plain">禁用修改</el-tag>
|
||||||
|
含「禁用修改」处方库模板,药材已锁定,不可增删改,如需调整请重新「从处方库导入」覆盖
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rp-toolbar__actions" role="toolbar" aria-label="处方药材快捷操作">
|
<div class="rp-toolbar__actions" role="toolbar" aria-label="处方药材快捷操作">
|
||||||
<el-button type="primary" size="small" :icon="CirclePlus" @click="handleAddHerb('主方')">
|
<el-button type="primary" size="small" :icon="CirclePlus" :disabled="herbsLocked" @click="handleAddHerb('主方')">
|
||||||
添加主方
|
添加主方
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" plain size="small" @click="handleAddHerb('辅方')">
|
<el-button type="primary" plain size="small" :disabled="herbsLocked" @click="handleAddHerb('辅方')">
|
||||||
添加辅方
|
添加辅方
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
@@ -135,7 +139,7 @@
|
|||||||
:class="{ 'herb-editor-card--dup': isDuplicateHerbName(row.index) }"
|
:class="{ 'herb-editor-card--dup': isDuplicateHerbName(row.index) }"
|
||||||
>
|
>
|
||||||
<div class="herb-editor-card__title">主方 {{ row.index + 1 }}</div>
|
<div class="herb-editor-card__title">主方 {{ row.index + 1 }}</div>
|
||||||
<MedicineNameSelect v-model="formData.herbs[row.index].name" class="herb-editor-card__select" />
|
<MedicineNameSelect v-model="formData.herbs[row.index].name" :disabled="herbsLocked" class="herb-editor-card__select" />
|
||||||
<div
|
<div
|
||||||
v-if="isDuplicateHerbName(row.index)"
|
v-if="isDuplicateHerbName(row.index)"
|
||||||
class="herb-editor-card__dup-hint text-amber-600 text-xs mb-1"
|
class="herb-editor-card__dup-hint text-amber-600 text-xs mb-1"
|
||||||
@@ -148,11 +152,12 @@
|
|||||||
:min="0.1"
|
:min="0.1"
|
||||||
:step="1"
|
:step="1"
|
||||||
:precision="1"
|
:precision="1"
|
||||||
|
:disabled="herbsLocked"
|
||||||
placeholder="剂量(克)"
|
placeholder="剂量(克)"
|
||||||
class="herb-editor-card__dose"
|
class="herb-editor-card__dose"
|
||||||
/>
|
/>
|
||||||
<span class="text-gray-500 shrink-0">克</span>
|
<span class="text-gray-500 shrink-0">克</span>
|
||||||
<el-button type="danger" size="small" link @click="handleRemoveHerb(row.index)">
|
<el-button v-if="!herbsLocked" type="danger" size="small" link @click="handleRemoveHerb(row.index)">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -171,7 +176,7 @@
|
|||||||
:class="{ 'herb-editor-card--dup': isDuplicateHerbName(row.index) }"
|
:class="{ 'herb-editor-card--dup': isDuplicateHerbName(row.index) }"
|
||||||
>
|
>
|
||||||
<div class="herb-editor-card__title">辅方</div>
|
<div class="herb-editor-card__title">辅方</div>
|
||||||
<MedicineNameSelect v-model="formData.herbs[row.index].name" class="herb-editor-card__select" />
|
<MedicineNameSelect v-model="formData.herbs[row.index].name" :disabled="herbsLocked" class="herb-editor-card__select" />
|
||||||
<div
|
<div
|
||||||
v-if="isDuplicateHerbName(row.index)"
|
v-if="isDuplicateHerbName(row.index)"
|
||||||
class="herb-editor-card__dup-hint text-amber-600 text-xs mb-1"
|
class="herb-editor-card__dup-hint text-amber-600 text-xs mb-1"
|
||||||
@@ -184,11 +189,12 @@
|
|||||||
:min="0.1"
|
:min="0.1"
|
||||||
:step="1"
|
:step="1"
|
||||||
:precision="1"
|
:precision="1"
|
||||||
|
:disabled="herbsLocked"
|
||||||
placeholder="剂量(克)"
|
placeholder="剂量(克)"
|
||||||
class="herb-editor-card__dose"
|
class="herb-editor-card__dose"
|
||||||
/>
|
/>
|
||||||
<span class="text-gray-500 shrink-0">克</span>
|
<span class="text-gray-500 shrink-0">克</span>
|
||||||
<el-button type="danger" size="small" link @click="handleRemoveHerb(row.index)">
|
<el-button v-if="!herbsLocked" type="danger" size="small" link @click="handleRemoveHerb(row.index)">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1028,6 +1034,8 @@ interface Herb {
|
|||||||
name: string
|
name: string
|
||||||
dosage: number
|
dosage: number
|
||||||
formula_type?: FormulaType
|
formula_type?: FormulaType
|
||||||
|
/** 来自「禁用修改」处方库模板:锁定后不可增删改,只能再次导入覆盖 */
|
||||||
|
locked?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuxUsageForm = {
|
type AuxUsageForm = {
|
||||||
@@ -1044,11 +1052,15 @@ function normalizeFormulaType(v: unknown): FormulaType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeHerbRow(raw: any): Herb {
|
function normalizeHerbRow(raw: any): Herb {
|
||||||
return {
|
const row: Herb = {
|
||||||
name: String(raw?.name ?? '').trim(),
|
name: String(raw?.name ?? '').trim(),
|
||||||
dosage: Number(raw?.dosage) || 0,
|
dosage: Number(raw?.dosage) || 0,
|
||||||
formula_type: normalizeFormulaType(raw?.formula_type)
|
formula_type: normalizeFormulaType(raw?.formula_type)
|
||||||
}
|
}
|
||||||
|
if (raw?.locked === true || raw?.locked === 1) {
|
||||||
|
row.locked = true
|
||||||
|
}
|
||||||
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultAuxUsage(prescriptionType = '浓缩水丸'): AuxUsageForm {
|
function defaultAuxUsage(prescriptionType = '浓缩水丸'): AuxUsageForm {
|
||||||
@@ -1430,6 +1442,12 @@ const auxHerbRows = computed(() =>
|
|||||||
const mainHerbCount = computed(() => mainHerbRows.value.length)
|
const mainHerbCount = computed(() => mainHerbRows.value.length)
|
||||||
const auxHerbCount = computed(() => auxHerbRows.value.length)
|
const auxHerbCount = computed(() => auxHerbRows.value.length)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整张处方是否被锁定:只要任一药材来自「禁用修改」模板即锁定。
|
||||||
|
* 锁定后:不可增删改任意药材,仅可再次「从处方库导入」覆盖。
|
||||||
|
*/
|
||||||
|
const herbsLocked = computed(() => formData.herbs.some((h) => (h as Herb).locked === true))
|
||||||
|
|
||||||
const libraryDoctorId = computed(() => {
|
const libraryDoctorId = computed(() => {
|
||||||
const uid = Number(userStore.userInfo?.id)
|
const uid = Number(userStore.userInfo?.id)
|
||||||
return uid > 0 ? uid : 0
|
return uid > 0 ? uid : 0
|
||||||
@@ -2029,10 +2047,18 @@ function findDuplicateHerbNames(): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleAddHerb = (formulaType: FormulaType = '主方') => {
|
const handleAddHerb = (formulaType: FormulaType = '主方') => {
|
||||||
|
if (herbsLocked.value) {
|
||||||
|
feedback.msgWarning('该处方含「禁用修改」模板,药材已锁定,请重新从处方库导入覆盖')
|
||||||
|
return
|
||||||
|
}
|
||||||
formData.herbs.push({ name: '', dosage: 6, formula_type: formulaType })
|
formData.herbs.push({ name: '', dosage: 6, formula_type: formulaType })
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRemoveHerb = (index: number) => {
|
const handleRemoveHerb = (index: number) => {
|
||||||
|
if (herbsLocked.value) {
|
||||||
|
feedback.msgWarning('该处方含「禁用修改」模板,药材已锁定,不可删除')
|
||||||
|
return
|
||||||
|
}
|
||||||
formData.herbs.splice(index, 1)
|
formData.herbs.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2089,10 +2115,18 @@ const handleImportLibrary = (row: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const formulaType = normalizeFormulaType(row.formula_type)
|
const formulaType = normalizeFormulaType(row.formula_type)
|
||||||
const imported = (JSON.parse(JSON.stringify(row.herbs)) as any[]).map((h) => ({
|
// 「禁用修改」模板:导入的药材打上锁定标记 → 整张处方锁定(不可增删改,只能再次导入覆盖)
|
||||||
...normalizeHerbRow(h),
|
const isLockedTemplate = Number(row?.disable_edit) === 1
|
||||||
formula_type: formulaType
|
const imported = (JSON.parse(JSON.stringify(row.herbs)) as any[]).map((h) => {
|
||||||
}))
|
const herb = normalizeHerbRow(h)
|
||||||
|
herb.formula_type = formulaType
|
||||||
|
if (isLockedTemplate) {
|
||||||
|
herb.locked = true
|
||||||
|
} else {
|
||||||
|
delete herb.locked
|
||||||
|
}
|
||||||
|
return herb
|
||||||
|
})
|
||||||
if (libraryImportMode.value === 'replace') {
|
if (libraryImportMode.value === 'replace') {
|
||||||
const kept = formData.herbs.filter((h) => normalizeFormulaType(h.formula_type) !== formulaType)
|
const kept = formData.herbs.filter((h) => normalizeFormulaType(h.formula_type) !== formulaType)
|
||||||
formData.herbs = [...kept, ...imported]
|
formData.herbs = [...kept, ...imported]
|
||||||
@@ -2532,6 +2566,17 @@ defineExpose({
|
|||||||
color: var(--el-text-color-regular);
|
color: var(--el-text-color-regular);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rp-toolbar__lock-tip {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 6px 0 0;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.55;
|
||||||
|
color: var(--el-color-danger);
|
||||||
|
}
|
||||||
|
|
||||||
.rp-toolbar__actions {
|
.rp-toolbar__actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
@@ -679,17 +679,21 @@
|
|||||||
粘贴文本解析药名与剂量;须与药品库名称完全一致才录入(导入至主方)
|
粘贴文本解析药名与剂量;须与药品库名称完全一致才录入(导入至主方)
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="herbsLocked" class="flex items-center gap-2 flex-wrap mt-2 text-xs text-[var(--el-color-danger)]">
|
||||||
|
<el-tag type="danger" size="small" effect="plain">禁用修改</el-tag>
|
||||||
|
含「禁用修改」处方库模板,药材已锁定,不可增删改,如需调整请重新「从处方库导入」覆盖
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="herb-formula-block mt-3">
|
<div class="herb-formula-block mt-3">
|
||||||
<div class="herb-formula-block__head">
|
<div class="herb-formula-block__head">
|
||||||
<el-tag type="primary" size="small">主方</el-tag>
|
<el-tag type="primary" size="small">主方</el-tag>
|
||||||
<el-button type="primary" size="small" @click="addHerb('主方')">添加主方药材</el-button>
|
<el-button type="primary" size="small" :disabled="herbsLocked" @click="addHerb('主方')">添加主方药材</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="mainHerbRows" class="mt-2" border empty-text="暂无主方药材">
|
<el-table :data="mainHerbRows" class="mt-2" border empty-text="暂无主方药材">
|
||||||
<el-table-column label="序号" type="index" width="60" />
|
<el-table-column label="序号" type="index" width="60" />
|
||||||
<el-table-column label="药材名称" min-width="220">
|
<el-table-column label="药材名称" min-width="220">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<MedicineNameSelect v-model="editForm.herbs[row.index].name" class="w-full" />
|
<MedicineNameSelect v-model="editForm.herbs[row.index].name" :disabled="herbsLocked" class="w-full" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="剂量(克)" min-width="120">
|
<el-table-column label="剂量(克)" min-width="120">
|
||||||
@@ -699,6 +703,7 @@
|
|||||||
:min="0"
|
:min="0"
|
||||||
:precision="1"
|
:precision="1"
|
||||||
:step="0.5"
|
:step="0.5"
|
||||||
|
:disabled="herbsLocked"
|
||||||
placeholder="剂量"
|
placeholder="剂量"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
@@ -706,7 +711,8 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="80">
|
<el-table-column label="操作" width="80">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="danger" link @click="removeHerb(row.index)">删除</el-button>
|
<el-button v-if="!herbsLocked" type="danger" link @click="removeHerb(row.index)">删除</el-button>
|
||||||
|
<span v-else class="text-gray-400 text-xs">已锁定</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -715,7 +721,7 @@
|
|||||||
<div class="herb-formula-block mt-4">
|
<div class="herb-formula-block mt-4">
|
||||||
<div class="herb-formula-block__head">
|
<div class="herb-formula-block__head">
|
||||||
<el-tag type="warning" size="small">辅方</el-tag>
|
<el-tag type="warning" size="small">辅方</el-tag>
|
||||||
<el-button type="primary" size="small" plain @click="addHerb('辅方')">
|
<el-button type="primary" size="small" plain :disabled="herbsLocked" @click="addHerb('辅方')">
|
||||||
添加辅方药材
|
添加辅方药材
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -723,7 +729,7 @@
|
|||||||
<el-table-column label="序号" type="index" width="60" />
|
<el-table-column label="序号" type="index" width="60" />
|
||||||
<el-table-column label="药材名称" min-width="220">
|
<el-table-column label="药材名称" min-width="220">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<MedicineNameSelect v-model="editForm.herbs[row.index].name" class="w-full" />
|
<MedicineNameSelect v-model="editForm.herbs[row.index].name" :disabled="herbsLocked" class="w-full" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="剂量(克)" min-width="120">
|
<el-table-column label="剂量(克)" min-width="120">
|
||||||
@@ -733,6 +739,7 @@
|
|||||||
:min="0"
|
:min="0"
|
||||||
:precision="1"
|
:precision="1"
|
||||||
:step="0.5"
|
:step="0.5"
|
||||||
|
:disabled="herbsLocked"
|
||||||
placeholder="剂量"
|
placeholder="剂量"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
@@ -740,7 +747,8 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="80">
|
<el-table-column label="操作" width="80">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="danger" link @click="removeHerb(row.index)">删除</el-button>
|
<el-button v-if="!herbsLocked" type="danger" link @click="removeHerb(row.index)">删除</el-button>
|
||||||
|
<span v-else class="text-gray-400 text-xs">已锁定</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -1698,7 +1706,7 @@ import jsPDF from 'jspdf'
|
|||||||
const TcmDiagnosisEditView = defineAsyncComponent(() => import('@/views/tcm/diagnosis/edit.vue'))
|
const TcmDiagnosisEditView = defineAsyncComponent(() => import('@/views/tcm/diagnosis/edit.vue'))
|
||||||
|
|
||||||
type FormulaType = '主方' | '辅方'
|
type FormulaType = '主方' | '辅方'
|
||||||
type HerbRow = { name: string; dosage: number; formula_type: FormulaType }
|
type HerbRow = { name: string; dosage: number; formula_type: FormulaType; locked?: boolean }
|
||||||
|
|
||||||
type AuxUsageForm = {
|
type AuxUsageForm = {
|
||||||
dosage_amount?: number
|
dosage_amount?: number
|
||||||
@@ -1798,11 +1806,15 @@ function normalizeFormulaType(v: unknown): FormulaType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeHerbRow(raw: any): HerbRow {
|
function normalizeHerbRow(raw: any): HerbRow {
|
||||||
return {
|
const row: HerbRow = {
|
||||||
name: String(raw?.name ?? '').trim(),
|
name: String(raw?.name ?? '').trim(),
|
||||||
dosage: Number(raw?.dosage) || 0,
|
dosage: Number(raw?.dosage) || 0,
|
||||||
formula_type: normalizeFormulaType(raw?.formula_type)
|
formula_type: normalizeFormulaType(raw?.formula_type)
|
||||||
}
|
}
|
||||||
|
if (raw?.locked === true || raw?.locked === 1) {
|
||||||
|
row.locked = true
|
||||||
|
}
|
||||||
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeSlipHerbs(raw: unknown): HerbRow[] {
|
function normalizeSlipHerbs(raw: unknown): HerbRow[] {
|
||||||
@@ -2481,6 +2493,12 @@ const auxHerbRows = computed(() =>
|
|||||||
.filter(({ herb }) => normalizeFormulaType(herb.formula_type) === '辅方')
|
.filter(({ herb }) => normalizeFormulaType(herb.formula_type) === '辅方')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整张处方是否被锁定:只要任一药材来自「禁用修改」处方库模板即锁定。
|
||||||
|
* 锁定后不可增删改任意药材,只能再次「从处方库导入」覆盖。
|
||||||
|
*/
|
||||||
|
const herbsLocked = computed(() => editForm.herbs.some((h) => (h as HerbRow).locked === true))
|
||||||
|
|
||||||
const slipDietaryText = computed(() => {
|
const slipDietaryText = computed(() => {
|
||||||
const d = slipView.value?.dietary_taboo
|
const d = slipView.value?.dietary_taboo
|
||||||
if (Array.isArray(d)) return d.filter(Boolean).join('、')
|
if (Array.isArray(d)) return d.filter(Boolean).join('、')
|
||||||
@@ -3441,10 +3459,18 @@ const handleImportLibrary = (row: any) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const formulaType = normalizeFormulaType(row.formula_type)
|
const formulaType = normalizeFormulaType(row.formula_type)
|
||||||
const imported = (JSON.parse(JSON.stringify(row.herbs)) as any[]).map((h) => ({
|
// 「禁用修改」模板:导入药材打上锁定标记 → 整张处方锁定(不可增删改,只能再次导入覆盖)
|
||||||
...normalizeHerbRow(h),
|
const isLockedTemplate = Number(row?.disable_edit) === 1
|
||||||
formula_type: formulaType
|
const imported = (JSON.parse(JSON.stringify(row.herbs)) as any[]).map((h) => {
|
||||||
}))
|
const herb = normalizeHerbRow(h)
|
||||||
|
herb.formula_type = formulaType
|
||||||
|
if (isLockedTemplate) {
|
||||||
|
herb.locked = true
|
||||||
|
} else {
|
||||||
|
delete herb.locked
|
||||||
|
}
|
||||||
|
return herb
|
||||||
|
})
|
||||||
if (libraryImportMode.value === 'replace') {
|
if (libraryImportMode.value === 'replace') {
|
||||||
const kept = editForm.herbs.filter((h) => normalizeFormulaType(h.formula_type) !== formulaType)
|
const kept = editForm.herbs.filter((h) => normalizeFormulaType(h.formula_type) !== formulaType)
|
||||||
editForm.herbs = [...kept, ...imported]
|
editForm.herbs = [...kept, ...imported]
|
||||||
@@ -3650,6 +3676,10 @@ async function handlePasteRecipeImport() {
|
|||||||
|
|
||||||
// 添加药材(主方 / 辅方)
|
// 添加药材(主方 / 辅方)
|
||||||
const addHerb = (formulaType: FormulaType = '主方') => {
|
const addHerb = (formulaType: FormulaType = '主方') => {
|
||||||
|
if (herbsLocked.value) {
|
||||||
|
feedback.msgWarning('该处方含「禁用修改」模板,药材已锁定,请重新从处方库导入覆盖')
|
||||||
|
return
|
||||||
|
}
|
||||||
editForm.herbs.push({
|
editForm.herbs.push({
|
||||||
name: '',
|
name: '',
|
||||||
dosage: 0,
|
dosage: 0,
|
||||||
@@ -3659,6 +3689,10 @@ const addHerb = (formulaType: FormulaType = '主方') => {
|
|||||||
|
|
||||||
// 删除药材
|
// 删除药材
|
||||||
const removeHerb = (index: number) => {
|
const removeHerb = (index: number) => {
|
||||||
|
if (herbsLocked.value) {
|
||||||
|
feedback.msgWarning('该处方含「禁用修改」模板,药材已锁定,不可删除')
|
||||||
|
return
|
||||||
|
}
|
||||||
editForm.herbs.splice(index, 1)
|
editForm.herbs.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="禁用修改" min-width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.disable_edit ? 'danger' : 'info'">
|
||||||
|
{{ row.disable_edit ? '已禁用' : '可修改' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="创建人" prop="creator_name" min-width="100" />
|
<el-table-column label="创建人" prop="creator_name" min-width="100" />
|
||||||
<el-table-column label="创建时间" prop="create_time" min-width="160" />
|
<el-table-column label="创建时间" prop="create_time" min-width="160" />
|
||||||
<el-table-column label="操作" width="180" fixed="right">
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
@@ -193,6 +200,21 @@
|
|||||||
勾选后,所有医生都可以查看和使用此处方模板
|
勾选后,所有医生都可以查看和使用此处方模板
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="禁用修改" prop="disable_edit">
|
||||||
|
<div class="flex flex-col gap-1 leading-none">
|
||||||
|
<el-switch
|
||||||
|
v-model="editForm.disable_edit"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
active-text="开启"
|
||||||
|
inactive-text="关闭"
|
||||||
|
/>
|
||||||
|
<div class="text-xs text-gray-400 leading-relaxed">
|
||||||
|
开启后,导入此模板到处方时将锁定整张处方的药材,不可增删改,只能再次导入覆盖
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template #footer v-if="editMode !== 'view'">
|
<template #footer v-if="editMode !== 'view'">
|
||||||
@@ -236,7 +258,8 @@ const editForm = reactive({
|
|||||||
prescription_name: '',
|
prescription_name: '',
|
||||||
formula_type: '主方',
|
formula_type: '主方',
|
||||||
herbs: [] as Array<{ name: string; dosage: number }>,
|
herbs: [] as Array<{ name: string; dosage: number }>,
|
||||||
is_public: 0
|
is_public: 0,
|
||||||
|
disable_edit: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
@@ -293,6 +316,7 @@ const resetForm = () => {
|
|||||||
editForm.formula_type = '主方'
|
editForm.formula_type = '主方'
|
||||||
editForm.herbs = []
|
editForm.herbs = []
|
||||||
editForm.is_public = 0
|
editForm.is_public = 0
|
||||||
|
editForm.disable_edit = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增处方
|
// 新增处方
|
||||||
@@ -310,6 +334,7 @@ const handleView = (row: any) => {
|
|||||||
editForm.formula_type = row.formula_type || '主方'
|
editForm.formula_type = row.formula_type || '主方'
|
||||||
editForm.herbs = row.herbs ? JSON.parse(JSON.stringify(row.herbs)) : []
|
editForm.herbs = row.herbs ? JSON.parse(JSON.stringify(row.herbs)) : []
|
||||||
editForm.is_public = row.is_public ?? 0
|
editForm.is_public = row.is_public ?? 0
|
||||||
|
editForm.disable_edit = row.disable_edit ?? 0
|
||||||
showEdit.value = true
|
showEdit.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,6 +346,7 @@ const handleEdit = (row: any) => {
|
|||||||
editForm.formula_type = row.formula_type || '主方'
|
editForm.formula_type = row.formula_type || '主方'
|
||||||
editForm.herbs = row.herbs ? JSON.parse(JSON.stringify(row.herbs)) : []
|
editForm.herbs = row.herbs ? JSON.parse(JSON.stringify(row.herbs)) : []
|
||||||
editForm.is_public = row.is_public ?? 0
|
editForm.is_public = row.is_public ?? 0
|
||||||
|
editForm.disable_edit = row.disable_edit ?? 0
|
||||||
showEdit.value = true
|
showEdit.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class PrescriptionLibraryLists extends BaseAdminDataLists implements ListsSearch
|
|||||||
public function lists(): array
|
public function lists(): array
|
||||||
{
|
{
|
||||||
$field = [
|
$field = [
|
||||||
'id', 'prescription_name', 'formula_type', 'herbs', 'is_public',
|
'id', 'prescription_name', 'formula_type', 'herbs', 'is_public', 'disable_edit',
|
||||||
'creator_id', 'creator_name', 'create_time', 'update_time'
|
'creator_id', 'creator_name', 'create_time', 'update_time'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -778,6 +778,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
|
|||||||
'export_channel' => '渠道',
|
'export_channel' => '渠道',
|
||||||
'export_guahao_channel_source' => '自媒体渠道(挂号渠道来源)',
|
'export_guahao_channel_source' => '自媒体渠道(挂号渠道来源)',
|
||||||
'export_medication_form' => '药品形态',
|
'export_medication_form' => '药品形态',
|
||||||
|
'export_prescription_name' => '药方名称',
|
||||||
'export_service_package' => '服务套餐',
|
'export_service_package' => '服务套餐',
|
||||||
'export_medication_days' => '天数',
|
'export_medication_days' => '天数',
|
||||||
'export_amount' => '总金额',
|
'export_amount' => '总金额',
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use app\common\model\Order;
|
|||||||
use app\common\model\tcm\Diagnosis;
|
use app\common\model\tcm\Diagnosis;
|
||||||
use app\common\model\tcm\DiagnosisAssignLog;
|
use app\common\model\tcm\DiagnosisAssignLog;
|
||||||
use app\common\model\tcm\Prescription;
|
use app\common\model\tcm\Prescription;
|
||||||
|
use app\common\model\tcm\PrescriptionLibrary;
|
||||||
use app\common\model\tcm\PrescriptionOrder;
|
use app\common\model\tcm\PrescriptionOrder;
|
||||||
use app\common\model\tcm\PrescriptionOrderLog;
|
use app\common\model\tcm\PrescriptionOrderLog;
|
||||||
use app\common\model\tcm\PrescriptionOrderPayOrder;
|
use app\common\model\tcm\PrescriptionOrderPayOrder;
|
||||||
@@ -3106,7 +3107,7 @@ class PrescriptionOrderLogic
|
|||||||
$rxById = [];
|
$rxById = [];
|
||||||
if ($rxIdList !== []) {
|
if ($rxIdList !== []) {
|
||||||
$rxRows = Prescription::whereIn('id', $rxIdList)->whereNull('delete_time')
|
$rxRows = Prescription::whereIn('id', $rxIdList)->whereNull('delete_time')
|
||||||
->field(['id', 'prescription_type', 'need_decoction', 'dose_unit', 'assistant_id', 'appointment_id'])
|
->field(['id', 'prescription_type', 'need_decoction', 'dose_unit', 'assistant_id', 'appointment_id', 'prescription_name', 'aux_usage', 'herbs', 'creator_id'])
|
||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
foreach ($rxRows as $xr) {
|
foreach ($rxRows as $xr) {
|
||||||
@@ -3114,6 +3115,10 @@ class PrescriptionOrderLogic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 药方名称反查:处方库(开方医师 creator_id + 公开模板),按 formula_type + 药材集合匹配,
|
||||||
|
// 复刻前端 resolveSlipAuxLibraryName 口径(主方/辅方均如此;处方记录 prescription_name 仅做兜底)。
|
||||||
|
[$libByDoctor, $libPublic] = self::buildPrescriptionLibraryNameIndexForExport($rxById);
|
||||||
|
|
||||||
if ($needGuahaoChannel) {
|
if ($needGuahaoChannel) {
|
||||||
$yejiChannelHighlightByDiag = [];
|
$yejiChannelHighlightByDiag = [];
|
||||||
if (
|
if (
|
||||||
@@ -3319,6 +3324,22 @@ class PrescriptionOrderLogic
|
|||||||
}
|
}
|
||||||
|
|
||||||
$item['export_medication_form'] = self::formatMedicationFormForExport(\is_array($rx) ? $rx : []);
|
$item['export_medication_form'] = self::formatMedicationFormForExport(\is_array($rx) ? $rx : []);
|
||||||
|
|
||||||
|
// 药方名称:主方/辅方均反查处方库取名称(与处方笺一致),带标签;甘草/无匹配留空
|
||||||
|
[$mainRxName, $auxRxName] = self::resolvePrescriptionNamesForExport(
|
||||||
|
\is_array($rx) ? $rx : [],
|
||||||
|
$libByDoctor,
|
||||||
|
$libPublic
|
||||||
|
);
|
||||||
|
$rxNameParts = [];
|
||||||
|
if ($mainRxName !== '') {
|
||||||
|
$rxNameParts[] = '主方:' . $mainRxName;
|
||||||
|
}
|
||||||
|
if ($auxRxName !== '') {
|
||||||
|
$rxNameParts[] = '辅方:' . $auxRxName;
|
||||||
|
}
|
||||||
|
$item['export_prescription_name'] = implode(' ', $rxNameParts);
|
||||||
|
|
||||||
$item['export_service_package'] = self::formatServicePackageForExport(
|
$item['export_service_package'] = self::formatServicePackageForExport(
|
||||||
$item['service_package'] ?? '',
|
$item['service_package'] ?? '',
|
||||||
$packageNameByValue
|
$packageNameByValue
|
||||||
@@ -3391,6 +3412,186 @@ class PrescriptionOrderLogic
|
|||||||
unset($item);
|
unset($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出药方名称反查:批量加载相关开方医师处方库(creator_id 命中 + 公开模板),
|
||||||
|
* 建立 [creator_id][formula_type][herbKey] => name 与 公开 [formula_type][herbKey] => name 两级索引。
|
||||||
|
*
|
||||||
|
* @param array<int, array> $rxById 处方 id => 处方行(需含 herbs / creator_id)
|
||||||
|
*
|
||||||
|
* @return array{0: array<int, array<string, array<string, string>>>, 1: array<string, array<string, string>>}
|
||||||
|
*/
|
||||||
|
private static function buildPrescriptionLibraryNameIndexForExport(array $rxById): array
|
||||||
|
{
|
||||||
|
$libByDoctor = [];
|
||||||
|
$libPublic = [];
|
||||||
|
if ($rxById === []) {
|
||||||
|
return [$libByDoctor, $libPublic];
|
||||||
|
}
|
||||||
|
|
||||||
|
$doctorIds = [];
|
||||||
|
foreach ($rxById as $rx) {
|
||||||
|
$cid = (int) ($rx['creator_id'] ?? 0);
|
||||||
|
if ($cid > 0) {
|
||||||
|
$doctorIds[$cid] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$doctorIdList = array_keys($doctorIds);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$libRows = PrescriptionLibrary::whereNull('delete_time')
|
||||||
|
->where(function ($q) use ($doctorIdList) {
|
||||||
|
if ($doctorIdList !== []) {
|
||||||
|
$q->whereIn('creator_id', $doctorIdList)->whereOr('is_public', 1);
|
||||||
|
} else {
|
||||||
|
$q->where('is_public', 1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->field(['prescription_name', 'formula_type', 'herbs', 'creator_id', 'is_public'])
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Log::warning('buildPrescriptionLibraryNameIndexForExport failed: ' . $e->getMessage());
|
||||||
|
|
||||||
|
return [$libByDoctor, $libPublic];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($libRows as $lib) {
|
||||||
|
$name = trim((string) ($lib['prescription_name'] ?? ''));
|
||||||
|
if ($name === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$herbsRaw = $lib['herbs'] ?? null;
|
||||||
|
if (\is_string($herbsRaw) && $herbsRaw !== '') {
|
||||||
|
$decoded = json_decode($herbsRaw, true);
|
||||||
|
$herbsRaw = \is_array($decoded) ? $decoded : [];
|
||||||
|
}
|
||||||
|
if (!\is_array($herbsRaw) || $herbsRaw === []) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$key = self::herbSetMatchKeyForExport($herbsRaw);
|
||||||
|
if ($key === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$ft = ((string) ($lib['formula_type'] ?? '')) === '辅方' ? '辅方' : '主方';
|
||||||
|
|
||||||
|
if ((int) ($lib['is_public'] ?? 0) === 1) {
|
||||||
|
$libPublic[$ft][$key] ??= $name;
|
||||||
|
}
|
||||||
|
$cid = (int) ($lib['creator_id'] ?? 0);
|
||||||
|
if ($cid > 0) {
|
||||||
|
$libByDoctor[$cid][$ft][$key] ??= $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$libByDoctor, $libPublic];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反查单张处方的主方 / 辅方名称(与处方笺展示一致):
|
||||||
|
* - 主方:主方药材集合匹配开方医师/公开处方库(formula_type=主方);兜底取处方 prescription_name。
|
||||||
|
* - 辅方:优先 aux_usage.prescription_name / library_name,否则辅方药材集合匹配(formula_type=辅方)。
|
||||||
|
*
|
||||||
|
* @param array $rx 处方行(含 herbs / creator_id / prescription_name / aux_usage)
|
||||||
|
* @param array<int, array<string, array<string, string>>> $libByDoctor
|
||||||
|
* @param array<string, array<string, string>> $libPublic
|
||||||
|
*
|
||||||
|
* @return array{0: string, 1: string} [主方名称, 辅方名称]
|
||||||
|
*/
|
||||||
|
private static function resolvePrescriptionNamesForExport(array $rx, array $libByDoctor, array $libPublic): array
|
||||||
|
{
|
||||||
|
if ($rx === []) {
|
||||||
|
return ['', ''];
|
||||||
|
}
|
||||||
|
|
||||||
|
$doctorId = (int) ($rx['creator_id'] ?? 0);
|
||||||
|
|
||||||
|
$herbs = $rx['herbs'] ?? null;
|
||||||
|
if (\is_string($herbs) && $herbs !== '') {
|
||||||
|
$decoded = json_decode($herbs, true);
|
||||||
|
$herbs = \is_array($decoded) ? $decoded : [];
|
||||||
|
}
|
||||||
|
if (!\is_array($herbs)) {
|
||||||
|
$herbs = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$mainHerbs = [];
|
||||||
|
$auxHerbs = [];
|
||||||
|
foreach ($herbs as $h) {
|
||||||
|
if (!\is_array($h)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (((string) ($h['formula_type'] ?? '')) === '辅方') {
|
||||||
|
$auxHerbs[] = $h;
|
||||||
|
} else {
|
||||||
|
$mainHerbs[] = $h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$lookup = static function (string $ft, array $hs) use ($doctorId, $libByDoctor, $libPublic): string {
|
||||||
|
if ($hs === []) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$key = self::herbSetMatchKeyForExport($hs);
|
||||||
|
if ($key === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if ($doctorId > 0 && isset($libByDoctor[$doctorId][$ft][$key])) {
|
||||||
|
return $libByDoctor[$doctorId][$ft][$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) ($libPublic[$ft][$key] ?? '');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 主方
|
||||||
|
$mainName = $lookup('主方', $mainHerbs);
|
||||||
|
if ($mainName === '') {
|
||||||
|
$mainName = trim((string) ($rx['prescription_name'] ?? ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅方:先读持久化字段
|
||||||
|
$auxName = '';
|
||||||
|
$auxUsage = $rx['aux_usage'] ?? null;
|
||||||
|
if (\is_string($auxUsage) && $auxUsage !== '') {
|
||||||
|
$decodedAux = json_decode($auxUsage, true);
|
||||||
|
$auxUsage = \is_array($decodedAux) ? $decodedAux : null;
|
||||||
|
}
|
||||||
|
if (\is_array($auxUsage)) {
|
||||||
|
$auxName = trim((string) ($auxUsage['prescription_name'] ?? ($auxUsage['library_name'] ?? '')));
|
||||||
|
}
|
||||||
|
if ($auxName === '') {
|
||||||
|
$auxName = $lookup('辅方', $auxHerbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$mainName, $auxName];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 药材集合匹配 key:每味 name:dosage(dosage 规整去尾零)排序后拼接,与处方库反查双方同口径。
|
||||||
|
*/
|
||||||
|
private static function herbSetMatchKeyForExport(array $herbs): string
|
||||||
|
{
|
||||||
|
$parts = [];
|
||||||
|
foreach ($herbs as $h) {
|
||||||
|
if (!\is_array($h)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$name = trim((string) ($h['name'] ?? ''));
|
||||||
|
if ($name === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$dosage = (float) ($h['dosage'] ?? 0);
|
||||||
|
if (floor($dosage) === $dosage) {
|
||||||
|
$dStr = (string) (int) $dosage;
|
||||||
|
} else {
|
||||||
|
$dStr = rtrim(rtrim(number_format($dosage, 4, '.', ''), '0'), '.');
|
||||||
|
}
|
||||||
|
$parts[] = $name . ':' . $dStr;
|
||||||
|
}
|
||||||
|
sort($parts);
|
||||||
|
|
||||||
|
return implode('|', $parts);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 完成订单时把关联诊单的 assistant_id 清空,让患者回到「待分配」状态
|
* 完成订单时把关联诊单的 assistant_id 清空,让患者回到「待分配」状态
|
||||||
* 仅当该患者没有其它进行中的处方订单且无指派日志时才清空,避免误覆盖
|
* 仅当该患者没有其它进行中的处方订单且无指派日志时才清空,避免误覆盖
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ class PrescriptionLibraryValidate extends BaseValidate
|
|||||||
'prescription_name' => 'require|max:100',
|
'prescription_name' => 'require|max:100',
|
||||||
'formula_type' => 'in:主方,辅方',
|
'formula_type' => 'in:主方,辅方',
|
||||||
'herbs' => 'require|array',
|
'herbs' => 'require|array',
|
||||||
'is_public' => 'in:0,1'
|
'is_public' => 'in:0,1',
|
||||||
|
'disable_edit' => 'in:0,1'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $message = [
|
protected $message = [
|
||||||
@@ -27,7 +28,8 @@ class PrescriptionLibraryValidate extends BaseValidate
|
|||||||
'formula_type.in' => '处方类型只能是主方或辅方',
|
'formula_type.in' => '处方类型只能是主方或辅方',
|
||||||
'herbs.require' => '药材列表不能为空',
|
'herbs.require' => '药材列表不能为空',
|
||||||
'herbs.array' => '药材列表格式错误',
|
'herbs.array' => '药材列表格式错误',
|
||||||
'is_public.in' => '是否公开参数错误'
|
'is_public.in' => '是否公开参数错误',
|
||||||
|
'disable_edit.in' => '禁用修改参数错误'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +37,7 @@ class PrescriptionLibraryValidate extends BaseValidate
|
|||||||
*/
|
*/
|
||||||
public function sceneAdd()
|
public function sceneAdd()
|
||||||
{
|
{
|
||||||
return $this->only(['prescription_name', 'formula_type', 'herbs', 'is_public']);
|
return $this->only(['prescription_name', 'formula_type', 'herbs', 'is_public', 'disable_edit']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,7 +45,7 @@ class PrescriptionLibraryValidate extends BaseValidate
|
|||||||
*/
|
*/
|
||||||
public function sceneEdit()
|
public function sceneEdit()
|
||||||
{
|
{
|
||||||
return $this->only(['id', 'prescription_name', 'formula_type', 'herbs', 'is_public']);
|
return $this->only(['id', 'prescription_name', 'formula_type', 'herbs', 'is_public', 'disable_edit']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- 处方库:禁用修改(导入处方后锁定药材,不可增删改,只能再次导入覆盖)
|
||||||
|
ALTER TABLE `zyt_prescription_library`
|
||||||
|
ADD COLUMN `disable_edit` tinyint(1) NOT NULL DEFAULT 0 COMMENT '导入处方后是否禁止修改/删除药材:0否 1是' AFTER `is_public`;
|
||||||
Reference in New Issue
Block a user