1. 医生端开方2.0测试

This commit is contained in:
李琦
2026-05-07 11:04:56 +08:00
parent 11b1c86a08
commit b862fc1817
8 changed files with 697 additions and 108 deletions

View File

@@ -115,10 +115,41 @@
<view class="info-row"><text class="label">订单号</text><text class="value order-font">{{ parsedContent.order_no }}</text></view>
<view class="info-row"><text class="label">就诊人</text><text class="value">{{ (parsedContent.user_patient && parsedContent.user_patient.name) || '未知' }}</text></view>
<view class="info-row highlight"><text class="label">费用</text><text class="value price">¥{{ parsedContent.price }}</text></view>
<view class="text-block" v-if="parsedContent.chief_complaint">
<text class="block-label">主诉</text>
<text class="block-content">{{ parsedContent.chief_complaint }}</text>
</view>
<view class="info-row" v-if="registerCardDrugNamesLine">
<text class="label">所选药品</text>
<text class="value">{{ registerCardDrugNamesLine }}</text>
</view>
<view class="info-row" v-if="parsedContent.number != null && parsedContent.number !== ''">
<text class="label">数量</text>
<text class="value"> {{ parsedContent.number }} </text>
</view>
</view>
<view class="card-footer"><button class="action-btn" @click="$emit('viewRegister', parsedContent.id)">查看详情</button></view>
</block>
<block v-else-if="msg.message_type === 11 && parsedContent && parsedContent.flow === 'follow_up_drug'">
<view class="card-header bg-gray">
<view class="title-group"><u-icon name="question-circle-fill" size="16" color="#64748B"></u-icon><text class="card-title">医生助理</text></view>
</view>
<view class="card-body">
<view class="text-block" v-if="parsedContent.question">
<text class="block-content">{{ parsedContent.question }}</text>
</view>
<view class="info-row" v-for="(row, idx) in (parsedContent.drugs || [])" :key="'dfd-' + idx">
<text class="label">{{ row.name || '药品' }}</text>
<text class="value">×{{ row.quantity != null ? row.quantity : 1 }}</text>
</view>
<view v-if="followUpAnsweredLabel" class="info-row">
<text class="label">患者选择</text>
<text class="value">{{ followUpAnsweredLabel }}</text>
</view>
</view>
</block>
<!-- 类型11: 患者就诊经历 -->
<block v-else-if="msg.message_type === 11">
<view class="card-header bg-gray">
@@ -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: {

View File

@@ -97,6 +97,44 @@
<text class="card-text">点击查看处方详情</text>
</view>
</view>
<!-- 挂号卡片 type10 -->
<view v-else-if="msg.message_type === 10" class="register-msg-card">
<view class="rmc-head">
<text class="rmc-title">预约挂号</text>
</view>
<view class="rmc-body">
<view class="rmc-row" v-if="getParsedContent(msg).order_no"><text class="k">订单号</text><text class="v">{{ getParsedContent(msg).order_no }}</text></view>
<view class="rmc-row" v-if="getParsedContent(msg).chief_complaint"><text class="k">主诉</text><text class="v">{{ getParsedContent(msg).chief_complaint }}</text></view>
<view class="rmc-row" v-if="registerCardDrugLine(msg)"><text class="k">所选药品</text><text class="v">{{ registerCardDrugLine(msg) }}</text></view>
<view class="rmc-row" v-if="getParsedContent(msg).number != null && getParsedContent(msg).number !== ''"><text class="k">数量</text><text class="v"> {{ getParsedContent(msg).number }} </text></view>
</view>
</view>
<!-- type11复诊助理 / 患者就诊经历 -->
<view v-else-if="msg.message_type === 11" class="register-msg-card">
<template v-if="getParsedContent(msg).flow === 'follow_up_drug'">
<view class="rmc-head"><text class="rmc-title">医生助理</text></view>
<view class="rmc-body">
<text class="rmc-q">{{ getParsedContent(msg).question }}</text>
<view class="rmc-row" v-for="(row, iix) in (getParsedContent(msg).drugs || [])" :key="'rxd-' + iix">
<text class="k">{{ row.name || '药品' }}</text>
<text class="v">×{{ row.quantity != null ? row.quantity : 1 }}</text>
</view>
<view class="rmc-row" v-if="followUpAnswerLine(msg)"><text class="k">患者选择</text><text class="v">{{ followUpAnswerLine(msg) }}</text></view>
</view>
</template>
<template v-else>
<view class="rmc-head"><text class="rmc-title">患者就诊经历</text></view>
<view class="rmc-body">
<view class="rmc-row" v-if="getParsedContent(msg).drug_name"><text class="k">药品</text><text class="v">{{ getParsedContent(msg).drug_name }}</text></view>
<view class="rmc-row"><text class="k">是否就诊过</text><text class="v">{{ getParsedContent(msg).has_visited === '1' ? '是' : '否' }}</text></view>
<view class="rmc-row"><text class="k">是否用过药</text><text class="v">{{ getParsedContent(msg).has_used_drug === '1' ? '是' : '否' }}</text></view>
</view>
</template>
</view>
<text v-else class="text-content">{{ formatUnknownMessage(msg) }}</text>
</view>
</view>
</view>
@@ -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;

View File

@@ -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) }"
>
<view class="drug-header flex-row flex-jus-sp flex-ali-center">
<d-text :text="getDrugName(item)" className="fs-3 color0 bold"></d-text>
@@ -47,7 +47,7 @@
<view class="drug-info m-t-16">
<view class="specification-row flex-row flex-jus-sp flex-ali-center m-b-16">
<d-text :text="`规格:${getSpecification(item)}`" className="fs-24 color9"></d-text>
<view class="selected-tag" v-if="isSelected(item)">已选</view>
<view class="selected-tag" v-if="isInSelected(item)">已选</view>
</view>
<view class="common-quantity-tags m-b-16" v-if="commonQuantities.length > 0">
<view
@@ -61,29 +61,47 @@
{{ qty }}g
</view>
</view>
<view class="quantity-input-row flex-row flex-ali-center">
<view class="quantity-label">用量</view>
<view class="quantity-input-wrapper flex-row flex-ali-center">
<view
class="quantity-btn"
@click.stop="handleDecreaseQuantity"
:data-index="index"
>-</view>
<input
class="quantity-input"
type="number"
:value="getQuantity(item)"
@input="handleQuantityInput"
:data-index="index"
placeholder="请输入"
/>
<view
class="quantity-btn"
@click.stop="handleIncreaseQuantity"
:data-index="index"
>+</view>
<view class="quantity-input-row flex-row flex-ali-center flex-jus-sp">
<view class="quantity-input-left flex-row flex-ali-center">
<view class="quantity-label">用量</view>
<view class="quantity-input-wrapper flex-row flex-ali-center">
<view
class="quantity-btn"
@click.stop="handleDecreaseQuantity"
:data-index="index"
>-</view>
<input
class="quantity-input"
type="number"
:value="getQuantity(item)"
@input="handleQuantityInput"
:data-index="index"
placeholder="请输入"
/>
<view
class="quantity-btn"
@click.stop="handleIncreaseQuantity"
:data-index="index"
>+</view>
</view>
<text class="unit-text">{{ getUnitName(item) }}</text>
</view>
<view
v-if="isInSelected(item)"
class="action-icon delete-icon"
@click.stop="handleRemoveDrug"
:data-index="index"
>
<u-icon name="trash" size="44" color="#FC3636"></u-icon>
</view>
<view
v-else
class="action-icon add-icon"
@click.stop="handleAddDrug"
:data-index="index"
>
<u-icon name="plus-circle" size="44" color="#6ACDBB"></u-icon>
</view>
<text class="unit-text">{{ getUnitName(item) }}</text>
</view>
</view>
</view>
@@ -105,15 +123,18 @@
</view>
<!-- 底部按钮 -->
<view class="modal-footer">
<view class="modal-footer flex-jus-center flex-ali-center">
<u-button
:throttle-time="0"
@click="handleClose"
:custom-style="{ backgroundColor: '#f5f5f5', color: '#333' }"
>取消</u-button>
<u-button
@click="handleConfirm"
:custom-style="{ backgroundColor: '#6ACDBB', color: '#fff' }"
>确定</u-button>
shape="circle"
:custom-style="{
backgroundColor: '#6ACDBB',
color: '#fff',
height: '86rpx',
width: '670rpx'
}"
>关闭</u-button>
</view>
</view>
</u-popup>
@@ -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列表项IDid 使用 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;
}

