From 0fb51e12d104ad1b65c4f1937b5e1e7ebee53a4a Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 May 2026 10:18:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/src/api/tcm.ts | 5 + .../consumer/prescription/order_list.vue | 120 +++++++++++++++++- .../tcm/PrescriptionOrderController.php | 19 +++ .../logic/tcm/PrescriptionOrderLogic.php | 72 ++++++++++- .../tcm/PrescriptionOrderValidate.php | 1 + ..._prescription_order_set_ship_mode_menu.sql | 16 +++ .../add_prescription_order_ship_mode.sql | 7 + 7 files changed, 231 insertions(+), 9 deletions(-) create mode 100644 server/sql/1.9.20260519/add_prescription_order_set_ship_mode_menu.sql create mode 100644 server/sql/1.9.20260519/add_prescription_order_ship_mode.sql diff --git a/admin/src/api/tcm.ts b/admin/src/api/tcm.ts index 42303f29..e98308ee 100644 --- a/admin/src/api/tcm.ts +++ b/admin/src/api/tcm.ts @@ -500,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 }) +} + // ========== 处方库 ========== // 处方库列表 diff --git a/admin/src/views/consumer/prescription/order_list.vue b/admin/src/views/consumer/prescription/order_list.vue index 88c7a508..6ae7f2d0 100644 --- a/admin/src/views/consumer/prescription/order_list.vue +++ b/admin/src/views/consumer/prescription/order_list.vue @@ -562,6 +562,28 @@ round class="ml-2" >甘草 {{ detailData.gancao_reciperl_order_no }} +
+ 发货类型 + + 甘草药房 + 洛阳药房 + + {{ shipModeLabel(detailData.ship_mode) }} +
- - 甘草药房直发 - 洛阳药房直发 - + {{ shipDialogModeDisplay }} + 请在订单详情顶部「发货类型」中设置,此处不可修改 @@ -2571,6 +2595,7 @@ import { prescriptionOrderShip, prescriptionOrderLogs, prescriptionOrderUpdateAmount, + prescriptionOrderSetShipMode, prescriptionOrderAddPayOrder, prescriptionOrderComplete, prescriptionOrderRevokeRxAudit, @@ -3364,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) @@ -4745,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('请先填写快递单号再确认发货') @@ -4762,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() }) diff --git a/server/app/adminapi/controller/tcm/PrescriptionOrderController.php b/server/app/adminapi/controller/tcm/PrescriptionOrderController.php index 9c8c7b6d..16a95eac 100755 --- a/server/app/adminapi/controller/tcm/PrescriptionOrderController.php +++ b/server/app/adminapi/controller/tcm/PrescriptionOrderController.php @@ -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); + } + /** * 修改关联处方的患者姓名与手机号(订单详情场景) */ diff --git a/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php b/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php index 072e0dfe..3faacb1a 100755 --- a/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php +++ b/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php @@ -677,9 +677,10 @@ class PrescriptionOrderLogic $rows = Order::whereIn('id', $ids)->whereNull('delete_time') ->field(['id', 'order_no', 'order_type', 'amount', 'status', 'create_time', 'creator_id', 'remark', 'is_exempt']) ->order('id', 'asc') + ->where('status', 2) ->select() ->toArray(); - + $creatorIds = array_values(array_unique(array_filter(array_map('intval', array_column($rows, 'creator_id'))))); $creatorNames = []; if ($creatorIds !== []) { @@ -1664,6 +1665,7 @@ class PrescriptionOrderLogic $order->express_company = self::normalizeExpressCompany($expressCompany); $order->tracking_number = $trackingNumber; + $order->ship_mode = $shipMode; // 仅履约中(2)时才推进到已发货(5),已发货(5)则只更新快递信息保持状态 $isFirstShip = false; if ((int) $order->fulfillment_status === 2) { @@ -2425,7 +2427,7 @@ class PrescriptionOrderLogic $linkedPayPaidTotal += (float) ($o['amount'] ?? 0); } $linkedPayPaidTotal = round($linkedPayPaidTotal, 2); - + if ($targetFulfillmentStatus === 3) { $order->fulfillment_status = 3; $order->paid = $linkedPayPaidTotal; @@ -3267,6 +3269,72 @@ class PrescriptionOrderLogic ]; } + /** + * 设置发货类型(甘草 / 洛阳),与确认发货选项一致 + * + * @return array|false + */ + public static function setShipMode(int $id, string $shipMode, int $adminId, array $adminInfo) + { + self::$error = ''; + + $order = PrescriptionOrder::where('id', $id)->whereNull('delete_time')->find(); + if (!$order) { + self::$error = '订单不存在'; + + return false; + } + if (!self::canAccessOrder($order, $adminId, $adminInfo)) { + self::$error = '无权限操作'; + + return false; + } + $fs = (int) $order->fulfillment_status; + if ($fs === 3 || $fs === 4) { + self::$error = '已完成或已取消的订单不可修改发货类型'; + + return false; + } + + $shipMode = self::normalizeShipMode($shipMode); + if ($shipMode === 'direct' && trim((string) $order->gancao_reciperl_order_no) !== '') { + self::$error = '已上传甘草药方,发货类型须为甘草药房'; + + return false; + } + + $oldMode = self::normalizeShipMode((string) ($order->ship_mode ?? 'gancao')); + if ($oldMode === $shipMode) { + $out = $order->toArray(); + self::maskInternalCostIfNeeded($out, $adminInfo); + self::maskRemarkExtraIfNeeded($out, $adminInfo); + self::attachLinkedPayOrders($out); + + return $out; + } + + $order->ship_mode = $shipMode; + + try { + $order->save(); + } catch (\Throwable $e) { + self::$error = $e->getMessage(); + + return false; + } + + $oldText = $oldMode === 'direct' ? '洛阳药房' : '甘草药房'; + $newText = $shipMode === 'direct' ? '洛阳药房' : '甘草药房'; + self::writeLog($id, $adminId, $adminInfo, 'set_ship_mode', '发货类型:' . $oldText . ' → ' . $newText); + + $out = $order->toArray(); + self::maskInternalCostIfNeeded($out, $adminInfo); + self::maskRemarkExtraIfNeeded($out, $adminInfo); + self::attachLinkedPayOrders($out); + + return $out; + } + /** * 修改订单金额 */ diff --git a/server/app/adminapi/validate/tcm/PrescriptionOrderValidate.php b/server/app/adminapi/validate/tcm/PrescriptionOrderValidate.php index d22a37b5..dd4eef12 100755 --- a/server/app/adminapi/validate/tcm/PrescriptionOrderValidate.php +++ b/server/app/adminapi/validate/tcm/PrescriptionOrderValidate.php @@ -78,6 +78,7 @@ class PrescriptionOrderValidate extends BaseValidate 'previewGancaoRecipel' => ['id'], 'patchPrescriptionPatient' => ['id', 'patient_name', 'phone'], 'updateAmount' => ['id', 'amount'], + 'setShipMode' => ['id', 'ship_mode'], ]; public function updateAmount(): PrescriptionOrderValidate diff --git a/server/sql/1.9.20260519/add_prescription_order_set_ship_mode_menu.sql b/server/sql/1.9.20260519/add_prescription_order_set_ship_mode_menu.sql new file mode 100644 index 00000000..f1b0aa74 --- /dev/null +++ b/server/sql/1.9.20260519/add_prescription_order_set_ship_mode_menu.sql @@ -0,0 +1,16 @@ +-- 处方业务订单:设置发货类型(甘草 / 洛阳) +-- 执行前确认表前缀为 zyt_;若已有相同 perms 则跳过。 + +SET @po_menu_id := (SELECT id FROM zyt_system_menu WHERE perms = 'tcm.prescriptionOrder/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 + @po_menu_id, 'A', '设置发货类型', '', 61, + 'tcm.prescriptionOrder/setShipMode', '', '', + '', '', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP() +FROM DUAL +WHERE @po_menu_id IS NOT NULL + AND NOT EXISTS (SELECT 1 FROM zyt_system_menu WHERE perms = 'tcm.prescriptionOrder/setShipMode'); diff --git a/server/sql/1.9.20260519/add_prescription_order_ship_mode.sql b/server/sql/1.9.20260519/add_prescription_order_ship_mode.sql new file mode 100644 index 00000000..86915755 --- /dev/null +++ b/server/sql/1.9.20260519/add_prescription_order_ship_mode.sql @@ -0,0 +1,7 @@ +-- 业务订单:发货药方(甘草 / 洛阳),与确认发货 ship_mode 一致 +-- 执行前确认表前缀为 zyt_;若列已存在可跳过。 + +ALTER TABLE `zyt_tcm_prescription_order` + ADD COLUMN `ship_mode` varchar(16) NOT NULL DEFAULT 'gancao' + COMMENT '发货药方:gancao=甘草药房 direct=洛阳药房' + AFTER `express_company`;