Compare commits

..
37 Commits
Author SHA1 Message Date
Your Name 0fb51e12d1 更新 2026-05-19 10:18:00 +08:00
Your Name 4f9494db0b Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-18 18:12:23 +08:00
Your Name 4e87b080a0 更新 2026-05-18 18:12:04 +08:00
long 2f3038aba1 Merge branch '20260518-long' 2026-05-18 18:08:46 +08:00
long 131fb7d9c7 Update edit.vue
增加:账户消耗列表-编辑可以修改自媒体
2026-05-18 18:08:35 +08:00
Your Name 762a724204 Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-18 18:02:15 +08:00
long 8090e0aab3 Merge branch '20260518-long' 2026-05-18 17:43:25 +08:00
long 9df6330d41 update
修改未服务天数判断条件
2026-05-18 17:42:24 +08:00
Your Name fd63e23eaf 更新 2026-05-18 16:56:00 +08:00
gr c1143f4629 geng
Merge branch 'master' of https://gitee.com/v_cms/zyt
2026-05-18 16:07:03 +08:00
Your Name 149fdffd49 更新 2026-05-18 15:59:22 +08:00
Your Name 439d5a3ec9 更新 2026-05-18 15:57:09 +08:00
long 9e24d49210 Merge branch '20260518-long' 2026-05-18 14:24:52 +08:00
long 90ac43fc82 update
更新自媒体渠道标签
2026-05-18 14:24:41 +08:00
gr 8b6b709987 Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-18 11:36:21 +08:00
Your Name fb6ca9ce85 更新 2026-05-18 11:23:01 +08:00
Your Name 08290b329e 更新 2026-05-18 11:20:24 +08:00
long 1d66f84bd3 Update PatientOrderList.vue
业务订单增加:服务套餐
2026-05-18 10:16:31 +08:00
Your Name a2d9c1a03f Merge branch 'chufan-2026-5-16' 2026-05-18 09:43:48 +08:00
Your Name d79db88349 更新 2026-05-18 09:42:11 +08:00
Your Name 9f5fb650af 新增功能 2026-05-16 16:08:54 +08:00
Your Name 15b4339c90 更新 2026-05-16 16:05:29 +08:00
gr 5ce331394d Merge branch 'master' of https://gitee.com/v_cms/zyt
你好
2026-05-14 16:27:49 +08:00
Your Name 7ba9dabdb4 更新 2026-05-14 16:26:27 +08:00
Your Name 611f3dcd5c Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-14 16:23:52 +08:00
Your Name d3388b160e 更新 2026-05-14 16:23:29 +08:00
long f83d4c06cb Merge branch 'long-20260514' 2026-05-14 16:22:38 +08:00
long 4941ea3e21 Update DailyMatrix.vue
更新血糖折线图显示
2026-05-14 15:54:30 +08:00
Your Name e35696e153 更新 2026-05-14 15:34:28 +08:00
gr 800c6af7f1 Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-14 11:31:40 +08:00
Your Name e1df584ed5 更新 2026-05-14 11:25:48 +08:00
gr 876ef0f8a0 Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-14 11:02:29 +08:00
gr fdcfa30810 Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-12 18:15:10 +08:00
gr 4caa98af3a Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-12 11:27:37 +08:00
gr bb87e4fb4c Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-12 10:59:56 +08:00
gr 039105580c Mergt branch 'master' of https://gitee.com/v_cms/zyt 2026-05-11 17:49:51 +08:00
gr f47f431bdf 更新 2026-05-11 17:49:38 +08:00
5885 changed files with 1903 additions and 419 deletions
+5
View File
@@ -71,6 +71,11 @@ export function appointmentAdminEdit(params: any) {
return request.post({ url: '/doctor.appointment/edit', params })
}
/** 批量修改挂号渠道来源(与 edit 共用 doctor.appointment/edit 权限) */
export function appointmentBatchEditChannel(params: any) {
return request.post({ url: '/doctor.appointment/batchEditChannel', params })
}
// 获取挂号详情
export function appointmentDetail(params: any) {
return request.get({ url: '/doctor.appointment/detail', params })
+15
View File
@@ -319,6 +319,16 @@ export function prescriptionEdit(params: any) {
return request.post({ url: '/tcm.prescription/edit', params })
}
/** 仅修正处方笺患者姓名、手机号与性别(不改审核状态),写入业务订单日志表 */
export function prescriptionPatchPatient(params: {
id: number
patient_name: string
phone: string
gender: number
}) {
return request.post({ url: '/tcm.prescription/patchPatient', params })
}
// 删除处方
export function prescriptionDelete(params: { id: number }) {
return request.post({ url: '/tcm.prescription/delete', params })
@@ -490,6 +500,11 @@ export function prescriptionOrderUpdateAmount(params: { id: number; amount: numb
return request.post({ url: '/tcm.prescriptionOrder/updateAmount', params })
}
/** 设置发货类型:gancao 甘草药房 / direct 洛阳药房 */
export function prescriptionOrderSetShipMode(params: { id: number; ship_mode: 'gancao' | 'direct' }) {
return request.post({ url: '/tcm.prescriptionOrder/setShipMode', params })
}
// ========== 处方库 ==========
// 处方库列表
@@ -26,6 +26,22 @@
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="医助">
<el-select
v-model="queryParams.assistant_id"
placeholder="全部"
clearable
filterable
class="!w-[180px]"
>
<el-option
v-for="a in assistantOptions"
:key="a.id"
:label="a.name + (a.account ? ` (${a.account})` : '')"
:value="a.id"
/>
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="queryParams.status" placeholder="全部" clearable class="!w-[130px]">
<el-option label="已预约" :value="1" />
@@ -34,6 +50,22 @@
<el-option label="已过号" :value="4" />
</el-select>
</el-form-item>
<el-form-item label="渠道">
<el-select
v-model="queryParams.channel_source"
placeholder="全部"
clearable
filterable
class="!w-[200px]"
>
<el-option
v-for="item in channelOptions"
:key="String(item.value)"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetFilter">重置</el-button>
@@ -42,7 +74,29 @@
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<el-table v-loading="pager.loading" :data="pager.lists" size="large" stripe>
<div class="flex flex-wrap items-center gap-3 mb-4">
<el-button
v-perms="['doctor.appointment/edit']"
type="primary"
:disabled="selectedRows.length === 0"
@click="openBatchChannelDialog"
>
批量修改渠道
</el-button>
<span v-if="selectedRows.length > 0" class="text-sm text-gray-500">
已选 {{ selectedRows.length }}
</span>
</div>
<el-table
ref="tableRef"
v-loading="pager.loading"
row-key="id"
:data="pager.lists"
size="large"
stripe
@selection-change="onSelectionChange"
>
<el-table-column type="selection" width="48" align="center" reserve-selection />
<el-table-column label="ID" prop="id" width="72" align="center" />
<el-table-column label="诊单/患者" min-width="140">
<template #default="{ row }">
@@ -190,13 +244,55 @@
<el-button type="primary" :loading="editSaving" @click="submitEdit">保存</el-button>
</template>
</el-dialog>
<el-dialog
v-model="batchChannelVisible"
title="批量修改渠道"
width="520px"
destroy-on-close
@closed="resetBatchChannelForm"
>
<p class="text-sm text-gray-600 mb-4">将对已选 {{ selectedRows.length }} 条挂号写入同一渠道来源仅改渠道不改其它字段</p>
<el-form :model="batchChannelForm" label-width="96px">
<el-form-item label="渠道来源" required>
<el-select
v-model="batchChannelForm.channel_source"
placeholder="请选择渠道来源"
filterable
class="!w-full"
@change="onBatchChannelSourceChange"
>
<el-option
v-for="item in channelOptions"
:key="String(item.value)"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-if="needsBatchChannelSourceDetail" label="自媒体补充" required>
<el-input
v-model="batchChannelForm.channel_source_detail"
maxlength="128"
show-word-limit
placeholder="请输入自媒体相关补充内容"
clearable
class="!w-full"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="batchChannelVisible = false">取消</el-button>
<el-button type="primary" :loading="batchChannelSaving" @click="submitBatchChannel">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup name="consumerPrescriptionGuahao">
import DaterangePicker from '@/components/daterange-picker/index.vue'
import { getDictData } from '@/api/app'
import { appointmentAdminEdit, appointmentLists } from '@/api/doctor'
import { appointmentAdminEdit, appointmentBatchEditChannel, appointmentLists } from '@/api/doctor'
import { getAssistants } from '@/api/tcm'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
@@ -206,10 +302,20 @@ const queryParams = reactive({
end_date: '',
patient_name: '',
doctor_name: '',
status: '' as number | ''
assistant_id: undefined as number | undefined,
status: '' as number | '',
channel_source: '' as string
})
const queryInit = { ...queryParams }
const queryInit = {
start_date: '',
end_date: '',
patient_name: '',
doctor_name: '',
assistant_id: undefined as number | undefined,
status: '' as number | '',
channel_source: ''
}
const { pager, getLists, resetPage } = usePaging({
fetchFun: appointmentLists,
@@ -218,6 +324,13 @@ const { pager, getLists, resetPage } = usePaging({
const assistantOptions = ref<Array<{ id: number; name: string; account?: string }>>([])
const tableRef = ref<{ clearSelection?: () => void } | null>(null)
const selectedRows = ref<Record<string, unknown>[]>([])
function onSelectionChange(rows: Record<string, unknown>[]) {
selectedRows.value = rows
}
/** 与诊单预约弹窗一致:这些字典 name 需填「自媒体补充」 */
const CHANNEL_NAMES_REQUIRING_SELF_MEDIA_DETAIL = new Set([
'自媒体4H',
@@ -242,6 +355,78 @@ const selectedChannelDictName = computed(() => {
const needsChannelSourceDetail = computed(() => channelNameRequiresSelfMediaDetail(selectedChannelDictName.value))
const batchSelectedChannelDictName = computed(() => {
const v = batchChannelForm.channel_source
if (v === '' || v == null) return ''
const row = channelOptions.value.find((item: { value: string }) => String(item.value) === String(v))
return row ? String(row.name ?? '').trim() : ''
})
const needsBatchChannelSourceDetail = computed(() =>
channelNameRequiresSelfMediaDetail(batchSelectedChannelDictName.value)
)
function onBatchChannelSourceChange(val: string) {
const row = channelOptions.value.find((item: { value: string }) => String(item.value) === String(val))
const name = row ? String(row.name ?? '').trim() : ''
if (!channelNameRequiresSelfMediaDetail(name)) {
batchChannelForm.channel_source_detail = ''
}
}
const batchChannelVisible = ref(false)
const batchChannelSaving = ref(false)
const batchChannelForm = reactive({
channel_source: '' as string,
channel_source_detail: '' as string
})
function openBatchChannelDialog() {
if (selectedRows.value.length === 0) {
feedback.msgWarning('请先勾选挂号记录')
return
}
batchChannelForm.channel_source = ''
batchChannelForm.channel_source_detail = ''
batchChannelVisible.value = true
}
function resetBatchChannelForm() {
batchChannelForm.channel_source = ''
batchChannelForm.channel_source_detail = ''
}
async function submitBatchChannel() {
if (selectedRows.value.length === 0) {
feedback.msgWarning('请先勾选挂号记录')
return
}
if (!batchChannelForm.channel_source) {
feedback.msgError('请选择渠道来源')
return
}
if (needsBatchChannelSourceDetail.value && !batchChannelForm.channel_source_detail.trim()) {
feedback.msgError('请填写自媒体补充说明')
return
}
batchChannelSaving.value = true
try {
const ids = selectedRows.value.map((r) => Number(r.id))
await appointmentBatchEditChannel({
ids,
channel_source: batchChannelForm.channel_source,
channel_source_detail: batchChannelForm.channel_source_detail.trim()
})
feedback.msgSuccess('批量修改成功')
batchChannelVisible.value = false
tableRef.value?.clearSelection?.()
selectedRows.value = []
getLists()
} finally {
batchChannelSaving.value = false
}
}
function onChannelSourceChange(val: string) {
const row = channelOptions.value.find((item: { value: string }) => String(item.value) === String(val))
const name = row ? String(row.name ?? '').trim() : ''
@@ -216,6 +216,15 @@
<el-button type="primary" link @click="handleView(row)" v-perms="['cf.prescription/read']">
查看
</el-button>
<el-button
v-if="Number(row.void_status) !== 1"
type="primary"
link
v-perms="['tcm.prescription/patchPatient']"
@click="openPatchPatientDialog(row)"
>
改姓名手机
</el-button>
<el-button
v-if="!Number(row.has_prescription_order) && Number(row.void_status) !== 1"
type="success"
@@ -980,6 +989,48 @@
</template>
</el-drawer>
<!-- 修正处方笺姓名 / 手机号(zyt_tcm_prescription,写入订单日志) -->
<el-dialog
v-model="patchPatientVisible"
title="修正姓名、性别与手机号"
width="440px"
:close-on-click-modal="false"
destroy-on-close
@closed="resetPatchPatientForm"
>
<el-form
ref="patchPatientFormRef"
:model="patchPatientForm"
:rules="patchPatientRules"
label-width="88px"
>
<el-form-item label="处方编号">
<span class="text-gray-700">#{{ patchPatientForm.id || '—' }}</span>
</el-form-item>
<el-form-item label="患者姓名" prop="patient_name">
<el-input v-model="patchPatientForm.patient_name" maxlength="50" show-word-limit placeholder="处方笺展示姓名" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="patchPatientForm.gender">
<el-radio :label="1">男</el-radio>
<el-radio :label="0">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="patchPatientForm.phone" maxlength="20" placeholder="处方笺展示手机号" />
</el-form-item>
</el-form>
<p class="text-xs text-gray-500 -mt-2 mb-2">
仅更新处方表 patient_name、gender、phone,不改变审核状态;记录写入业务订单操作日志(有关联订单时可在此订单日志中查看)。
</p>
<template #footer>
<el-button @click="patchPatientVisible = false">取消</el-button>
<el-button type="primary" :loading="patchPatientSubmitLoading" @click="submitPatchPatient">
保存
</el-button>
</template>
</el-dialog>
<!-- 从消费者处方创建业务订单(zyt_tcm_prescription_order,与支付单 zyt_order 分离) -->
<el-dialog
v-model="createOrderVisible"
@@ -1444,6 +1495,7 @@ import {
prescriptionLists,
prescriptionAdd,
prescriptionEdit,
prescriptionPatchPatient,
prescriptionDelete,
prescriptionAudit,
prescriptionDetail,
@@ -1531,6 +1583,66 @@ const auditTargetId = ref(0)
const auditRemark = ref('')
const auditLoading = ref(false)
/** 修正处方笺显示用姓名 / 手机号 */
const patchPatientVisible = ref(false)
const patchPatientSubmitLoading = ref(false)
const patchPatientFormRef = ref<FormInstance>()
const patchPatientForm = reactive({
id: 0,
patient_name: '',
gender: 1 as 0 | 1,
phone: ''
})
const patchPatientRules: FormRules = {
patient_name: [{ required: true, message: '请输入患者姓名', trigger: 'blur' }],
gender: [{ required: true, message: '请选择性别', trigger: 'change' }],
phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }]
}
function openPatchPatientDialog(row: Record<string, unknown>) {
patchPatientForm.id = Number(row.id) || 0
patchPatientForm.patient_name = String(row.patient_name ?? '').trim()
const g = Number(row.gender)
patchPatientForm.gender = g === 0 || g === 1 ? (g as 0 | 1) : 1
patchPatientForm.phone = String(row.phone ?? '').trim()
patchPatientVisible.value = true
}
function resetPatchPatientForm() {
patchPatientForm.id = 0
patchPatientForm.patient_name = ''
patchPatientForm.gender = 1
patchPatientForm.phone = ''
patchPatientFormRef.value?.clearValidate()
}
async function submitPatchPatient() {
const form = patchPatientFormRef.value
if (!form) return
try {
await form.validate()
} catch {
return
}
patchPatientSubmitLoading.value = true
try {
await prescriptionPatchPatient({
id: patchPatientForm.id,
patient_name: patchPatientForm.patient_name.trim(),
phone: patchPatientForm.phone.trim(),
gender: patchPatientForm.gender
})
feedback.msgSuccess('已保存')
patchPatientVisible.value = false
getLists()
} catch (e: unknown) {
const msg = e && typeof e === 'object' && 'msg' in e ? String((e as { msg?: string }).msg) : ''
feedback.msgError(msg || '保存失败')
} finally {
patchPatientSubmitLoading.value = false
}
}
/** 从消费者处方创建订单 */
const createOrderVisible = ref(false)
/** 创建订单分步向导:0 患者与收货 / 1 服务与支付单 / 2 金额与确认 */
@@ -263,6 +263,11 @@
/>
</el-select>
</el-form-item>
<el-form-item class="w-[160px]" label="服务渠道">
<el-select v-model="queryParams.service_channel" clearable placeholder="全部" class="!w-full">
<el-option label="未指派" value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="handleReset">重置</el-button>
@@ -272,7 +277,7 @@
:fetch-fun="prescriptionOrderExport"
:params="prescriptionOrderExportParams"
:page-size="pager.size"
export-hint="导出范围与上方筛选一致(履约状态、创建时间及其他条件均会生效)。"
export-hint="导出范围与上方筛选一致(履约状态、创建时间及其他条件均会生效)。含「自媒体渠道(挂号渠道来源)」:优先取该单关联处方登记的挂号;无则诊单下同患者挂号取 id 最大的一条(与前台挂号选择的记录一致);业绩侧栏带渠道筛选导出时与同页列表高亮挂号同源。"
/>
</el-form-item>
</el-form>
@@ -557,6 +562,28 @@
round
class="ml-2"
>甘草 {{ detailData.gancao_reciperl_order_no }}</el-tag>
<div v-if="detailData" class="flex items-center gap-2 ml-4 shrink-0">
<span class="text-sm text-gray-500">发货类型</span>
<el-radio-group
v-perms="['tcm.prescriptionOrder/setShipMode']"
:model-value="normalizeShipMode(detailData.ship_mode)"
size="small"
:disabled="shipModeSaving || !canEditShipMode(detailData)"
@change="onDetailShipModeChange"
>
<el-radio-button label="gancao">甘草药房</el-radio-button>
<el-radio-button
label="direct"
:disabled="isShipModeLockedToGancao(detailData)"
>洛阳药房</el-radio-button>
</el-radio-group>
<el-tag
v-if="!hasSetShipModePerm"
:type="normalizeShipMode(detailData.ship_mode) === 'direct' ? 'warning' : 'success'"
effect="plain"
round
>{{ shipModeLabel(detailData.ship_mode) }}</el-tag>
</div>
</div>
<div v-if="detailData" class="flex items-center gap-2 mr-6">
<el-button
@@ -1377,7 +1404,7 @@
<!-- 编辑分步向导与创建业务订单弹窗统一 -->
<el-dialog
v-model="editVisible"
title="编辑业务订单"
:title="editGancaoLogisticsOnlyMode ? '修改物流信息(甘草订单)' : '编辑业务订单'"
width="940px"
top="4vh"
:close-on-click-modal="false"
@@ -1400,18 +1427,33 @@
</el-tooltip>
</div>
<el-steps
:active="editOrderStep"
finish-status="success"
align-center
class="create-order-steps"
<el-alert
v-if="editGancaoLogisticsOnlyMode"
type="info"
:closable="false"
show-icon
class="mb-4"
title="订单已提交甘草,仅可修改快递单号与承运商;地址、金额等变更请先走取消流程。"
>
<el-step title="患者与收货" description="诊单与物流地址" />
<el-step title="服务与支付单" description="套餐与关联收款" />
<el-step title="金额与确认" description="费用与备注" />
</el-steps>
<template v-if="editGancaoDisplayNo" #default>
<div class="text-sm text-gray-700 mt-1">甘草处方单号{{ editGancaoDisplayNo }}</div>
</template>
</el-alert>
<p class="create-order-step-lead">{{ editOrderStepLead }}</p>
<template v-if="!editGancaoLogisticsOnlyMode">
<el-steps
:active="editOrderStep"
finish-status="success"
align-center
class="create-order-steps"
>
<el-step title="患者与收货" description="诊单与物流地址" />
<el-step title="服务与支付单" description="套餐与关联收款" />
<el-step title="金额与确认" description="费用与备注" />
</el-steps>
<p class="create-order-step-lead">{{ editOrderStepLead }}</p>
</template>
<el-form
ref="editFormRef"
@@ -1420,6 +1462,24 @@
label-width="108px"
class="create-order-form"
>
<template v-if="editGancaoLogisticsOnlyMode">
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="物流设置">
<div class="flex gap-2 w-full">
<el-select v-model="editForm.express_company" placeholder="承运商" class="w-[140px] shrink-0">
<el-option label="自动识别" value="auto" />
<el-option label="顺丰速运" value="sf" />
<el-option label="京东快递" value="jd" />
<el-option label="极兔速递" value="jt" />
</el-select>
<el-input v-model="editForm.tracking_number" maxlength="80" placeholder="快递单号" class="flex-1 min-w-0" />
</div>
</el-form-item>
</el-col>
</el-row>
</template>
<template v-if="!editGancaoLogisticsOnlyMode">
<div v-show="editOrderStep === 0" class="create-order-step-panel">
<el-row :gutter="20">
<el-col :span="12">
@@ -1566,7 +1626,17 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="服务渠道">
<el-input v-model="editForm.service_channel" placeholder="可选" maxlength="100" />
<el-select
v-model="editForm.service_channel"
class="w-full"
filterable
allow-create
default-first-option
clearable
placeholder="可选或自定义输入"
>
<el-option label="未指派" value="0" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
@@ -1743,12 +1813,13 @@
</el-col>
</el-row>
</div>
</template>
</el-form>
</div>
<template #footer>
<div class="create-order-footer">
<div class="create-order-footer__hint">
<div v-if="!editGancaoLogisticsOnlyMode" class="create-order-footer__hint">
<span class="create-order-footer__step"> {{ editOrderStep + 1 }} / 3 </span>
<span v-if="editOrderStep === 2 && editDepositMin > 0" class="create-order-footer__warn">
订单金额与关联支付单合计须 ¥{{ formatMoney(editDepositMin) }}
@@ -1756,17 +1827,19 @@
</div>
<div class="create-order-footer__actions">
<el-button size="large" @click="editVisible = false">取消</el-button>
<el-button v-if="editOrderStep > 0" size="large" @click="goEditOrderPrevStep">上一步</el-button>
<template v-if="!editGancaoLogisticsOnlyMode">
<el-button v-if="editOrderStep > 0" size="large" @click="goEditOrderPrevStep">上一步</el-button>
<el-button
v-if="editOrderStep < 2"
type="primary"
size="large"
@click="goEditOrderNextStep"
>
下一步
</el-button>
</template>
<el-button
v-if="editOrderStep < 2"
type="primary"
size="large"
@click="goEditOrderNextStep"
>
下一步
</el-button>
<el-button
v-if="editOrderStep === 2"
v-if="editGancaoLogisticsOnlyMode || editOrderStep === 2"
type="primary"
size="large"
:loading="editSaving"
@@ -1874,10 +1947,12 @@
/>
<el-form v-loading="shipSaving" label-width="90px" class="pr-2" @submit.prevent="submitShip">
<el-form-item label="发货方式">
<el-radio-group v-model="shipForm.ship_mode">
<el-radio label="gancao">甘草药方发</el-radio>
<el-radio label="direct">药房直发</el-radio>
</el-radio-group>
<el-tag
:type="normalizeShipMode(shipForm.ship_mode) === 'direct' ? 'warning' : 'success'"
effect="plain"
size="default"
>{{ shipDialogModeDisplay }}</el-tag>
<span class="text-xs text-gray-400 ml-2">请在订单详情顶部发货类型中设置此处不可修改</span>
</el-form-item>
<el-form-item label="承运商">
<el-select v-model="shipForm.express_company" class="w-full">
@@ -2295,7 +2370,7 @@
<p v-if="rxPharmacyRemarkText" class="rx-text-warn">
药房备注{{ rxPharmacyRemarkText }}
</p>
<p v-if="rxOutPelletText" class="rx-text-warn">
<p v-if="rxOutPelletText && prescriptionViewData?.prescription_type !== '饮片'" class="rx-text-warn">
出丸{{ rxOutPelletText }}
</p>
</div>
@@ -2520,6 +2595,7 @@ import {
prescriptionOrderShip,
prescriptionOrderLogs,
prescriptionOrderUpdateAmount,
prescriptionOrderSetShipMode,
prescriptionOrderAddPayOrder,
prescriptionOrderComplete,
prescriptionOrderRevokeRxAudit,
@@ -2798,6 +2874,8 @@ const queryParams = reactive({
payment_slip_audit_status: '' as number | '',
/** 供货方式:甘草(已传甘草药方单号)/ 自营(无甘草单号) */
supply_mode: '' as '' | 'gancao' | 'self',
/** 服务渠道:'' 不限;'0' 未指派(库内 '' 或 '0' */
service_channel: '' as '' | '0',
/** 列表排除履约已取消(4):重点看板「待处方审核」等用 */
exclude_fulfillment_cancelled: 0 as number
})
@@ -2914,6 +2992,12 @@ function normalizePrescriptionOrderListQuery(params: Record<string, unknown>): R
if (!String(p.patient_keyword || '').trim()) delete p.patient_keyword
if (!String(p.express_keyword || '').trim()) delete p.express_keyword
if (!p.express_company || p.express_company === '') delete p.express_company
if (p.service_channel === '' || p.service_channel === undefined || p.service_channel === null) {
delete p.service_channel
} else {
p.service_channel = String(p.service_channel).trim()
if (p.service_channel === '') delete p.service_channel
}
if (Number(p.exclude_fulfillment_cancelled) !== 1) delete p.exclude_fulfillment_cancelled
if (!String(p.start_time || '').trim() || !String(p.end_time || '').trim()) {
delete p.start_time
@@ -3131,6 +3215,7 @@ function handleReset() {
queryParams.prescription_audit_status = ''
queryParams.payment_slip_audit_status = ''
queryParams.supply_mode = ''
queryParams.service_channel = ''
queryParams.exclude_fulfillment_cancelled = 0
resetParams()
}
@@ -3234,14 +3319,21 @@ function canEditRow(row: {
gancao_reciperl_order_no?: string | null
gancao_submit_time?: number | null
}) {
// (5)(6)(3)(4)
const fs = Number(row.fulfillment_status)
if (fs !== 1 && fs !== 2) return false
// > 0
// (3)(4)
if (fs === 3 || fs === 4) return false
const gcNo = String(row.gancao_reciperl_order_no || '').trim()
const gcTime = Number(row.gancao_submit_time || 0)
if (gcNo !== '' || gcTime > 0) return false
return true
const gcLocked = gcNo !== '' || gcTime > 0
// /// 6 edit
if (gcLocked) {
return [1, 2, 5, 7].includes(fs)
}
// (1)(2)
return fs === 1 || fs === 2
}
function canRxAudit(row: { prescription_audit_status?: number; fulfillment_status?: number }) {
@@ -3297,6 +3389,70 @@ function canShipRow(row: { fulfillment_status?: number }) {
return Number(row.fulfillment_status) === 2
}
type ShipMode = 'gancao' | 'direct'
const hasSetShipModePerm = computed(() => {
const p = userStore.perms || []
return p.includes('*') || p.includes('tcm.prescriptionOrder/setShipMode')
})
function normalizeShipMode(v: unknown): ShipMode {
return String(v || '').toLowerCase() === 'direct' ? 'direct' : 'gancao'
}
function shipModeLabel(v: unknown): string {
return normalizeShipMode(v) === 'direct' ? '洛阳药房' : '甘草药房'
}
function isShipModeLockedToGancao(row: { gancao_reciperl_order_no?: string | null }) {
return String(row.gancao_reciperl_order_no || '').trim() !== ''
}
function canEditShipMode(row: { fulfillment_status?: number }) {
const fs = Number(row.fulfillment_status)
return fs !== 3 && fs !== 4
}
const shipModeSaving = ref(false)
function isSamePrescriptionOrderId(a: unknown, b: unknown) {
const na = Number(a)
const nb = Number(b)
return na > 0 && na === nb
}
const shipDialogModeDisplay = computed(() => {
return normalizeShipMode(shipForm.ship_mode) === 'direct' ? '洛阳药房直发' : '甘草药房直发'
})
async function onDetailShipModeChange(mode: string | number | boolean | undefined) {
const row = detailData.value
if (!row?.id) return
const next = normalizeShipMode(mode)
const prev = normalizeShipMode(row.ship_mode)
if (next === prev) return
if (!canEditShipMode(row)) {
feedback.msgWarning('当前订单状态不可修改发货类型')
return
}
shipModeSaving.value = true
try {
await prescriptionOrderSetShipMode({ id: row.id, ship_mode: next })
if (detailData.value) detailData.value.ship_mode = next
if (shipVisible.value && isSamePrescriptionOrderId(shipRowId.value, row.id)) {
shipForm.ship_mode = next
}
await refreshCurrentPrescriptionOrderDetail()
feedback.msgSuccess('发货类型已保存')
getLists()
void fetchLogs(row.id)
} catch {
/* 拦截器已提示 */
} finally {
shipModeSaving.value = false
}
}
function canAddPayOrderRow(row: { fulfillment_status?: number }) {
// (5) / (6)
const fs = Number(row.fulfillment_status)
@@ -3310,9 +3466,8 @@ function canCompleteRow(row: { fulfillment_status?: number; payment_slip_audit_s
}
function canQuickTrackRow(row: { fulfillment_status?: number }) {
// (5) / (6) 使
const fs = Number(row.fulfillment_status)
return fs === 5 || fs === 6
// (5) (6)
return Number(row.fulfillment_status) === 5
}
function canUpdateAmount(row: { id?: number; fulfillment_status?: number } | null | undefined) {
@@ -3948,6 +4103,10 @@ const editSaving = ref(false)
const editOrderStep = ref(0)
/** 顶部「关联处方」卡片数据(来自业务订单详情中的 prescription */
const editOrderPrescription = ref<Record<string, any> | null>(null)
/** 甘草 SCM 已提交:弹窗仅展示并提交快递单号与承运商 */
const editGancaoLogisticsOnlyMode = ref(false)
/** 用于提示文案展示甘草处方单号 */
const editGancaoDisplayNo = ref('')
const editOrderStepLead = computed(() => {
const texts = [
@@ -4126,6 +4285,8 @@ const editRules = computed<FormRules>(() => {
function resetEditOrderDialog() {
editOrderStep.value = 0
editOrderPrescription.value = null
editGancaoLogisticsOnlyMode.value = false
editGancaoDisplayNo.value = ''
editFormRef.value?.clearValidate()
}
@@ -4245,7 +4406,12 @@ async function openEdit(row: { id: number }) {
editForm.pay_order_ids = Array.isArray(pids) ? pids.map((x: unknown) => Number(x)).filter((n) => !Number.isNaN(n)) : []
editForm.internal_cost =
d.internal_cost != null && d.internal_cost !== '' ? Number(d.internal_cost) : undefined
const gcNo = String(d.gancao_reciperl_order_no || '').trim()
const gcTime = Number(d.gancao_submit_time || 0)
editGancaoLogisticsOnlyMode.value = gcNo !== '' || gcTime > 0
editGancaoDisplayNo.value = gcNo || ''
await loadEditPaidOrders(editForm.diagnosis_id, editForm.id)
// BUG FIX: NextTick
@@ -4261,8 +4427,14 @@ async function openEdit(row: { id: number }) {
}
async function submitEdit() {
if (!editFormRef.value || editOrderStep.value !== 2) return
await editFormRef.value.validate()
if (!editFormRef.value) return
const gancaoLogisticsOnly = editGancaoLogisticsOnlyMode.value
if (!gancaoLogisticsOnly && editOrderStep.value !== 2) return
if (!gancaoLogisticsOnly) {
await editFormRef.value.validate()
} else {
editFormRef.value.clearValidate()
}
editSaving.value = true
try {
const payload: Record<string, unknown> = {
@@ -4634,8 +4806,8 @@ async function submitQuickTrack() {
if (nd) detailData.value = nd
} catch { /* 静默 */ }
}
//
if (canShipRow({ fulfillment_status: 2, tracking_number: quickTrackForm.tracking_number })) {
// (2)(5)/(6)
if (canShipRow({ fulfillment_status: Number(d.fulfillment_status) })) {
try {
await ElMessageBox.confirm(
`快递单号「${quickTrackForm.tracking_number}」已保存,是否立即确认发货?`,
@@ -4662,14 +4834,31 @@ const shipForm = reactive({
tracking_number: ''
})
function resolveShipModeForRow(row: { id: number; ship_mode?: unknown }) {
if (isSamePrescriptionOrderId(detailData.value?.id, row.id)) {
return normalizeShipMode(detailData.value!.ship_mode)
}
return normalizeShipMode(row.ship_mode)
}
function openShip(row: { id: number; express_company?: unknown; tracking_number?: unknown; ship_mode?: unknown }) {
shipRowId.value = row.id
shipForm.ship_mode = String(row.ship_mode || 'gancao') || 'gancao'
shipRowId.value = Number(row.id)
shipForm.ship_mode = resolveShipModeForRow(row)
shipForm.express_company = String(row.express_company || 'auto') || 'auto'
shipForm.tracking_number = String(row.tracking_number || '')
shipVisible.value = true
}
watch(
() => detailData.value?.ship_mode,
(v) => {
if (!shipVisible.value || !shipRowId.value || !isSamePrescriptionOrderId(detailData.value?.id, shipRowId.value)) {
return
}
shipForm.ship_mode = normalizeShipMode(v)
}
)
async function submitShip() {
if (!shipForm.tracking_number.trim()) {
feedback.msgError('请先填写快递单号再确认发货')
@@ -4679,7 +4868,7 @@ async function submitShip() {
try {
await prescriptionOrderShip({
id: shipRowId.value,
ship_mode: shipForm.ship_mode === 'direct' ? 'direct' : 'gancao',
ship_mode: normalizeShipMode(shipForm.ship_mode),
express_company: shipForm.express_company || 'auto',
tracking_number: shipForm.tracking_number.trim()
})
@@ -5110,6 +5299,8 @@ const rxTypeText = computed(() => {
const v = prescriptionViewData.value as any
if (!v) return '—'
const t = v.prescription_type || '浓缩水丸'
/** 饮片不匹配「丸|散|膏|片」,避免误显示「浓缩丸-饮片」;类型字段直接展示饮片 */
if (t === '饮片') return '饮片'
return /丸|散|膏|片/.test(t) ? `浓缩丸-${t}` : t
})
@@ -3052,14 +3052,18 @@ function canEditRow(row: {
gancao_reciperl_order_no?: string | null
gancao_submit_time?: number | null
}) {
// (5)(6)(3)(4)
const fs = Number(row.fulfillment_status)
if (fs !== 1 && fs !== 2) return false
// > 0
if (fs === 3 || fs === 4) return false
const gcNo = String(row.gancao_reciperl_order_no || '').trim()
const gcTime = Number(row.gancao_submit_time || 0)
if (gcNo !== '' || gcTime > 0) return false
return true
const gcLocked = gcNo !== '' || gcTime > 0
if (gcLocked) {
return [1, 2, 5, 7].includes(fs)
}
return fs === 1 || fs === 2
}
function canRxAudit(row: { prescription_audit_status?: number; fulfillment_status?: number }) {
@@ -3128,9 +3132,7 @@ function canCompleteRow(row: { fulfillment_status?: number; payment_slip_audit_s
}
function canQuickTrackRow(row: { fulfillment_status?: number }) {
// (5) / (6) 使
const fs = Number(row.fulfillment_status)
return fs === 5 || fs === 6
return Number(row.fulfillment_status) === 5
}
function canUploadGancaoRow(row: {
@@ -4312,8 +4314,8 @@ async function submitQuickTrack() {
if (nd) detailData.value = nd
} catch { /* 静默 */ }
}
//
if (canShipRow({ fulfillment_status: 2, tracking_number: quickTrackForm.tracking_number })) {
// (2)(5)/(6)
if (canShipRow({ fulfillment_status: Number(d.fulfillment_status) })) {
try {
await ElMessageBox.confirm(
`快递单号「${quickTrackForm.tracking_number}」已保存,是否立即确认发货?`,
+39 -12
View File
@@ -22,16 +22,25 @@
<el-select
v-model="formData.media_channel_code"
placeholder="请选择自媒体渠道"
class="w-full"
class="account-cost-channel-select w-full"
filterable
:disabled="mode === 'edit'"
>
<el-option
v-for="item in mediaChannelOptions"
:key="item.code"
:label="item.name"
:value="item.code"
/>
<el-option-group
v-for="g in mediaChannelGroups"
:key="g.group_name"
:label="g.group_name"
>
<el-option
v-for="ch in g.channels"
:key="ch.channel_code"
:label="ch.channel_name"
:value="ch.channel_code"
>
<div class="channel-opt-row">
<span class="opt-name">{{ ch.channel_name }}</span>
</div>
</el-option>
</el-option-group>
</el-select>
</el-form-item>
<el-form-item label="部门" prop="dept_id">
@@ -78,9 +87,9 @@ import type { FormInstance } from 'element-plus'
import { accountCostAdd, accountCostDetail, accountCostEdit } from '@/api/finance'
import Popup from '@/components/popup/index.vue'
interface MediaChannelOption {
code: string
name: string
interface MediaChannelGroup {
group_name: string
channels: { channel_code: string; channel_name: string }[]
}
interface DeptOption {
@@ -90,7 +99,7 @@ interface DeptOption {
}
const props = defineProps<{
mediaChannelOptions: MediaChannelOption[]
mediaChannelGroups: MediaChannelGroup[]
deptOptions: DeptOption[]
defaultMediaChannelCode: string
}>()
@@ -197,3 +206,21 @@ defineExpose({
getDetail,
})
</script>
<style scoped lang="scss">
.account-cost-channel-select {
:deep(.channel-opt-row) {
display: flex;
align-items: center;
width: 100%;
min-width: 0;
padding-right: 4px;
}
:deep(.opt-name) {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}
}
</style>
+63 -9
View File
@@ -27,14 +27,25 @@
placeholder="筛选全部渠道"
clearable
filterable
class="w-[220px]"
class="account-cost-channel-select w-[220px]"
>
<el-option
v-for="item in mediaChannelOptions"
:key="item.code"
:label="item.name"
:value="item.code"
/>
<el-option label="全部" value="" />
<el-option-group
v-for="g in mediaChannelGroups"
:key="g.group_name"
:label="g.group_name"
>
<el-option
v-for="ch in g.channels"
:key="ch.channel_code"
:label="ch.channel_name"
:value="ch.channel_code"
>
<div class="channel-opt-row">
<span class="opt-name">{{ ch.channel_name }}</span>
</div>
</el-option>
</el-option-group>
</el-select>
</el-form-item>
<el-form-item label="部门">
@@ -117,7 +128,7 @@
<edit-popup
v-if="showEdit"
ref="editRef"
:media-channel-options="mediaChannelOptions"
:media-channel-groups="mediaChannelGroups"
:dept-options="deptOptions"
:default-media-channel-code="defaultMediaChannelCode"
@success="getLists"
@@ -133,6 +144,11 @@ import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
interface MediaChannelGroup {
group_name: string
channels: { channel_code: string; channel_name: string }[]
}
interface MediaChannelOption {
code: string
name: string
@@ -160,7 +176,7 @@ const { pager, getLists, resetPage } = usePaging({
params: queryParams,
})
const mediaChannelOptions = computed<MediaChannelOption[]>(() => {
const mediaChannelOptionsFlat = computed<MediaChannelOption[]>(() => {
const options = pager.extend.media_channel_options
if (!Array.isArray(options)) return []
@@ -170,6 +186,26 @@ const mediaChannelOptions = computed<MediaChannelOption[]>(() => {
}))
})
const mediaChannelGroups = computed<MediaChannelGroup[]>(() => {
const groups = pager.extend.media_channel_groups
if (Array.isArray(groups) && groups.length > 0) {
return groups as MediaChannelGroup[]
}
const flat = mediaChannelOptionsFlat.value
if (!flat.length) {
return []
}
return [
{
group_name: '渠道',
channels: flat.map(item => ({
channel_code: item.code,
channel_name: item.name,
})),
},
]
})
const deptOptions = computed<DeptOption[]>(() => {
const options = pager.extend.dept_options
return Array.isArray(options) ? options : []
@@ -213,3 +249,21 @@ const handleReset = () => {
getLists()
</script>
<style scoped lang="scss">
.account-cost-channel-select {
:deep(.channel-opt-row) {
display: flex;
align-items: center;
width: 100%;
min-width: 0;
padding-right: 4px;
}
:deep(.opt-name) {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}
}
</style>
@@ -683,7 +683,7 @@ const bloodTrendOption = computed(() => ({
name: '空腹血糖',
type: 'line',
smooth: true,
connectNulls: false,
connectNulls: true,
data: bloodTrendSeries.value.fasting,
symbolSize: 7,
itemStyle: {
@@ -698,7 +698,7 @@ const bloodTrendOption = computed(() => ({
name: '餐后血糖',
type: 'line',
smooth: true,
connectNulls: false,
connectNulls: true,
data: bloodTrendSeries.value.postprandial,
symbolSize: 7,
itemStyle: {
@@ -719,7 +719,8 @@ function formatColumnDate(date: string) {
function parseTrendNumber(value: unknown): number | null {
if (value === '' || value == null) return null
const parsed = Number(value)
return Number.isFinite(parsed) ? parsed : null
if (!Number.isFinite(parsed) || parsed === 0) return null
return parsed
}
function getCell(metric: string, date: string): { value: string; isHigh: boolean; hasRecord: boolean } {
@@ -274,6 +274,7 @@
<el-descriptions-item label="用药疗程">{{ detailData.medication_days ? detailData.medication_days + ' 天' : '—' }}</el-descriptions-item>
<el-descriptions-item label="上次医护">{{ detailData.prev_staff || '—' }}</el-descriptions-item>
<el-descriptions-item label="服务渠道">{{ detailData.service_channel || '—' }}</el-descriptions-item>
<el-descriptions-item label="服务套餐">{{ formatServicePackage(detailData.service_package) }}</el-descriptions-item>
<el-descriptions-item label="费用类别">{{ feeTypeText(detailData.fee_type) }}</el-descriptions-item>
<el-descriptions-item label="快递单号">{{ detailData.tracking_number || '—' }}</el-descriptions-item>
<el-descriptions-item label="快递公司">{{ expressCompanyLabel(detailData.express_company) }}</el-descriptions-item>
@@ -332,7 +333,7 @@
</template>
<script setup lang="ts">
import { computed, watch, ref } from 'vue'
import { computed, watch, ref, onMounted } from 'vue'
import { usePaging } from '@/hooks/usePaging'
import {
prescriptionOrderLists,
@@ -341,6 +342,7 @@ import {
prescriptionOrderLogisticsTrace,
prescriptionOrderPaidPayOrders
} from '@/api/tcm'
import { getDictData } from '@/api/app'
import { hasPermission } from '@/utils/perm'
import feedback from '@/utils/feedback'
import useUserStore from '@/stores/modules/user'
@@ -563,6 +565,39 @@ function feeTypeText(t: number | undefined) {
return m[Number(t)] ?? '—'
}
// 服务套餐字典选项(与 order_list.vue 数据源一致:dict 类型 server_order
const servicePackageOptions = ref<Array<{ name: string; value: string }>>([])
async function loadServicePackageOptions() {
try {
const data: any = await getDictData({ type: 'server_order' })
const list = (data?.server_order || []) as Array<{ name: string; value: string; status?: number }>
servicePackageOptions.value = list.filter((item) => item.status !== 0)
} catch {
servicePackageOptions.value = []
}
}
function formatServicePackage(value: unknown): string {
if (value === null || value === undefined || value === '') return '—'
let packages: string[] = []
if (Array.isArray(value)) {
packages = value.map((v) => String(v)).filter((v) => v !== '')
} else if (typeof value === 'string') {
packages = value.split(',').map((v) => v.trim()).filter((v) => v !== '')
}
if (packages.length === 0) return '—'
const names = packages.map((val) => {
const opt = servicePackageOptions.value.find((o) => o.value === val)
return opt ? opt.name : val
})
return names.join('、')
}
onMounted(() => {
loadServicePackageOptions()
})
function expressCompanyLabel(v: unknown) {
const s = String(v || '').toLowerCase()
if (s === 'sf') return '顺丰速运'
+1 -1
View File
@@ -257,7 +257,7 @@
<template #default="{ row }">
<el-tooltip
v-if="row.last_blood_record_at"
:content="`最近一次血糖打卡:${row.last_blood_record_at}`"
:content="`最近一次健康打卡:${row.last_blood_record_at}`"
placement="top"
>
<span class="unserved-days" :class="unservedDaysClass(row.unserved_days)">
+2 -2
View File
@@ -17,14 +17,14 @@
</span>
<el-tooltip
v-if="lastBloodAt"
:content="`最近一次血糖打卡:${lastBloodAt}`"
:content="`最近一次健康打卡:${lastBloodAt}`"
placement="bottom"
>
<span :class="['unserved-badge', unservedDaysClass(unservedDays)]">
未服务 {{ unservedDays ?? '—' }}
</span>
</el-tooltip>
<span v-else class="unserved-badge unserved-muted">从未打卡血糖</span>
<span v-else class="unserved-badge unserved-muted">从未打卡</span>
</div>
</div>
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
+16
View File
@@ -82,6 +82,22 @@ class AppointmentController extends BaseAdminController
return $this->success('保存成功');
}
/** 批量修改挂号渠道来源(消费者处方-挂号列表) */
public function batchEditChannel()
{
$params = (new AppointmentValidate())->post()->goCheck('batchEditChannel');
$post = $this->request->post();
if (\array_key_exists('channel_source_detail', $post)) {
$params['channel_source_detail'] = $post['channel_source_detail'];
}
$result = AppointmentLogic::adminBatchEditChannel($params, $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(AppointmentLogic::getError());
}
return $this->success((string) ($result['msg'] ?? '操作成功'), $result);
}
/**
* @notes 预约详情
* @return \think\response\Json
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
+21
View File
@@ -48,6 +48,27 @@ class PrescriptionController extends BaseAdminController
return $this->success('编辑成功');
}
/**
* @notes 修正处方患者姓名手机性别
*/
public function patchPatient()
{
$params = (new PrescriptionValidate())->post()->goCheck('patchPatient');
$ok = PrescriptionLogic::patchPatientContact(
(int) $params['id'],
(string) $params['patient_name'],
(string) $params['phone'],
(int) $params['gender'],
(int) $this->adminId,
$this->adminInfo
);
if (!$ok) {
return $this->fail(PrescriptionLogic::getError());
}
return $this->success('已更新');
}
/**
* @notes 删除处方
*/
View File
+19
View File
@@ -124,6 +124,25 @@ class PrescriptionOrderController extends BaseAdminController
return $this->success('修改成功');
}
/**
* 设置发货类型(甘草 / 洛阳)
*/
public function setShipMode()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('setShipMode');
$result = PrescriptionOrderLogic::setShipMode(
(int) $params['id'],
(string) ($params['ship_mode'] ?? 'gancao'),
$this->adminId,
$this->adminInfo
);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('已保存', $result);
}
/**
* 修改关联处方的患者姓名与手机号(订单详情场景)
*/
View File
View File
Regular → Executable
View File
+22 -9
View File
@@ -109,17 +109,30 @@ class AuthMiddleware
*/
private function matchPermissionAlias(string $accessUri, array $adminUris): bool
{
if (!in_array('tcm.diagnosis/dailyrecord', $adminUris, true)) {
return false;
if (in_array('tcm.diagnosis/dailyrecord', $adminUris, true)
&& in_array($accessUri, [
'tcm.diagnosistodo/lists',
'tcm.diagnosistodo/add',
'tcm.diagnosistodo/cancel',
'tcm.diagnosis/trackingnotes',
'tcm.diagnosis/addtrackingnote',
], true)) {
return true;
}
return in_array($accessUri, [
'tcm.diagnosistodo/lists',
'tcm.diagnosistodo/add',
'tcm.diagnosistodo/cancel',
'tcm.diagnosis/trackingnotes',
'tcm.diagnosis/addtrackingnote',
], true);
// 导出与列表共用 PrescriptionOrderLists 数据域;角色漏勾「导出订单」子权限时仍返回 权限不足
if ($accessUri === 'tcm.prescriptionorder/export'
&& in_array('tcm.prescriptionorder/lists', $adminUris, true)) {
return true;
}
// 挂号列表批量改渠道:与单条编辑同一数据域,复用 doctor.appointment/edit
if ($accessUri === 'doctor.appointment/batcheditchannel'
&& in_array('doctor.appointment/edit', $adminUris, true)) {
return true;
}
return false;
}
/**
View File
View File
View File
View File

Some files were not shown because too many files have changed in this diff Show More