View File

@@ -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)"
>
<view class="product-header flex-row flex-jus-sp flex-ali-center">
<d-text :text="item.drug.drug_name || item.drug.name" className="fs-3 color0 bold"></d-text>
<d-text :text="`¥${parseFloat(item.price || 0).toFixed(2)}`" className="fs-3 error-c"></d-text>
</view>
<view class="product-info m-t-16">
<d-text :text="`规格:${item.drug.specification || '--'}`" className="fs-24 color9"></d-text>
</view>
<view class="product-action m-t-16">
<u-button
size="mini"
:custom-style="{ backgroundColor: '#6ACDBB', color: '#fff' }"
@click.stop="handleSelectProduct(item)"
>
选择
</u-button>
<view class="product-content flex-row">
<image
v-if="(item.drug && item.drug.image) || item.image"
:src="(item.drug && item.drug.image) || item.image"
class="product-image"
mode="aspectFill"
></image>
<view class="product-info-wrapper flex-1">
<view class="product-header flex-row flex-jus-sp flex-ali-center">
<d-text :text="item.drug.drug_name || item.drug.name" className="fs-3 color0 bold"></d-text>
<d-text :text="`¥${parseFloat(item.price || 0).toFixed(2)}`" className="fs-3 error-c"></d-text>
</view>
<view class="product-info m-t-16">
<d-text :text="`规格:${item.drug.specification || '--'}`" className="fs-24 color9"></d-text>
</view>
<view class="product-action m-t-16">
<u-button
size="mini"
:custom-style="{ backgroundColor: '#6ACDBB', color: '#fff' }"
@click.stop="handleSelectProduct(item)"
>
选择
</u-button>
</view>
</view>
</view>
</view>
</view>
@@ -58,6 +67,32 @@
<d-empty text="暂无产品"></d-empty>
</view>
</view>
<!-- 底部按钮 -->
<view class="modal-footer flex-jus-sp flex-ali-center">
<u-button
:throttle-time="0"
@click="handleClose"
shape="circle"
:custom-style="{
backgroundColor: '#f5f5f5',
color: '#333',
height: '86rpx',
width: '320rpx'
}"
>取消</u-button>
<u-button
:throttle-time="0"
@click="handleClose"
shape="circle"
:custom-style="{
backgroundColor: '#6ACDBB',
color: '#fff',
height: '86rpx',
width: '320rpx'
}"
>确定</u-button>
</view>
</view>
</u-popup>
</template>
@@ -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;
}
</style>

