diff --git a/api/reception.js b/api/reception.js index f9f6a6c..14d9638 100644 --- a/api/reception.js +++ b/api/reception.js @@ -11,6 +11,15 @@ export function getPatientList(data) { }) } +// 获取正在接诊的患者列表 +export function getAcceptingPatientList(data) { + return req.request({ + url: '/newApi/doctor-reception-wx/accepting-patient-list', + method: 'GET', + data + }) +} + // 获取患者详情 export function getPatientItem(id) { return req.request({ diff --git a/pages/workbench/index.vue b/pages/workbench/index.vue index 1022e59..5a6c420 100644 --- a/pages/workbench/index.vue +++ b/pages/workbench/index.vue @@ -74,6 +74,41 @@ + + + + 正在接诊 + + + + + + + + + + + + + + + + + + {{item.user_patient && item.user_patient.sex %2 != 0 ? '男' : '女'}} + {{item.user_patient && item.user_patient.age ? item.user_patient.age + '岁' : ''}} + + + + + + + + 消息通知 @@ -85,7 +120,7 @@ @@ -228,6 +259,25 @@ export default { } } return message_content; + }, + registerCardDrugNamesLine() { + if (this.msg.message_type !== 10) return ''; + const pc = this.parsedContent; + if (!pc || typeof pc !== 'object') return ''; + const arr = pc.selected_western_drugs; + if (Array.isArray(arr) && arr.length) { + return arr.map((d) => d && d.name).filter(Boolean).join('、'); + } + if (pc.drug && pc.drug.name) return pc.drug.name; + return ''; + }, + followUpAnsweredLabel() { + const pc = this.parsedContent; + if (!pc || pc.flow !== 'follow_up_drug') return ''; + const st = pc.answer_status; + if (st === 'yes' || st === '1') return '是,曾使用过'; + if (st === 'no' || st === '0') return '否,未使用过'; + return ''; } }, methods: { diff --git a/subPackages/sub_reception/reception_chat.vue b/subPackages/sub_reception/reception_chat.vue index 13bb964..c476f94 100644 --- a/subPackages/sub_reception/reception_chat.vue +++ b/subPackages/sub_reception/reception_chat.vue @@ -97,6 +97,44 @@ 点击查看处方详情 + + + + + 预约挂号 + + + 订单号{{ getParsedContent(msg).order_no }} + 主诉{{ getParsedContent(msg).chief_complaint }} + 所选药品{{ registerCardDrugLine(msg) }} + 数量各 {{ getParsedContent(msg).number }} 盒 + + + + + + + + + + {{ formatUnknownMessage(msg) }} @@ -186,7 +224,7 @@ const uploadBaseUrl = isDev ? 'http://127.0.0.1:18001/api/mobile' : 'https://api // 辅助函数 function getParsedContent(messageType, messageContent) { - if ([4, 9, 10, 11, 12, 13].includes(messageType)) { + if ([4, 9, 10, 11, 12, 13, 14].includes(messageType)) { try { return typeof messageContent === 'object' ? messageContent : JSON.parse(messageContent); } catch (e) { @@ -385,6 +423,10 @@ export default { // 获取消息头像 getMsgAvatar(msg) { + const sid = msg.sender_user_id || ''; + if (sid === 'doctor_assistant') { + return 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk_upload_20250108/29bdb9560340373bb3096394a845afa5.jpg'; + } if (this.isMsgMine(msg)) { // 医生头像 return uni.getStorageSync('doctor_avatar') || 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk_upload_20250108/29bdb9560340373bb3096394a845afa5.jpg'; @@ -393,6 +435,33 @@ export default { return this.patientInfo?.user_patient?.avatar || 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk_upload_20250108/29bdb9560340373bb3096394a845afa5.jpg'; } }, + + registerCardDrugLine(msg) { + const pc = getParsedContent(msg.message_type, msg.message_content); + if (!pc || typeof pc !== 'object') return ''; + const arr = pc.selected_western_drugs; + if (Array.isArray(arr) && arr.length) { + return arr.map((d) => d && d.name).filter(Boolean).join('、'); + } + if (pc.drug && pc.drug.name) return pc.drug.name; + return ''; + }, + + followUpAnswerLine(msg) { + const pc = getParsedContent(msg.message_type, msg.message_content); + if (!pc || pc.flow !== 'follow_up_drug') return ''; + const st = pc.answer_status; + if (st === 'yes' || st === '1') return '是,曾使用过'; + if (st === 'no' || st === '0') return '否,未使用过'; + return ''; + }, + + formatUnknownMessage(msg) { + if (msg.message_content == null) return '[消息]'; + if (typeof msg.message_content === 'object') return '[卡片消息]'; + const s = String(msg.message_content); + return s.length > 120 ? s.slice(0, 120) + '…' : s; + }, // 解析消息内容 getParsedContent(msg) { @@ -1090,6 +1159,32 @@ $bg-white: #ffffff; } } +.register-msg-card { + background: #fff; + border: 1rpx solid #e8e8e8; + border-radius: 12rpx; + padding: 16rpx 20rpx; + max-width: 520rpx; + .rmc-head { + margin-bottom: 12rpx; + .rmc-title { font-size: 28rpx; font-weight: 600; color: #333; } + } + .rmc-body { + display: flex; + flex-direction: column; + gap: 10rpx; + .rmc-q { font-size: 26rpx; color: #333; line-height: 1.4; } + .rmc-row { + display: flex; + justify-content: space-between; + font-size: 24rpx; + gap: 12rpx; + .k { color: #888; flex-shrink: 0; } + .v { color: #333; text-align: right; word-break: break-all; } + } + } +} + .recording-overlay { position: fixed; top: 0; diff --git a/subPackages/sub_workbench/prescription_v2/components/modals/ChineseMedicineModal.vue b/subPackages/sub_workbench/prescription_v2/components/modals/ChineseMedicineModal.vue index 58a0495..9272730 100644 --- a/subPackages/sub_workbench/prescription_v2/components/modals/ChineseMedicineModal.vue +++ b/subPackages/sub_workbench/prescription_v2/components/modals/ChineseMedicineModal.vue @@ -38,7 +38,7 @@ class="drug-item white b-r-8 p-32 m-t-2" v-for="(item, index) in drugList" :key="item.id || index" - :class="{ selected: isSelected(item) }" + :class="{ selected: isInSelected(item) }" > @@ -47,7 +47,7 @@ - 已选 + 已选 - - 用量: - - - - - + + + + 用量: + + - + + + + + {{ getUnitName(item) }} + + + + + + - {{ getUnitName(item) }} @@ -105,15 +123,18 @@ - + 取消 - 确定 + shape="circle" + :custom-style="{ + backgroundColor: '#6ACDBB', + color: '#fff', + height: '86rpx', + width: '670rpx' + }" + >关闭 @@ -207,8 +228,15 @@ export default { const list = res.data || res.result || []; this.hasMore = list.length >= this.pageSize; // 合并已选中的药品数量,使用 $set 确保响应式 + // 匹配优先级:selectedDrugs.index_id === drug.id,再 fallback 到 entity id const merged = list.map(drug => { - const selected = this.selectedDrugs.find(item => (item.id || item.drug_id) === drug.id); + const entityId = (drug.drug && drug.drug.id) || drug.id; + const selected = this.selectedDrugs.find(item => { + const matchByIndexId = (item.index_id !== undefined && item.index_id !== null) && item.index_id === drug.id; + const matchByEntityId = (item.id !== undefined && item.id !== null) && item.id === entityId; + const matchByDrugId = (item.drug_id !== undefined && item.drug_id !== null) && item.drug_id === entityId; + return matchByIndexId || matchByEntityId || matchByDrugId; + }); // 直接使用原对象,使用 $set 添加响应式属性 this.$set(drug, '_quantity', selected ? selected.number : 0); return drug; @@ -320,7 +348,7 @@ export default { }, /** - * 判断是否已选中该中药 + * 判断是否已选中该中药(基于父组件传入的 currentDrugs,初始展示用) * @param {Object} drug * @returns {boolean} */ @@ -329,6 +357,141 @@ export default { const id = drug.id || drug.drug_id; return this.currentDrugs.some(item => (item.id || item.drug_id) === id); }, + + /** + * 判断是否已加入本次会话的处方(基于实时 selectedDrugs) + * @param {Object} drug + * @returns {boolean} + */ + isInSelected(drug) { + return this.findSelectedIndex(drug) !== -1; + }, + + /** + * 在 selectedDrugs 中查找当前 drug 对应的索引 + * 匹配优先级:index_id === drug.id;否则 id === drug.drug?.id || drug.id + * @param {Object} drug + * @returns {number} 找到返回索引,未找到返回 -1 + */ + findSelectedIndex(drug) { + if (!drug || !Array.isArray(this.selectedDrugs)) return -1; + const listId = drug.id; + const entityId = (drug.drug && drug.drug.id) || drug.id; + return this.selectedDrugs.findIndex(item => { + const matchByIndexId = (item.index_id !== undefined && item.index_id !== null) && item.index_id === listId; + const matchByEntityId = (item.id !== undefined && item.id !== null) && item.id === entityId; + const matchByDrugId = (item.drug_id !== undefined && item.drug_id !== null) && item.drug_id === entityId; + return matchByIndexId || matchByEntityId || matchByDrugId; + }); + }, + + /** + * 把 drugList 中某个药品转成 selectedDrugs 的标准条目 + * 字段与原 handleConfirm 中保持一致 + * @param {Object} drug + * @returns {Object} + */ + buildSelectedItem(drug) { + let drugName = ''; + if (drug.drug && drug.drug.drug_name) { + drugName = drug.drug.drug_name; + } else if (drug.drug_name) { + drugName = drug.drug_name; + } else if (drug.name) { + drugName = drug.name; + } + return { + index_id: drug.id, + id: (drug.drug && drug.drug.id) || drug.id, + drug_name: drugName, + number: drug._quantity, + price: drug.price || 0, + way_id: (drug.drug && drug.drug.way_id) || drug.way_id || 0, + select_number: 1 + }; + }, + + /** + * emit select 事件,传出当前完整的 selectedDrugs(深拷贝) + */ + emitSelect() { + const payload = JSON.parse(JSON.stringify(this.selectedDrugs)); + this.$emit('select', payload); + }, + + /** + * 添加药品到处方 + * @param {Event} event - 点击事件对象 + */ + handleAddDrug(event) { + const index = event.currentTarget.dataset.index; + if (index === undefined || index === null) { + console.error('handleAddDrug: index is undefined'); + return; + } + const drug = this.drugList[index]; + if (!drug) { + console.error('handleAddDrug: drug not found at index', index); + return; + } + + // 用量为空或 0 时,默认设为 1 + if (!drug._quantity || drug._quantity <= 0) { + this.$set(drug, '_quantity', 1); + } + + // 已经在 selectedDrugs 中则只更新数量 + const existIndex = this.findSelectedIndex(drug); + if (existIndex !== -1) { + this.$set(this.selectedDrugs[existIndex], 'number', drug._quantity); + } else { + this.selectedDrugs.push(this.buildSelectedItem(drug)); + } + this.emitSelect(); + this.$toast(`已将${this.getDrugName(drug)}添加到处方`); + }, + + /** + * 从处方中移除药品 + * @param {Event} event - 点击事件对象 + */ + handleRemoveDrug(event) { + const index = event.currentTarget.dataset.index; + if (index === undefined || index === null) { + console.error('handleRemoveDrug: index is undefined'); + return; + } + const drug = this.drugList[index]; + if (!drug) { + console.error('handleRemoveDrug: drug not found at index', index); + return; + } + + const existIndex = this.findSelectedIndex(drug); + if (existIndex !== -1) { + this.selectedDrugs.splice(existIndex, 1); + } + this.$set(drug, '_quantity', 0); + this.emitSelect(); + }, + + /** + * 把 drug 的最新 _quantity 同步到 selectedDrugs 中(如果已加入处方) + * 用于 +/-、输入、点击常用克数后实时同步 + * @param {Object} drug + */ + syncQuantityToSelected(drug) { + const existIndex = this.findSelectedIndex(drug); + if (existIndex === -1) return; + const newNumber = drug._quantity || 0; + if (newNumber <= 0) { + // 数量被改为 0,从处方中移除 + this.selectedDrugs.splice(existIndex, 1); + } else { + this.$set(this.selectedDrugs[existIndex], 'number', newNumber); + } + this.emitSelect(); + }, /** * 增加数量 @@ -357,6 +520,7 @@ export default { this.$set(drug, '_quantity', 0); } this.$set(drug, '_quantity', (drug._quantity || 0) + 1); + this.syncQuantityToSelected(drug); }, /** @@ -388,6 +552,7 @@ export default { } if (drug._quantity > 0) { this.$set(drug, '_quantity', drug._quantity - 1); + this.syncQuantityToSelected(drug); } }, @@ -428,8 +593,10 @@ export default { if (!isNaN(numValue) && numValue >= 0) { this.$set(drug, '_quantity', numValue); + this.syncQuantityToSelected(drug); } else if (value === '') { this.$set(drug, '_quantity', 0); + this.syncQuantityToSelected(drug); } }, @@ -467,6 +634,7 @@ export default { } // 设置数量 this.$set(drug, '_quantity', quantity); + this.syncQuantityToSelected(drug); }, /** @@ -481,45 +649,10 @@ export default { this.loadDrugList(this.searchKey); }, - /** - * 确认选择 - * 职责:将选中的药品传递给父组件 - */ - handleConfirm() { - // 过滤出数量大于0的药品 - // 参考PC端:index_id 使用 drug.id(列表项ID),id 使用 drug.drug.id(药品本身的ID) - const selected = this.drugList - .filter(drug => drug._quantity > 0) - .map(drug => { - // 获取药品名称 - let drugName = ''; - if (drug.drug && drug.drug.drug_name) { - drugName = drug.drug.drug_name; - } else if (drug.drug_name) { - drugName = drug.drug_name; - } else if (drug.name) { - drugName = drug.name; - } - - // 参考PC端数据结构:index_id, id, drug_name, number, price, way_id, select_number - return { - index_id: drug.id, // 列表项ID(对应PC端的 data.id) - id: drug.drug?.id || drug.id, // 药品本身的ID(对应PC端的 data.drug.id) - drug_name: drugName, - number: drug._quantity, - price: drug.price || 0, - way_id: drug.drug?.way_id || drug.way_id || 0, // 用法ID(对应PC端的 data.drug?.way_id) - select_number: 1 // 默认为1(与PC端一致) - }; - }); - - this.$emit('select', selected); - this.handleClose(); - }, - /** * 关闭弹窗 * 职责:关闭弹窗,触发input事件 + * 注:由于 add/remove/调用量都是实时 emit,关闭无需额外提交 */ handleClose() { this.show = false; @@ -626,6 +759,28 @@ export default { align-items: center; } +.quantity-input-left { + display: flex; + flex-direction: row; + align-items: center; + gap: 16rpx; + flex: 1; + min-width: 0; +} + +.action-icon { + width: 64rpx; + height: 64rpx; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.action-icon:active { + opacity: 0.7; +} + .quantity-label { font-size: 28rpx; color: #6C7380; @@ -673,13 +828,15 @@ export default { .modal-footer { display: flex; - gap: 24rpx; + flex-direction: row; + align-items: center; + justify-content: center; padding: 32rpx; border-top: 1rpx solid #eee; - - .u-button { - flex: 1; - } + background-color: #fff; + position: sticky; + bottom: 0; + z-index: 10; } .white { @@ -711,6 +868,10 @@ export default { justify-content: space-between; } +.flex-jus-center { + justify-content: center; +} + .flex-ali-center { align-items: center; } diff --git a/subPackages/sub_workbench/prescription_v2/components/modals/SimpleProductModal.vue b/subPackages/sub_workbench/prescription_v2/components/modals/SimpleProductModal.vue index 0555ad5..ae56fd2 100644 --- a/subPackages/sub_workbench/prescription_v2/components/modals/SimpleProductModal.vue +++ b/subPackages/sub_workbench/prescription_v2/components/modals/SimpleProductModal.vue @@ -32,23 +32,32 @@ class="product-item white b-r-8 p-32 m-t-2" v-for="item in productList" :key="item.id" - @click="handleSelectProduct(item)" > - - - - - - - - - - 选择 - + + + + + + + + + + + + + 选择 + + + @@ -58,6 +67,32 @@ + + + + 取消 + 确定 + @@ -221,6 +256,23 @@ export default { margin-bottom: 16rpx; } +.product-content { + gap: 24rpx; +} + +.product-image { + width: 120rpx; + height: 120rpx; + border-radius: 8rpx; + flex-shrink: 0; + background-color: #f5f5f5; +} + +.product-info-wrapper { + min-width: 0; + flex: 1; +} + .product-header { margin-bottom: 16rpx; } @@ -235,7 +287,7 @@ export default { } .empty-state { - padding: 100rpx 0; + //padding: 100rpx 0; text-align: center; } @@ -283,4 +335,17 @@ export default { .bold { font-weight: bold; } + +.modal-footer { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding: 32rpx; + border-top: 1rpx solid #eee; + background-color: #fff; + position: sticky; + bottom: 0; + z-index: 10; +} diff --git a/subPackages/sub_workbench/prescription_v2/components/modals/WesternMedicineModal.vue b/subPackages/sub_workbench/prescription_v2/components/modals/WesternMedicineModal.vue index bf27f55..c116c1c 100644 --- a/subPackages/sub_workbench/prescription_v2/components/modals/WesternMedicineModal.vue +++ b/subPackages/sub_workbench/prescription_v2/components/modals/WesternMedicineModal.vue @@ -79,6 +79,32 @@ + + + + 取消 + 确定 + @@ -291,6 +317,7 @@ export default { .empty-state { padding: 100rpx 0; + align-items: center; text-align: center; } @@ -342,4 +369,17 @@ export default { .bold { font-weight: bold; } + +.modal-footer { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding: 32rpx; + border-top: 1rpx solid #eee; + background-color: #fff; + position: sticky; + bottom: 0; + z-index: 10; +} diff --git a/subPackages/sub_workbench/prescription_v2/index.vue b/subPackages/sub_workbench/prescription_v2/index.vue index 2873b3a..79b2a58 100644 --- a/subPackages/sub_workbench/prescription_v2/index.vue +++ b/subPackages/sub_workbench/prescription_v2/index.vue @@ -197,17 +197,43 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + - + + + + + + + + + @@ -1155,17 +1181,17 @@ export default { } // 添加到列表 + // 参考PC端:index_id, id, drug_name, number, price, image, instruction, type, select_number const newProduct = { index_id: product.id, id: product.drug_id || product.drug?.id || product.id, - drug_id: product.drug_id || product.drug?.id || product.id, drug_name: product.drug_name || product.drug?.drug_name || product.name, number: 1, - select_number: 1, price: product.price || 0, - specification: product.specification || product.drug?.specification || '', image: product.image || product.drug?.image || '', - instruction: product.instruction || product.drug?.instruction || '' + instruction: product.instruction || product.drug?.instruction || '', + type: product.drug?.type || product.type || this.activeCategory, + select_number: 1 }; this.currentDrugs.push(newProduct); @@ -1236,6 +1262,52 @@ export default { }); }, + /** + * 增加简单产品数量 + * @param {number} index - 产品索引 + * 职责:增加简单产品的数量 + */ + handleIncrementSimpleProduct(index) { + if (index >= 0 && index < this.currentDrugs.length) { + const product = this.currentDrugs[index]; + const currentNumber = product.select_number || product.number || 1; + this.$set(product, 'select_number', currentNumber + 1); + // 保存到本地存储 + this.saveToLocalStorage(); + } + }, + + /** + * 减少简单产品数量 + * @param {number} index - 产品索引 + * 职责:减少简单产品的数量,如果为1则提示删除 + */ + handleDecrementSimpleProduct(index) { + if (index >= 0 && index < this.currentDrugs.length) { + const product = this.currentDrugs[index]; + const currentNumber = product.select_number || product.number || 1; + if (currentNumber > 1) { + this.$set(product, 'select_number', currentNumber - 1); + // 保存到本地存储 + this.saveToLocalStorage(); + } else { + // 数量为1时,提示是否删除 + uni.showModal({ + title: '删除产品', + content: '数量为1时,是否要删除该产品?', + showCancel: true, + success: ({ confirm }) => { + if (confirm) { + this.currentDrugs.splice(index, 1); + // 保存到本地存储 + this.saveToLocalStorage(); + } + } + }); + } + } + }, + /** * 删除所有药品(中药) * 职责:清空中药列表,保存到本地存储 @@ -1630,6 +1702,30 @@ export default { select_number: drug.select_number || 1 // 选择数量 }; + return cleanDrug; + }); + } else if ([3, 5, 6, 7].includes(this.activeCategory)) { + // 简单产品(保健食品、产品服务包、非药品、医疗器械):参考PC端,不需要用法用量 + // PC端字段:index_id, id, drug_name, number, price, image, instruction, type, select_number + drugsData = this.currentDrugs.map((drug) => { + const cleanDrug = { + index_id: drug.index_id, + id: drug.id, + drug_name: drug.drug_name || drug.name, + number: drug.number || 1, + price: drug.price || '0.0000', + select_number: drug.select_number || 1 + }; + // 可选字段:image, instruction, type(如果存在则保留) + if (drug.image) { + cleanDrug.image = drug.image; + } + if (drug.instruction) { + cleanDrug.instruction = drug.instruction; + } + if (drug.type) { + cleanDrug.type = drug.type; + } return cleanDrug; }); } else { @@ -1903,6 +1999,20 @@ export default { margin-right: 16rpx; } +.m-l-16 { + margin-left: 16rpx; +} + +.m-r-16 { + margin-right: 16rpx; +} + +.quantity-control { + display: flex; + align-items: center; + gap: 16rpx; +} + .flex { display: flex; } @@ -1986,12 +2096,17 @@ export default { background: #fff; border-top: 1px solid #f0f0f0; z-index: 99; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; } .btnText { color: #6ACDBB; font-size: 28rpx; padding: 0 32rpx; + flex-shrink: 0; } .label {