From c468c57cda239f78f1143cbdf13889834ad75c2b Mon Sep 17 00:00:00 2001 From: ShengLong <452591453@qq.com> Date: Mon, 11 May 2026 11:25:03 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=85=B3=E8=81=94=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E5=8D=95=E8=B1=81=E5=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + admin/src/api/order.ts | 5 ++++ admin/src/views/order/index.vue | 27 +++++++++++++++++-- .../controller/order/OrderController.php | 18 +++++++++++++ .../app/adminapi/logic/order/OrderLogic.php | 14 +++++++++- .../logic/tcm/PrescriptionOrderLogic.php | 13 +++++++-- .../2026_05_11_order_exempt_menu.sql | 13 +++++++++ .../migrations/2026_05_11_order_is_exempt.sql | 3 +++ 8 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 server/database/migrations/2026_05_11_order_exempt_menu.sql create mode 100644 server/database/migrations/2026_05_11_order_is_exempt.sql diff --git a/.gitignore b/.gitignore index bd2f47fe..f7dd36f3 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ bin-release/ /.kbctx /server/.spool /server/.claude +/.spool diff --git a/admin/src/api/order.ts b/admin/src/api/order.ts index 91ba8688..8f7ac5d2 100644 --- a/admin/src/api/order.ts +++ b/admin/src/api/order.ts @@ -104,3 +104,8 @@ export function orderActionLogStats(params?: { start_time?: string; end_time?: s export function orderBatchAssignAssistant(params: { order_ids: number[]; assistant_id: number }) { return request.post({ url: '/order.order/assignAssistant', params }) } + +/** 设置/取消支付单豁免权 */ +export function orderSetExempt(params: { id: number; is_exempt: 0 | 1 }) { + return request.post({ url: '/order.order/setExempt', params }) +} diff --git a/admin/src/views/order/index.vue b/admin/src/views/order/index.vue index 1ff526c5..55b865f1 100644 --- a/admin/src/views/order/index.vue +++ b/admin/src/views/order/index.vue @@ -180,11 +180,12 @@ - + @@ -270,6 +271,14 @@ > 删除 + + {{ row.is_exempt === 1 ? '取消豁免' : '设为豁免' }} + @@ -779,7 +788,8 @@ import { orderActionLogs, orderActionLogStats, orderBatchAssignAssistant, - orderSplit + orderSplit, + orderSetExempt } from '@/api/order' import { getAssistants } from '@/api/tcm' import { generateOrderQrcode } from '@/api/tcm' @@ -1494,6 +1504,19 @@ const handleDelete = async (row: any) => { } } +const handleToggleExempt = async (row: any) => { + const newVal: 0 | 1 = row.is_exempt === 1 ? 0 : 1 + const actionText = newVal === 1 ? '设为豁免' : '取消豁免' + try { + await feedback.confirm(`确定要${actionText}该支付单吗?豁免后关联此单的业务订单将跳过定金门槛校验。`) + await orderSetExempt({ id: row.id, is_exempt: newVal }) + feedback.msgSuccess(`${actionText}成功`) + getLists() + } catch (error) { + // 用户取消操作 + } +} + // 小程序码相关 const qrcodeDialogVisible = ref(false) const qrcodeLoading = ref(false) diff --git a/server/app/adminapi/controller/order/OrderController.php b/server/app/adminapi/controller/order/OrderController.php index cedef3eb..2dff9aab 100644 --- a/server/app/adminapi/controller/order/OrderController.php +++ b/server/app/adminapi/controller/order/OrderController.php @@ -557,6 +557,24 @@ class OrderController extends BaseAdminController } } + public function setExempt() + { + $id = (int) $this->request->post('id', 0); + $isExempt = (int) $this->request->post('is_exempt', 0); + if ($id <= 0) { + return $this->fail('参数错误'); + } + if (!in_array($isExempt, [0, 1], true)) { + return $this->fail('is_exempt 值无效'); + } + $result = OrderLogic::setExempt($id, $isExempt); + if (!$result) { + return $this->fail(OrderLogic::getError()); + } + $this->logOrderAction($id, 'set_exempt', $isExempt === 1 ? '设置豁免权' : '取消豁免权'); + return $this->success($isExempt === 1 ? '已设置豁免权' : '已取消豁免权'); + } + private function logOrderAction(int $orderId, string $action, string $summary = ''): void { OrderActionLogLogic::record($orderId, (int) $this->adminId, $this->adminInfo, $action, $summary); diff --git a/server/app/adminapi/logic/order/OrderLogic.php b/server/app/adminapi/logic/order/OrderLogic.php index 87209f67..0523c404 100644 --- a/server/app/adminapi/logic/order/OrderLogic.php +++ b/server/app/adminapi/logic/order/OrderLogic.php @@ -1213,7 +1213,7 @@ class OrderLogic } $rows = $q - ->field(['id', 'order_no', 'order_type', 'amount', 'status', 'create_time', 'creator_id', 'remark']) + ->field(['id', 'order_no', 'order_type', 'amount', 'status', 'create_time', 'creator_id', 'remark', 'is_exempt']) ->order('id', 'desc') ->select() ->toArray(); @@ -1400,4 +1400,16 @@ class OrderLogic 'errors' => $errors, ]; } + + public static function setExempt(int $id, int $isExempt): bool + { + $order = Order::find($id); + if (!$order) { + self::setError('订单不存在'); + return false; + } + $order->is_exempt = $isExempt; + $order->save(); + return true; + } } diff --git a/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php b/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php index b1d129a0..0234c6fd 100644 --- a/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php +++ b/server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php @@ -323,7 +323,16 @@ class PrescriptionOrderLogic if ($payOrderIds === []) { return '未关联支付单,关联支付单总金额须大于等于定金门槛 ¥' . $min; } - + + // 豁免权:关联的支付单中有豁免单则跳过金额校验 + $hasExempt = Order::whereIn('id', $payOrderIds) + ->whereNull('delete_time') + ->where('is_exempt', 1) + ->count(); + if ($hasExempt > 0) { + return null; + } + // 检查关联支付单的总金额 $rows = Order::whereIn('id', $payOrderIds)->whereNull('delete_time')->column('amount', 'id'); $totalAmount = 0.0; @@ -503,7 +512,7 @@ class PrescriptionOrderLogic return []; } $rows = Order::whereIn('id', $ids)->whereNull('delete_time') - ->field(['id', 'order_no', 'order_type', 'amount', 'status', 'create_time', 'creator_id', 'remark']) + ->field(['id', 'order_no', 'order_type', 'amount', 'status', 'create_time', 'creator_id', 'remark', 'is_exempt']) ->order('id', 'asc') ->select() ->toArray(); diff --git a/server/database/migrations/2026_05_11_order_exempt_menu.sql b/server/database/migrations/2026_05_11_order_exempt_menu.sql new file mode 100644 index 00000000..34cea3a3 --- /dev/null +++ b/server/database/migrations/2026_05_11_order_exempt_menu.sql @@ -0,0 +1,13 @@ +-- 支付单:设置/取消豁免权(权限节点) +SET @order_menu_id := (SELECT id FROM zyt_system_menu WHERE perms = 'order.order/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 + @order_menu_id, 'A', '设置豁免权', '', 0, 'order.order/setExempt', '', '', + '', '', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP() +FROM DUAL +WHERE @order_menu_id IS NOT NULL + AND NOT EXISTS (SELECT 1 FROM zyt_system_menu WHERE perms = 'order.order/setExempt'); diff --git a/server/database/migrations/2026_05_11_order_is_exempt.sql b/server/database/migrations/2026_05_11_order_is_exempt.sql new file mode 100644 index 00000000..1973f51b --- /dev/null +++ b/server/database/migrations/2026_05_11_order_is_exempt.sql @@ -0,0 +1,3 @@ +ALTER TABLE `zyt_order` + ADD COLUMN `is_exempt` tinyint(1) unsigned NOT NULL DEFAULT 0 + COMMENT '豁免权:1=关联此单时跳过定金门槛校验' AFTER `status`; From 1774a87dd796a483cfffef721a4ce4afb6b2ab99 Mon Sep 17 00:00:00 2001 From: ShengLong <452591453@qq.com> Date: Mon, 11 May 2026 11:41:42 +0800 Subject: [PATCH 2/3] update --- admin/src/views/consumer/prescription/order_list.vue | 6 ++++-- admin/src/views/consumer/prescription/order_list_h5.vue | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/admin/src/views/consumer/prescription/order_list.vue b/admin/src/views/consumer/prescription/order_list.vue index bf34cdf9..cb6a91a1 100644 --- a/admin/src/views/consumer/prescription/order_list.vue +++ b/admin/src/views/consumer/prescription/order_list.vue @@ -911,11 +911,12 @@ ¥{{ row.amount }} - + @@ -968,11 +969,12 @@ ¥{{ row.amount }} - + diff --git a/admin/src/views/consumer/prescription/order_list_h5.vue b/admin/src/views/consumer/prescription/order_list_h5.vue index d03b4b45..bdc20579 100644 --- a/admin/src/views/consumer/prescription/order_list_h5.vue +++ b/admin/src/views/consumer/prescription/order_list_h5.vue @@ -925,11 +925,12 @@ ¥{{ row.amount }} - + @@ -982,11 +983,12 @@ ¥{{ row.amount }} - + From d8d4da197e081fd86c1b5101a08f3f2019fb4f82 Mon Sep 17 00:00:00 2001 From: ShengLong <452591453@qq.com> Date: Mon, 11 May 2026 15:04:24 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=96=B0=E6=8C=87=E6=B4=BE=E5=8C=BB?= =?UTF-8?q?=E5=8A=A9=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/src/views/tcm/diagnosis/index.vue | 10 ++++++---- admin/src/views/tcm/diagnosis/index_h5.vue | 13 +++++++++++++ admin/src/views/tcm/follow/index.vue | 10 ++++++---- .../controller/tcm/DiagnosisController.php | 3 ++- .../app/adminapi/lists/tcm/DiagnosisLists.php | 6 +++--- .../app/adminapi/logic/tcm/DiagnosisLogic.php | 18 +++++++++++++++++- .../2026_05_11_diagnosis_assign_read.sql | 7 +++++++ 7 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 server/database/migrations/2026_05_11_diagnosis_assign_read.sql diff --git a/admin/src/views/tcm/diagnosis/index.vue b/admin/src/views/tcm/diagnosis/index.vue index 49404e06..a95d3b36 100644 --- a/admin/src/views/tcm/diagnosis/index.vue +++ b/admin/src/views/tcm/diagnosis/index.vue @@ -151,12 +151,14 @@ stripe > - + @@ -1352,7 +1354,7 @@ const handleSingleAssign = (row: any) => { currentRow.value = row batchAssignIds.value = [] // 确保类型一致,转换为数字 - assignForm.value.assistant_id = row.assistant_id ? Number(row.assistant_id) : null + assignForm.value.assistant_id = Number(row.assistant_id) > 0 ? Number(row.assistant_id) : null assignDialogVisible.value = true } diff --git a/admin/src/views/tcm/diagnosis/index_h5.vue b/admin/src/views/tcm/diagnosis/index_h5.vue index bdd74536..0324f428 100644 --- a/admin/src/views/tcm/diagnosis/index_h5.vue +++ b/admin/src/views/tcm/diagnosis/index_h5.vue @@ -130,6 +130,7 @@
#{{ row.id }} · {{ row.diagnosis_date_text || formatDateTime(row.create_time) }} + NEW
@@ -1672,6 +1673,18 @@ $dh5-card-bg: #ffffff; flex-wrap: wrap; } +.dh5-tag-new { + display: inline-block; + background: #ef4444; + color: #fff; + font-size: 10px; + font-weight: 700; + padding: 1px 4px; + border-radius: 3px; + margin-left: 4px; + vertical-align: middle; +} + .dh5-meta-gender, .dh5-meta-age { font-size: 12px; diff --git a/admin/src/views/tcm/follow/index.vue b/admin/src/views/tcm/follow/index.vue index 6cc84658..9a9ae541 100644 --- a/admin/src/views/tcm/follow/index.vue +++ b/admin/src/views/tcm/follow/index.vue @@ -97,12 +97,14 @@ stripe > - + @@ -1088,7 +1090,7 @@ const handleSingleAssign = (row: any) => { assignMode.value = 'single' currentRow.value = row // 确保类型一致,转换为数字 - assignForm.value.assistant_id = row.assistant_id ? Number(row.assistant_id) : null + assignForm.value.assistant_id = Number(row.assistant_id) > 0 ? Number(row.assistant_id) : null assignDialogVisible.value = true } diff --git a/server/app/adminapi/controller/tcm/DiagnosisController.php b/server/app/adminapi/controller/tcm/DiagnosisController.php index 8ef71593..d1eb592f 100644 --- a/server/app/adminapi/controller/tcm/DiagnosisController.php +++ b/server/app/adminapi/controller/tcm/DiagnosisController.php @@ -117,6 +117,7 @@ class DiagnosisController extends BaseAdminController $params = (new DiagnosisValidate())->goCheck('id'); $result = DiagnosisLogic::detail($params); + DiagnosisLogic::markAssignRead((int) ($params['id'] ?? 0), $this->adminId); return $this->data($result); } @@ -135,7 +136,7 @@ class DiagnosisController extends BaseAdminController if (empty($result)) { return $this->fail(DiagnosisLogic::getError() ?: '诊单不存在或无权访问'); } - + DiagnosisLogic::markAssignRead((int) ($params['id'] ?? 0), $this->adminId); return $this->data($result); } diff --git a/server/app/adminapi/lists/tcm/DiagnosisLists.php b/server/app/adminapi/lists/tcm/DiagnosisLists.php index f067c4e5..79c8a78a 100644 --- a/server/app/adminapi/lists/tcm/DiagnosisLists.php +++ b/server/app/adminapi/lists/tcm/DiagnosisLists.php @@ -177,14 +177,14 @@ class DiagnosisLists extends BaseAdminDataLists implements ListsSearchInterface $isCompletedTab = !$pendingWideSearch && isset($this->params['completed_appointment']) && (string) $this->params['completed_appointment'] === '1'; if ($isCompletedTab) { $maxCompletedAptExpr = '(SELECT MAX(CONCAT(apt.appointment_date, \' \', IFNULL(NULLIF(TRIM(apt.appointment_time), \'\'), \'00:00:00\'))) FROM ' . $aptTbl . ' apt WHERE apt.patient_id = ' . $diagTbl . '.id AND apt.status = 3' . $minAptDateCond . ')'; - $orderRaw = 'IFNULL(' . $maxCompletedAptExpr . ", '1970-01-01 00:00:00') DESC, {$diagTbl}.id DESC"; + $orderRaw = $diagTbl . '.assign_read_at IS NULL DESC, IFNULL(' . $maxCompletedAptExpr . ", '1970-01-01 00:00:00') DESC, {$diagTbl}.id DESC"; } else { - $orderRaw = 'CASE IFNULL(' . $minAptStatusExpr . ', 999) WHEN 4 THEN 1 WHEN 1 THEN 2 WHEN 3 THEN 3 ELSE 4 END ASC, IFNULL(' . $minAptExpr . ", '9999-12-31 23:59:59') ASC, {$diagTbl}.id DESC"; + $orderRaw = $diagTbl . '.assign_read_at IS NULL DESC, CASE IFNULL(' . $minAptStatusExpr . ', 999) WHEN 4 THEN 1 WHEN 1 THEN 2 WHEN 3 THEN 3 ELSE 4 END ASC, IFNULL(' . $minAptExpr . ", '9999-12-31 23:59:59') ASC, {$diagTbl}.id DESC"; } $lists = $query ->with(['DiagnosisViewRecord']) - ->field(['id', 'patient_id', 'patient_name', 'id_card', 'phone', 'gender', 'age', 'diagnosis_date', 'diagnosis_type', 'syndrome_type', 'assistant_id', 'status', 'create_time', 'update_time']) + ->field(['id', 'patient_id', 'patient_name', 'id_card', 'phone', 'gender', 'age', 'diagnosis_date', 'diagnosis_type', 'syndrome_type', 'assistant_id', 'assign_read_at', 'status', 'create_time', 'update_time']) ->append(['gender_desc', 'status_desc', 'diagnosis_date_text']) ->orderRaw($orderRaw) ->limit($this->limitOffset, $this->limitLength) diff --git a/server/app/adminapi/logic/tcm/DiagnosisLogic.php b/server/app/adminapi/logic/tcm/DiagnosisLogic.php index fccdd594..5ddc0591 100644 --- a/server/app/adminapi/logic/tcm/DiagnosisLogic.php +++ b/server/app/adminapi/logic/tcm/DiagnosisLogic.php @@ -535,6 +535,19 @@ class DiagnosisLogic extends BaseLogic return 0; } + public static function markAssignRead(int $diagnosisId, int $adminId): void + { + if ($diagnosisId <= 0 || $adminId <= 0) { + return; + } + Db::name('tcm_diagnosis') + ->where('id', $diagnosisId) + ->where('assistant_id', $adminId) + ->whereNull('assign_read_at') + ->whereNull('delete_time') + ->update(['assign_read_at' => time()]); + } + /** * @notes 指派医助(每次成功更新写入一条操作记录,批量指派为多次接口调用各记一条)。 * **原医助**:优先诊单 `assistant_id`;若为 0 且本次为指派到某人,则从**最近一条**指派日志推断(覆盖发货释放后库为 0、业务上仍有「前任」医助的情况)。 @@ -588,7 +601,10 @@ class DiagnosisLogic extends BaseLogic Db::name('tcm_diagnosis') ->where('id', $id) ->whereNull('delete_time') - ->update(['assistant_id' => $toAssistantId]); + ->update([ + 'assistant_id' => $toAssistantId, + 'assign_read_at' => $toAssistantId > 0 ? null : 0, + ]); $req = request(); $admin = $req->adminInfo ?? []; diff --git a/server/database/migrations/2026_05_11_diagnosis_assign_read.sql b/server/database/migrations/2026_05_11_diagnosis_assign_read.sql new file mode 100644 index 00000000..8865ad21 --- /dev/null +++ b/server/database/migrations/2026_05_11_diagnosis_assign_read.sql @@ -0,0 +1,7 @@ +-- 二诊医助:新指派患者已读标记 +ALTER TABLE `zyt_tcm_diagnosis` + ADD COLUMN `assign_read_at` int(10) unsigned DEFAULT NULL + COMMENT '医助查看指派时间戳,NULL=未读(新指派红旗)' AFTER `assistant_id`; + +-- 已有数据标记为已读,避免全部显示红旗 +UPDATE `zyt_tcm_diagnosis` SET `assign_read_at` = UNIX_TIMESTAMP() WHERE `assistant_id` > 0;