From 1ff538ba6e2c71a73534f0f13682b7e2874edc61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=90=A6?= Date: Fri, 3 Jul 2026 16:49:12 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E7=89=B9=E8=89=B2=E6=96=B9=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E8=BF=AD=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/Code-Standards.mdc | 9 + .gitignore | 3 +- .../components/ChineseMedicineConfig.vue | 38 +++-- .../sub_workbench/prescription_v2/index.vue | 154 +++++++++++++++--- .../utils/specialPrescription.js | 57 ++++++- .../sub_workbench/workbench_infoPatient.vue | 82 +++++++--- 6 files changed, 285 insertions(+), 58 deletions(-) create mode 100644 .cursor/rules/Code-Standards.mdc diff --git a/.cursor/rules/Code-Standards.mdc b/.cursor/rules/Code-Standards.mdc new file mode 100644 index 0000000..99af2df --- /dev/null +++ b/.cursor/rules/Code-Standards.mdc @@ -0,0 +1,9 @@ +--- +description: +alwaysApply: true +--- + +1. 写代码的时候要补充详细的中文注释(每个方法是干嘛的,为什么要这样写),如果是工作区,则所有项目都适用该规则 +2. 注意不要生成太多的空行,上一部分代码和下一部分代码中间的空行不要大于2行 +3. 有封装好的方法、组件需要复用,不要重复造轮子 +4. 小程序端的抽屉全部需要用page-container来防止用户意外退出页面 diff --git a/.gitignore b/.gitignore index dc76fc1..5c99acc 100644 --- a/.gitignore +++ b/.gitignore @@ -114,4 +114,5 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* -package-lock.json \ No newline at end of file +package-lock.json +/.cursor/skills/ diff --git a/subPackages/sub_workbench/prescription_v2/components/ChineseMedicineConfig.vue b/subPackages/sub_workbench/prescription_v2/components/ChineseMedicineConfig.vue index 9d89cf4..3c13a6f 100644 --- a/subPackages/sub_workbench/prescription_v2/components/ChineseMedicineConfig.vue +++ b/subPackages/sub_workbench/prescription_v2/components/ChineseMedicineConfig.vue @@ -9,15 +9,15 @@ 自制剂 委托调剂 @@ -36,8 +36,8 @@ v-for="item in packageMethodList" :key="item.id" class="modern-pill outline" - :class="{ active: localConfig.packageMethodId === item.id }" - @click="handlePackageMethodTagClick(item)" + :class="{ active: localConfig.packageMethodId === item.id, disabled: disabled }" + @click="!disabled && handlePackageMethodTagClick(item)" > {{ item.name }} @@ -56,8 +56,8 @@ v-for="item in processRuleList" :key="item.id" class="modern-pill outline" - :class="{ active: localConfig.processRuleId === item.id }" - @click="handleProcessRuleTagClick(item)" + :class="{ active: localConfig.processRuleId === item.id, disabled: disabled }" + @click="!disabled && handleProcessRuleTagClick(item)" > {{ item.name }} @@ -73,8 +73,8 @@ v-for="item in childProcessRuleList" :key="item.id" class="modern-pill outline" - :class="{ active: localConfig.childProcessRuleId === item.id }" - @click="handleChildProcessRuleTagClick(item)" + :class="{ active: localConfig.childProcessRuleId === item.id, disabled: disabled }" + @click="!disabled && handleChildProcessRuleTagClick(item)" > {{ item.name }} @@ -90,8 +90,8 @@ v-for="item in processRuleNoteList" :key="item.id" class="modern-pill outline" - :class="{ active: localConfig.processRuleNoteId === item.id }" - @click="handleProcessRuleNoteTagClick(item)" + :class="{ active: localConfig.processRuleNoteId === item.id, disabled: disabled }" + @click="!disabled && handleProcessRuleNoteTagClick(item)" > {{ item.note || item.name }} @@ -108,6 +108,7 @@ [] + }, + /** + * 特色方锁定后禁止修改配置 + */ + disabled: { + type: Boolean, + default: false } }, data() { @@ -368,5 +377,10 @@ export default { border-color: #00A88A; } } + + &.disabled { + opacity: 0.5; + pointer-events: none; + } } \ No newline at end of file diff --git a/subPackages/sub_workbench/prescription_v2/index.vue b/subPackages/sub_workbench/prescription_v2/index.vue index 0f55474..42a0a20 100644 --- a/subPackages/sub_workbench/prescription_v2/index.vue +++ b/subPackages/sub_workbench/prescription_v2/index.vue @@ -2,7 +2,7 @@ @@ -54,6 +54,9 @@ 剂量:{{ specialPrescriptionRecord.dose_count }} 剂 + + 规格:{{ specialPrescriptionPurchaseLabel }} + 常用方 - + - + 删除 - + 调整用量 @@ -236,7 +239,7 @@ - + @@ -260,7 +263,7 @@ :ripple="true"> 常用方 - + 药材清单 (共{{currentDrugs.length}}味) - 修改剂量 - 清空 + + 清空药方 @@ -289,7 +299,7 @@ v-for="(it, tcmIndex) in currentDrugs" :key="tcmTagKey(it, tcmIndex)" :data-idx="tcmIndex" - @longpress.stop="onTcmTagLongPress"> + @longpress.stop="!isSpecialPrescriptionCartLocked && onTcmTagLongPress"> {{it.drug_name || it.name}} {{String(it.number)}}{{it.unit ? it.unit.name : 'g'}} - + @@ -313,7 +323,7 @@ 产品/器械 - + - + 删除 @@ -375,15 +385,20 @@ - + - + - 另存常用方 + + 另存常用方 + {{ isCommonPrescription ? '保存常用方' : (isSalespersonTransferMode ? '提交传方' : '发送处方') }} @@ -624,6 +644,10 @@ import { import { pickSpecialPrescriptionRecord, applySpecialPrescriptionPayload, + resolveSpecialPrescriptionPurchaseLabel, + clearAppliedSpecialPrescription, + isSpecialPrescriptionCartLocked, + guardSpecialPrescriptionCartEdit, } from './utils/specialPrescription.js'; const PENDING_RX_FROM_CHAT = 'xk_pending_rx_from_chat'; @@ -733,6 +757,11 @@ export default { specialPrescriptionRecord: null, applyingSpecialPrescription: false, pendingImportSpecial: false, + /** 医生已导入的特色方 ID,仅 >0 时提交走特色方计价 */ + appliedSpecialPrescriptionId: 0, + appliedSpecialPrescriptionFreeShipping: false, + /** 特色方 apply 返回的套餐/贴数总价,用于底部合计 */ + appliedSpecialPrescriptionExpectedTotal: null, /** 在线复诊中药:术语表(HTTP 拉取,内存缓存) */ traditionalTcmData: null, @@ -795,7 +824,9 @@ export default { return Number(this.registerStoreInfo?.allow_insurance_category ?? 0) === 1; }, canPreSendPriceAdjust() { - return Number(this.enableOrderPricePercentAdjust) === 1 && this.currentDrugs.length > 0; + return Number(this.enableOrderPricePercentAdjust) === 1 + && this.currentDrugs.length > 0 + && !this.isSpecialPrescriptionCartLocked; }, preSendDiscountLabel() { return formatPriceDiscountLabel(this.priceDiscount); @@ -825,6 +856,13 @@ export default { return PrescriptionCalculator.calculateProcessingFee(processRule, this.chineseConfig.dosage, totalDrugQuantity); }, totalPrice() { + const expected = this.appliedSpecialPrescriptionExpectedTotal; + if (expected != null && !Number.isNaN(Number(expected)) && Number(expected) > 0) { + const base = parseFloat(expected); + const fee = parseFloat(this.treatmentPrice || 0); + const process = this.activeCategory === 1 ? parseFloat(this.processingFee || 0) : 0; + return (base + fee + process).toFixed(2); + } const total = PrescriptionCalculator.calculateTotalPrice({ category: this.activeCategory, drugs: this.currentDrugs, @@ -863,6 +901,24 @@ export default { hasSpecialPrescriptionRecord() { return !!this.specialPrescriptionRecord; }, + /** 导入卡片:SKU 名或单剂 */ + specialPrescriptionPurchaseLabel() { + return resolveSpecialPrescriptionPurchaseLabel(this.specialPrescriptionRecord); + }, + /** 已导入特色方时锁定药方不可编辑 */ + isSpecialPrescriptionCartLocked() { + return isSpecialPrescriptionCartLocked(this); + }, + /** 底部发送按钮宽度(左侧仅「另存常用方」时需留出空间) */ + bottomSendBtnWidth() { + if (this.isSalespersonTransferMode || this.isCommonPrescription) { + return '686rpx'; + } + if (this.supportsCommonPrescriptionTemplate) { + return '400rpx'; + } + return '686rpx'; + }, navbarTitle() { if (this.isSalespersonTransferMode) { return '传方'; @@ -1241,9 +1297,11 @@ export default { uni.showToast({ title: discount === 100 ? '已清除浮动' : '调价成功', icon: 'none' }); }, clearPreSendPriceDiscount() { + if (guardSpecialPrescriptionCartEdit(this)) return; this.applyPreSendPriceDiscount(100); }, openPreSendOrderPriceAdjust() { + if (guardSpecialPrescriptionCartEdit(this)) return; if (!this.canPreSendPriceAdjust) return; this.currentDrugs = this.snapshotDrugOrigins(this.currentDrugs); this.priceAdjustVisible = true; @@ -1394,7 +1452,9 @@ export default { console.error('获取诊所信息失败:', error); } }, - handleOpenDiagnosisModal() { this.showDiagnosisModal = true; }, + handleOpenDiagnosisModal() { + this.showDiagnosisModal = true; + }, async ensureTraditionalTcmData() { if (this.traditionalTcmData) return this.traditionalTcmData; if (this.traditionalTcmLoadPromise) return this.traditionalTcmLoadPromise; @@ -1448,7 +1508,9 @@ export default { this.diagnosisText = this.diagnoses.map(item => item.name).join(','); this.saveToLocalStorage(); }, - handleOpenDoctorOrderModal() { this.showDoctorOrderModal = true; }, + handleOpenDoctorOrderModal() { + this.showDoctorOrderModal = true; + }, handleDoctorOrderConfirm(doctorOrderText) { this.medicalAdvice = doctorOrderText; this.saveToLocalStorage(); @@ -1463,6 +1525,13 @@ export default { applySpecialPrescriptionPayload(this, data); await this.loadRegisterOrderType(); this.$toast(`已导入特色方:${data.special_prescription_name || ''}`); + if (data.price_hint) { + uni.showModal({ + title: '价格提示', + content: data.price_hint, + showCancel: false, + }); + } } catch (error) { console.error('导入特色方失败:', error); this.$toast('导入特色方失败,请稍后重试'); @@ -1472,6 +1541,7 @@ export default { }, async handleSelectCommonPrescription(item) { try { + clearAppliedSpecialPrescription(this); const payload = item && item.apply_payload; if (!payload || !Array.isArray(payload.drugs)) { this.$toast('常用方数据异常'); @@ -1636,10 +1706,12 @@ export default { } }, handleOpenWesternMedicineModal() { + if (guardSpecialPrescriptionCartEdit(this)) return; this.westernModalInitialKeyword = ''; this.showWesternMedicineModal = true; }, handleSelectWesternDrug(drug) { + if (guardSpecialPrescriptionCartEdit(this)) return; if (PrescriptionValidator.isDrugExists(this.currentDrugs, drug)) { this.$toast('该药品已在列表中'); return; @@ -1671,6 +1743,7 @@ export default { this.$toast(`已添加 ${newDrug.drug_name}`); }, handleOpenChineseMedicineModal() { + if (guardSpecialPrescriptionCartEdit(this)) return; this.chineseModalInitialKeyword = ''; this.showChineseMedicineModal = true; }, @@ -1684,6 +1757,7 @@ export default { * 中药标签长按菜单(小程序 showActionSheet 回调里勿依赖闭包 item,用 dataset.idx + currentDrugs) */ onTcmTagLongPress(e) { + if (guardSpecialPrescriptionCartEdit(this)) return; const raw = e && e.currentTarget && e.currentTarget.dataset ? e.currentTarget.dataset.idx : undefined; const idx = raw === undefined || raw === '' ? NaN : Number(raw); if (Number.isNaN(idx) || idx < 0 || idx >= this.currentDrugs.length) return; @@ -1702,6 +1776,7 @@ export default { }); }, handleSelectChineseDrug(drugs) { + if (guardSpecialPrescriptionCartEdit(this)) return; this.currentDrugs = applyRatioToDrugs( this.snapshotDrugOrigins(drugs || []), this.priceDiscount, @@ -1709,8 +1784,12 @@ export default { ); this.saveToLocalStorage(); }, - handleOpenSimpleProductModal() { this.showSimpleProductModal = true; }, + handleOpenSimpleProductModal() { + if (guardSpecialPrescriptionCartEdit(this)) return; + this.showSimpleProductModal = true; + }, handleSelectSimpleProduct(product) { + if (guardSpecialPrescriptionCartEdit(this)) return; if (PrescriptionValidator.isDrugExists(this.currentDrugs, product)) { this.$toast('该产品已在列表中'); return; @@ -1731,6 +1810,7 @@ export default { this.$toast(`已添加 ${newProduct.drug_name}`); }, handleEditWesternDrug(drug, index) { + if (guardSpecialPrescriptionCartEdit(this)) return; this.editingDrug = JSON.parse(JSON.stringify(drug)); this.editingDrugIndex = index; this.showWesternUsageModal = true; @@ -1754,6 +1834,7 @@ export default { this.editingDrugIndex = -1; }, handleRemoveDrug(index) { + if (guardSpecialPrescriptionCartEdit(this)) return; uni.showModal({ title: '移除药品', content: '确定要从处方中移除该药品吗?', @@ -1787,6 +1868,7 @@ export default { } }, handleRemoveAllDrugs() { + if (guardSpecialPrescriptionCartEdit(this)) return; uni.showModal({ title: '清空药材', content: '确定要清空所有中药材吗?', @@ -1800,6 +1882,7 @@ export default { }); }, async handleUpdateChineseConfig(config) { + if (guardSpecialPrescriptionCartEdit(this)) return; const oldRuleType = this.chineseConfig.ruleType; const oldProcessRuleId = this.chineseConfig.processRuleId; const oldChildProcessRuleId = this.chineseConfig.childProcessRuleId; @@ -2158,6 +2241,7 @@ export default { patient: patientData, drugs: drugsData, diagnosis: clinical_diagnose, medicalAdvice: this.medicalAdvice, total: parseFloat(this.totalPrice), category: this.feeCategory, drug_type: 2, register_id: parseInt(this.registerId), treatment_price: parseFloat(this.treatmentPrice || 0), prescription_type: this.activeCategory, doctor_second_sign: doctorSecondSignValue, send_mode: finalSendMode, custom_store_id: finalSendMode === 1 ? finalStoreId : null, salesperson_transfer_prescription_id: this.salespersonTransferPrescriptionId || undefined, price_discount: this.priceDiscount, + special_prescription_id: Number(this.appliedSpecialPrescriptionId) || 0, }; if (this.activeCategory === 1) { params.package_method_id = this.chineseConfig.packageMethodId || null; params.process_rule_id = this.chineseConfig.processRuleId || null; params.process_rule_note_id = this.chineseConfig.processRuleNoteId || null; params.child_process_rule_id = this.chineseConfig.childProcessRuleId || null; params.process_rule_type = this.chineseConfig.ruleType || 1; params.processing_fee = this.processingFee; params.dosage = this.chineseConfig.dosage || 7; params.day_dosage = this.chineseConfig.dayDosage || 2; @@ -2235,6 +2319,33 @@ export default { this.onlineTcmDiseasesId = null; this.onlineTcmMethodId = null; this.onlineTcmSyndromeId = null; + clearAppliedSpecialPrescription(this); + }, + /** + * 清空药方(含特色方导入状态),与 PC 接诊「清空药方」一致 + */ + handleClearPrescriptionCart() { + const hasContent = this.currentDrugs.length > 0 + || this.diagnoses.length > 0 + || !!(this.diagnosisText && String(this.diagnosisText).trim()) + || !!(this.medicalAdvice && String(this.medicalAdvice).trim()) + || Number(this.appliedSpecialPrescriptionId) > 0; + if (!hasContent) { + this.$toast('当前无药方内容'); + return; + } + uni.showModal({ + title: '清空药方', + content: '确定清空当前药方吗?特色方将需重新导入。', + confirmColor: '#FC3636', + success: ({ confirm }) => { + if (!confirm) return; + this.clearPrescriptionData(); + this.saveToLocalStorage(); + PrescriptionStorage.clearAllPrescriptionData(this.registerId); + this.$toast('已清空药方'); + }, + }); }, handleSaveAsCommonPrescription() { if (this.currentDrugs.length === 0) { this.$toast('请先添加药品后再保存为常用方'); return; } @@ -2657,4 +2768,7 @@ export default { padding: 0 32rpx; flex-shrink: 0; } +.btnText--danger { + color: #FC3636; +} \ No newline at end of file diff --git a/subPackages/sub_workbench/prescription_v2/utils/specialPrescription.js b/subPackages/sub_workbench/prescription_v2/utils/specialPrescription.js index aaff35b..b672b0d 100644 --- a/subPackages/sub_workbench/prescription_v2/utils/specialPrescription.js +++ b/subPackages/sub_workbench/prescription_v2/utils/specialPrescription.js @@ -12,6 +12,54 @@ export function pickSpecialPrescriptionRecord(data) { ); } +/** + * 导入卡片规格文案:SKU 套餐名或单剂 + * @param record {{ sku_id?, sku_name? }|null} + */ +export function resolveSpecialPrescriptionPurchaseLabel(record) { + if (!record) return '' + return Number(record.sku_id) > 0 + ? (record.sku_name || 'SKU套餐') + : '单剂' +} + +/** + * 是否已导入特色方并锁定药方编辑 + * @param page 处方页实例 + */ +export function isSpecialPrescriptionCartLocked(page) { + if (!page) return false + return Number(page.appliedSpecialPrescriptionId) > 0 +} + +/** 特色方锁定提示文案 */ +export const SP_CART_LOCK_MSG = '特色方药方不可修改,请先清空药方' + +/** + * 特色方锁定中则 toast 并返回 true + * @param page 处方页实例 + */ +export function guardSpecialPrescriptionCartEdit(page) { + if (!isSpecialPrescriptionCartLocked(page)) return false + if (page.$toast) { + page.$toast(SP_CART_LOCK_MSG) + } else { + uni.showToast({ title: SP_CART_LOCK_MSG, icon: 'none' }) + } + return true +} + +/** + * 清空「已导入特色方」状态(普通开方/常用方时调用) + * @param page 处方页实例 + */ +export function clearAppliedSpecialPrescription(page) { + if (!page) return + page.appliedSpecialPrescriptionId = 0 + page.appliedSpecialPrescriptionExpectedTotal = null + page.appliedSpecialPrescriptionFreeShipping = false +} + /** * 将 apply 接口返回的数据写入处方页 state */ @@ -42,13 +90,18 @@ export function applySpecialPrescriptionPayload(page, data) { dayDosage: data.day_dosage ?? 2, packageMethodId: data.package_method_id ?? 2, }; - if (data.clinical_diagnose) { + if (data.clinical_diagnose !== undefined && data.clinical_diagnose !== null) { page.diagnosisText = data.clinical_diagnose; const names = String(data.clinical_diagnose).split(',').filter(Boolean); page.diagnoses = names.map((name, index) => ({ id: `temp_${index}`, name })); } - if (data.doctor_order) { + if (data.doctor_order !== undefined && data.doctor_order !== null) { page.medicalAdvice = data.doctor_order; } + page.appliedSpecialPrescriptionId = data.special_prescription_id || 0; + page.appliedSpecialPrescriptionFreeShipping = Number(data.is_free_shipping) === 1; + page.appliedSpecialPrescriptionExpectedTotal = data.expected_total_price != null + ? parseFloat(data.expected_total_price) + : null; page.saveToLocalStorage(); } diff --git a/subPackages/sub_workbench/workbench_infoPatient.vue b/subPackages/sub_workbench/workbench_infoPatient.vue index 494d60f..514acb5 100644 --- a/subPackages/sub_workbench/workbench_infoPatient.vue +++ b/subPackages/sub_workbench/workbench_infoPatient.vue @@ -57,6 +57,10 @@ 剂量 {{ infoList.special_prescription_patient_record.dose_count }} 剂 + + 规格 + {{ specialPrescriptionPurchaseLabel }} + { + this.$go(this.buildPrescriptionV2Url(registerId, patientId, importSpecial)); + }, 800); + }, // 接诊 - accept(e, pid) { - receptionApi(e).then((res) => { - if (this.apiOk(res)) { - this.$toast('已接诊'); - this.getList() - if (infoList.special_prescription_patient_record) { - return; - } - setTimeout(() => { - let url = `/subPackages/sub_workbench/prescription_v2/index?register_id=${e}`; - if (pid) url += `&patient_id=${pid}`; - this.$go(url); - }, 800) - } else { + accept(registerId, patientId) { + // 接诊前缓存特色方记录,避免 getList 异步刷新导致判断丢失 + const hasSp = !!this.infoList?.special_prescription_patient_record; + receptionApi(registerId).then((res) => { + if (!this.apiOk(res)) { this.$toast(this.apiMsg(res)); + return; } - }) + this.$toast('已接诊'); + this.getList(); + if (!hasSp) { + this.navigateToPrescriptionV2(registerId, patientId, false); + return; + } + uni.showModal({ + title: '导入特色方', + content: '该患者已选择特色方,是否立即导入?', + confirmColor: '#00A88A', + cancelColor: '#8A92A3', + success: (modalRes) => { + this.navigateToPrescriptionV2(registerId, patientId, !!modalRes.confirm); + }, + }); + }); }, // 结束问诊 acceptEnds(e) { @@ -540,7 +580,7 @@ export default { goToPrescriptionV2() { const registerId = this.infoList.id; const patientId = this.infoList.user_patient_id; - this.$go(`/subPackages/sub_workbench/prescription_v2/index?register_id=${registerId}&patient_id=${patientId}`); + this.$go(this.buildPrescriptionV2Url(registerId, patientId, false)); }, goImportSpecialPrescription() { const registerId = this.infoList.id; @@ -549,11 +589,7 @@ export default { this.$toast('挂号信息无效'); return; } - let url = `/subPackages/sub_workbench/prescription_v2/index?register_id=${registerId}&import_special=1`; - if (patientId) { - url += `&patient_id=${patientId}`; - } - this.$go(url); + this.$go(this.buildPrescriptionV2Url(registerId, patientId, true)); }, goToReusePrescription(prescriptionId) { const registerId = this.infoList.id;