509 lines
13 KiB
Vue
Raw Normal View History

2026-07-27 11:26:39 +08:00
<template>
<view class="page-container" :class="{ 'elder-mode': elderMode }">
<view class="search-container" :class="{ 'search-container--elder': elderMode }">
<view class="search" :class="{ 'search--elder': elderMode }">
<uni-icons class="search-icon" type="search" :size="elderMode ? 36 : 28"></uni-icons>
<input v-model="keyword" type="text" placeholder="搜索药品" class="search-input"
:class="{ 'search-input--elder': elderMode }" />
<view class="search-btn" :class="{ 'search-btn--elder': elderMode }" :style="keyword ? '' : 'opacity:0'"
@click="clear()">取消</view>
</view>
<view class="scan-code flex flex-col items-center" :class="{ 'scan-code--elder': elderMode }" @click="scanCode">
<uni-icons class="" color="#999" type="scan" :size="elderMode ? 36 : 30"></uni-icons>
<view v-if="order.consultType === 'onlineMedicinePurchase'" class="text-dark">条形码</view>
</view>
</view>
<view class="drug-wrapper">
<scroll-view scroll-y="true" class="drug-list" @scrolltolower="loadMore">
<view v-for="drug in list" :key="drug._id" class="drug" :class="{ 'drug--elder': elderMode }"
@click="select(drug)">
<view class="drug-info" :class="{ 'drug-info--elder': elderMode }">
<view class="drug-name" :class="{ 'drug-name--elder': elderMode }">{{ drug.name }}</view>
<view v-if="drug.medication_proof_desc" class="drug-proof-tip"
:class="{ 'drug-proof-tip--elder': elderMode }">{{ proofTipText }}</view>
<view v-if="drug.specification" class="drug-spec" :class="{ 'drug-spec--elder': elderMode }">药品规格{{
drug.specification }}</view>
<view v-if="drug.manufacturer" class="drug-spec" :class="{ 'drug-spec--elder': elderMode }">{{
drug.manufacturer }}</view>
</view>
<view v-if="selectMap[drug._id]" class="drug-btn drug-btn--unactive"
:class="{ 'drug-btn--elder': elderMode }">已选择</view>
<view v-else class="drug-btn" :class="{ 'drug-btn--elder': elderMode }">选择该药</view>
</view>
<uni-load-more v-if="loading && page > 1" status="loading"></uni-load-more>
<view v-if="list.length === 0 && order.consultType === 'onlineMedicinePurchase'"
class="lack-tip-container flex flex-col items-center justify-center" :style="elderVarStyle">
<image class="lack-img" :class="elderClass" src="/static/empty.svg" />
<view class="text-lg text-dark">搜索不到该药品</view>
<view class="pt-5" @click="showRegPopup()">
<text class="mr-5 text-lg text-dark">您可进行</text>
<text class="text-lg text-primary">缺货登记</text>
</view>
</view>
</scroll-view>
</view>
<view class="my-drugs-container">
<view v-if="showDrugs" class="shopcart-list">
<my-drugs :drugs="drugs" :elderMode="elderMode" @edit="edit" @remove="cancel" />
</view>
</view>
<view class="shopcart-footer" :class="{ 'shopcart-footer--elder': elderMode }" @click="showDrugs = !showDrugs">
<image class="shopcart-icon" :class="{ 'shopcart-icon--elder': elderMode }" src="/static/shopcart.svg" />
<view class="shopcart-text" :class="{ 'shopcart-text--elder': elderMode }">
<text>已选</text>
<text class="shopcart-num" :class="{ 'shopcart-num--elder': elderMode }">{{ drugs.length }}</text>
<text>种药品</text>
</view>
<view class="confirm-btn"
:class="[drugs.length ? '' : 'confirm-btn--unactive', { 'confirm-btn--elder': elderMode }]"
@click.stop="confirm">确认</view>
</view>
<view class="safearea-bottom" style="background: white;"></view>
</view>
<edit-popup :consultType="order.consultType" :drug="editDrug" :visible="showEditPopup" :elderMode="elderMode"
@close="showEditPopup = false" @change="changeDrug" />
<view v-if="showDrugs" class="mask" @click="showDrugs = false"></view>
<lack-reg-popup :order="order" :visible="visible" @close="visible = false" />
<!-- 自定义确认弹窗仅用于本页面 -->
<confirm-popup :visible="customConfirmVisible" :title="customConfirmData.title" :content="customConfirmData.content"
:showCancel="customConfirmData.showCancel" :cancelText="customConfirmData.cancelText"
:confirmText="customConfirmData.confirmText" @confirm="handleCustomConfirm" @cancel="handleCustomCancel"
@close="customConfirmVisible = false" />
</template>
<script setup>
import { computed, ref, onMounted, onUnmounted } from 'vue';
import { storeToRefs } from "pinia";
import { onLoad } from '@dcloudio/uni-app';
import useDebounce from '@/hooks/useDebounce';
import useRefChange from '@/hooks/useRefChange';
import useElder from '@/hooks/useElder';
import orderStore from '@/store/order';
import { getDrugs, getOnlineDrugList } from '@/utils/api'
import { toast } from '@/utils/widget';
import editPopup from './edit-popup.vue'
import myDrugs from './my-drugs.vue'
import lackRegPopup from './lack-reg-popup.vue'
import confirmPopup from '@/components/confirm-popup.vue'
// 长辈模式状态
const { elderMode, elderClass, elderVarStyle } = useElder();
const proofTipText = '*购买该药品需上传用药证明';
const { order } = storeToRefs(orderStore());
const keyword = ref('');
const drugs = ref([]);
const editDrug = ref({})
const editType = ref('add')
const showEditPopup = ref(false)
const showDrugs = ref(false)
const page = ref(1);
const list = ref([]);
const loading = ref(false)
const more = ref(false)
const visible = ref(false)
// 自定义确认弹窗状态(仅用于本页面)
const customConfirmVisible = ref(false);
const customConfirmData = ref({
title: '提示',
content: '',
showCancel: true,
cancelText: '取消',
confirmText: '确定',
onConfirm: null,
onCancel: null
});
const selectMap = computed(() => drugs.value.reduce((acc, cur) => {
acc[cur._id] = true;
return acc
}, {}))
useRefChange(keyword, search);
onLoad(() => {
drugs.value = order.value && Array.isArray(order.value.drugs) ? order.value.drugs.map(i => ({ ...i })) : [];
search()
})
// 监听全局确认弹窗事件(仅用于本页面)
onMounted(() => {
uni.$on('showConfirmPopup_selectDrug', showCustomConfirm);
});
onUnmounted(() => {
uni.$off('showConfirmPopup_selectDrug', showCustomConfirm);
});
function showCustomConfirm(data) {
customConfirmData.value = { ...customConfirmData.value, ...data };
customConfirmVisible.value = true;
}
function handleCustomConfirm() {
if (customConfirmData.value.onConfirm) {
customConfirmData.value.onConfirm();
}
customConfirmVisible.value = false;
customConfirmData.value.onConfirm = null;
customConfirmData.value.onCancel = null;
}
function handleCustomCancel() {
if (customConfirmData.value.onCancel) {
customConfirmData.value.onCancel();
}
customConfirmVisible.value = false;
customConfirmData.value.onConfirm = null;
customConfirmData.value.onCancel = null;
}
function edit(drug) {
showDrugs.value = false;
setTimeout(() => {
select(drug, 'edit')
}, 600);
}
function loadMore() {
if (!loading.value && more.value) {
page.value++;
getList()
}
}
function select(drug = {}, type = 'add') {
if (type === 'add' && drugs.value.length >= 5) {
toast('最多只能选择5种药品')
return
}
editDrug.value = { ...drug };
editType.value = type;
showEditPopup.value = true
}
function showRegPopup() {
visible.value = true
}
function cancel({ _id }) {
drugs.value = drugs.value.filter(item => item._id !== _id)
if (drugs.value.length === 0 && showDrugs.value) {
showDrugs.value = false
}
}
function changeDrug(drug) {
if (editType.value === 'add') {
if (!drugs.value.some(i => i._id === drug._id)) {
drugs.value.push(drug)
}
} else {
const index = drugs.value.findIndex(item => item._id === drug._id)
drugs.value.splice(index, 1, drug)
}
showEditPopup.value = false;
}
function clear() {
keyword.value = ''
}
const confirm = useDebounce(_confirm, 1000);
function _confirm() {
if (drugs.value.length) {
order.value.drugs = drugs.value.map(i => ({ ...i }))
uni.navigateBack()
} else {
toast('请添加药品')
}
}
function search() {
page.value = 1;
loading.value = false;
getList()
}
async function getList() {
if (loading.value) return;
loading.value = true;
const apiName = order.value.consultType === 'onlineMedicinePurchase' ? getOnlineDrugList : getDrugs;
const res = await apiName({ page: page.value, pageSize: 15, keyword: keyword.value });
const listData = res && Array.isArray(res.data) ? res.data : [];
list.value = page.value === 1 ? res.data : [...list.value, ...listData];
const message = res && typeof res.message === 'string' ? res.message : '获取药品失败';
if (!res || !res.success) {
toast(message)
}
loading.value = false;
more.value = res && res.pages > page.value;
}
function scanCode() {
uni.scanCode({
success: (res) => {
keyword.value = res.result
}
})
}
</script>
<style lang="scss" scoped>
@import '../drug.scss';
.page-container {
display: flex;
flex-direction: column;
height: 100%;
background: white;
}
.search-container {
padding: 24rpx;
display: flex;
align-items: center;
flex-shrink: 0;
}
.scan-code {
margin-left: 30rpx;
flex-shrink: 0;
}
.search {
width: 0;
flex-grow: 1;
flex-shrink: 0;
display: flex;
align-items: center;
background: #f5f6f7;
height: 100rpx;
border-radius: 50rpx;
padding: 0 40rpx 0 30rpx;
&-input {
flex-grow: 1;
margin: 0 20rpx 0 10rpx;
background-color: transparent;
}
&-btn {
flex-shrink: 0;
}
}
.drug-wrapper {
border-top: 1rpx solid #e5e5e5;
flex-grow: 1;
position: relative;
}
.drug-list {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.shopcart-footer {
display: flex;
align-items: center;
height: 120rpx;
background: #fff;
border-top: 1rpx solid #e5e5e5;
padding: 24rpx 30rpx;
flex-shrink: 0;
position: relative;
z-index: 2;
}
.shopcart-list {
position: absolute;
left: 0;
right: 0;
bottom: 0;
}
.my-drugs-container {
position: relative;
}
.shopcart-icon {
width: 80rpx;
height: 80rpx;
flex-shrink: 0;
}
.shopcart-num {
color: $theme-brown-primary;
font-size: 36rpx;
font-weight: bold;
margin: 0 10rpx;
}
.shopcart-text {
flex-grow: 1;
font-size: 28rpx;
color: #333;
margin: 0 16rpx;
}
.confirm-btn {
flex-shrink: 0;
width: 240rpx;
height: 80rpx;
background: $theme-brown-primary;
color: #fff;
font-size: 28rpx;
text-align: center;
line-height: 80rpx;
border-radius: 16rpx;
@at-root &--disabled {
background: #ccc;
}
}
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .1);
z-index: 1;
}
.drug-proof-tip {
color: #ff4757;
font-size: 24rpx;
line-height: 36rpx;
margin-top: 8rpx;
font-weight: 500;
}
/* 长辈模式样式 */
.elder-mode {
// 搜索容器样式
.search-container--elder {
padding: 36rpx 30rpx; // 24 * 1.5
}
.search--elder {
height: 120rpx; // 100 * 1.2
padding: 0 50rpx 0 40rpx; // 增加内边距
border-radius: 60rpx; // 50 * 1.2
}
.search-input--elder {
font-size: 36rpx; // 增大字体
margin: 0 25rpx 0 15rpx; // 调整间距
}
.search-btn--elder {
font-size: 36rpx; // 增大字体
font-weight: 600;
}
.scan-code--elder {
margin-left: 40rpx; // 30 * 1.33
}
// 药品列表样式
.drug--elder {
padding: 36rpx 30rpx; // 增加内边距
border-bottom: 2rpx solid #e5e5e5; // 加粗边框
}
.drug-info--elder {
flex: 1;
}
.drug-name--elder {
font-size: 42rpx; // 30 * 1.4
font-weight: bold;
line-height: 58rpx; // 42 * 1.38
margin-bottom: 12rpx; // 增加间距
}
.drug-spec--elder {
font-size: 36rpx; // 26 * 1.38
line-height: 50rpx; // 36 * 1.4
color: #666;
margin-bottom: 8rpx; // 增加间距
font-weight: 500;
}
.drug-proof-tip--elder {
color: #ff4757;
font-size: 32rpx; // 24 * 1.33
line-height: 48rpx; // 36 * 1.33
margin-top: 12rpx; // 8 * 1.5
font-weight: 600;
}
.drug-btn--elder {
font-size: 36rpx; // 28 * 1.29
padding: 16rpx 32rpx; // 12 * 1.33, 24 * 1.33
border-radius: 32rpx; // 24 * 1.33
min-width: 140rpx; // 增加最小宽度
text-align: center;
font-weight: bold;
border: 2rpx solid $theme-brown-primary; // 加粗边框
}
// 购物车底部样式
.shopcart-footer--elder {
height: 140rpx; // 120 * 1.17
padding: 30rpx 40rpx; // 增加内边距
border-top: 2rpx solid #e5e5e5; // 加粗边框
}
.shopcart-icon--elder {
width: 100rpx; // 80 * 1.25
height: 100rpx;
}
.shopcart-text--elder {
font-size: 36rpx; // 28 * 1.29
font-weight: 600;
margin: 0 20rpx; // 16 * 1.25
}
.shopcart-num--elder {
font-size: 44rpx; // 36 * 1.22
font-weight: bold;
margin: 0 12rpx; // 10 * 1.2
}
.confirm-btn--elder {
width: 280rpx; // 240 * 1.17
height: 96rpx; // 80 * 1.2
font-size: 36rpx; // 28 * 1.29
line-height: 96rpx;
border-radius: 20rpx; // 16 * 1.25
font-weight: bold;
}
}
.lack-tip-container {
height: 60vh;
}
.lack-img {
width: 240rpx;
height: 240rpx;
}
.lack-img.caring-mode-active {
width: 360rpx;
height: 360rpx;
}
</style>