View File

@@ -79,6 +79,32 @@
<d-empty text="暂无药品"></d-empty>
</view>
</view>
<!-- 底部按钮 -->
<view class="modal-footer flex-jus-sp flex-ali-center">
<u-button
:throttle-time="0"
@click="handleClose"
shape="circle"
:custom-style="{
backgroundColor: '#f5f5f5',
color: '#333',
height: '86rpx',
width: '320rpx'
}"
>取消</u-button>
<u-button
:throttle-time="0"
@click="handleClose"
shape="circle"
:custom-style="{
backgroundColor: '#6ACDBB',
color: '#fff',
height: '86rpx',
width: '320rpx'
}"
>确定</u-button>
</view>
</view>
</u-popup>
</template>
@@ -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;
}
</style>

View File

@@ -197,17 +197,43 @@
</view>
</view>
<view class="bottom-border p-col-32" v-for="(item, index) in currentDrugs" :key="index">
<view class="flex-row flex-jus-sp flex-ali-center">
<d-text :text="`${index+1}、${item.drug_name}`" className="fs-3 content-c"></d-text>
<d-text :text="`¥${parseFloat(item.price || 0).toFixed(2)}`" className="error-c fs-3"></d-text>
</view>
<view class="flex-row flex-ali-center flex-jus-sp m-t-16">
<view class="flex-row flex-ali-center m-t-16">
<d-text text="规格:" color="#6C7380"></d-text>
<d-text :text="item.specification || '--'" color="#6C7380"></d-text>
</view>
<view class="flex-row flex-ali-center m-t-16">
<d-text :text="`${item.select_number || item.number}${getProductUnit(activeCategory)}`" color="#6C7380"></d-text>
<view class="drug-item-content flex-row">
<image
v-if="item.image"
:src="item.image"
class="drug-image"
mode="aspectFill"
></image>
<view class="drug-info-wrapper flex-1">
<view class="flex-row flex-jus-sp flex-ali-center">
<d-text :text="`${index+1}、${item.drug_name}`" className="fs-3 content-c"></d-text>
<d-text :text="`${parseFloat(item.price || 0).toFixed(2)}`" className="error-c fs-3"></d-text>
</view>
<view class="flex-row flex-ali-center flex-jus-sp m-t-16">
<view class="flex-row flex-ali-center m-t-16">
<d-text text="规格:" color="#6C7380"></d-text>
<d-text :text="item.specification || '--'" color="#6C7380"></d-text>
</view>
<view class="flex-row flex-ali-center m-t-16">
<view class="quantity-control flex-row flex-ali-center">
<u-button
size="mini"
:custom-style="{ backgroundColor: '#6ACDBB', color: '#fff', width: '48rpx', height: '48rpx', padding: 0 }"
@click.stop="handleDecrementSimpleProduct(index)"
>
-
</u-button>
<d-text :text="`${item.select_number || item.number}${getProductUnit(activeCategory)}`" color="#6C7380" className="m-l-16 m-r-16"></d-text>
<u-button
size="mini"
:custom-style="{ backgroundColor: '#6ACDBB', color: '#fff', width: '48rpx', height: '48rpx', padding: 0 }"
@click.stop="handleIncrementSimpleProduct(index)"
>
+
</u-button>
</view>
</view>
</view>
</view>
</view>
<view class="m-t-24 flex-row flex-jus-sa btnBox">
@@ -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 {