hn-hlw-app/pages/consult/disease-description.vue
2026-07-27 11:26:39 +08:00

517 lines
11 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<full-page :animation="true" ref="pageRef" mainStyle="background:#f0f0f0" @reachBottom="onReachBottom()">
<view class="container" :class="{ 'elder-mode-active': elderMode }">
<view class="user-header shadow-lg">
就诊人{{ form.name }} {{ form.sex }} {{ form.age ? `${form.age}` : '' }}
</view>
<!-- <view class="relative mt-12 px-15 py-12 bg-white shadow-lg" @click="toAddDisease()">
<view class="section-title is-required">已在实体医疗机构确诊的疾病</view>
<view class="disease-tags">
<view v-for="(i, idx) in form.diseases" class="disease-tag" @click.stop="() => { }">
<text>{{ i }}</text>
<text class="disease-remove" @click.stop="removeDisease(idx)"> <uni-icons type="closeempty" color="#b8956a"
size="14"></uni-icons> </text>
</view>
<view class="disease-tag add-tag">+ 添加</view>
</view>
</view> -->
<view class="description-section relative mt-12 px-15 py-12 bg-white shadow-lg">
<view class="section-title is-required">请描述您的病情</view>
<textarea v-model="form.description" :show-confirm-bar="false" auto-height="true" class="mt-10 description"
placeholder-class="placeholderClass" maxlength="300" placeholder="为了更好地获得医生帮助,请尽可能地详细描述病情"
@focus="showDescriptionGuess" @input="handleDescriptionInput" @blur="hideDescriptionGuess"></textarea>
<view v-if="guessVisible" class="guess-popup">
<view class="guess-title">猜你想输入</view>
<view v-for="item in guessList" :key="item" class="guess-option" @click="selectDescriptionGuess(item)">
{{ item }}
</view>
</view>
</view>
<view class="relative mt-12 px-15 py-12 bg-white shadow-lg">
<view class="section-title">上传本院或者外院的病历资料</view>
<view class="mt-10 section-sub-title">
请上传诊断处方出院小结医嘱单浙里办医保结算明细等其中一种
</view>
<view class="image-uploader">
<view v-for="(image, index) in form.images" :key="index" class="image-preview">
<image :src="image" class="image" @click="previewImage(index)" />
<view class="close-icon" @click="removeImage(index)">
<uni-icons color="red" size="24" type="close" />
</view>
</view>
<view v-if="form.images.length < 9" class="upload-button" @click="uploadImage">
<uni-icons type="camera" size="40" />
</view>
</view>
</view>
<view class="relative mt-12 px-15 py-12 bg-white shadow-lg">
<view v-for="history in histories" :key="history.label" class="history-item">
<text class="history-label">{{ history.label }}</text>
<radio-group class="radio-group">
<label v-for="i in history.options" :key="i" class="radio-label">
<radio :value="i" :checked="form[history.prop] === i" @change="changeHistory(history.prop, i)"
class="custom-radio" color="#b8956a" />
<text>{{ i }}</text>
</label>
</radio-group>
</view>
</view>
</view>
<template #footer>
<footer-button text="下一步" theme="brown" @onClick="nextStep" />
</template>
</full-page>
</template>
<script setup>
import { ref } from "vue";
import { storeToRefs } from "pinia";
import { onLoad, onUnload } from '@dcloudio/uni-app';
import orderStore from '@/store/order';
import { uploadUrl, getFullPath } from '@/utils/http';
import { toast, loading, hideLoading } from '@/utils/widget';
import footerButton from '@/components/footer-button.vue';
import fullPage from '@/components/full-page.vue';
const guessList = [
'药已用完,需要再次开药',
'病情稳定,要求开具处方买药',
'没有药了,要求开放续药',
'家里药已用完,需要开具新的处方',
'药用完了,需要再开一些', '病情稳定,要求开方配药',
'上次开的药已经用完,需要续药',
'储备的药品已用完,要求开方配药'
]
const { order: form, histories, ybVisitRecord } = storeToRefs(orderStore());
const { init: initOrder } = orderStore();
const visible = ref(false);
const guessVisible = ref(false);
const reachBottom = ref(false);
const pageRef = ref(null);
let guessCloseTimer = null;
// 长辈模式状态
const elderMode = ref(false);
const titleMap = {
YB: "医保处方",
ZF: "自费处方",
};
function changeHistory(prop, value) {
form.value[prop] = value;
}
function showDescriptionGuess() {
if (guessCloseTimer) clearTimeout(guessCloseTimer);
guessCloseTimer = null;
guessVisible.value = !form.value.description.trim();
}
function handleDescriptionInput(event) {
const description = event && event.detail && typeof event.detail.value === 'string'
? event.detail.value
: form.value.description;
if (description.trim()) {
guessVisible.value = false;
}
}
function hideDescriptionGuess() {
if (guessCloseTimer) clearTimeout(guessCloseTimer);
guessCloseTimer = setTimeout(() => {
guessVisible.value = false;
guessCloseTimer = null;
}, 200);
}
function selectDescriptionGuess(description) {
if (guessCloseTimer) clearTimeout(guessCloseTimer);
guessCloseTimer = null;
form.value.description = description;
guessVisible.value = false;
}
function nextStep() {
if (form.value.description.trim() === '') {
toast('请填写病情描述');
return;
}
if (!reachBottom.value) {
pageRef.value?.scrollToBottom();
reachBottom.value = true;
return
}
for (let item of histories.value) {
if (!item.options.includes(form.value[item.prop])) {
toast(`请选择${item.label}`);
return;
}
}
if (form.value.hasVisitedInLastSixMonths === 'N') {
confirmVisible.value = true;
return;
}
uni.navigateTo({ url: '/pages/consult/info' })
}
function onDiseaseSelected(disease) {
if (form.value.diseases.length < 5) {
form.value.diseases.push(disease);
}
}
function removeImage(index) {
form.value.images.splice(index, 1);
}
function uploadImage() {
uni.chooseImage({
count: 9 - form.value.images.length,
sizeType: ['compressed'],
success: async (res) => {
loading('上传中...');
const arr = await Promise.all(res.tempFilePaths.map(upload));
const urls = arr.filter(Boolean);
form.value.images = [...form.value.images, ...urls];
hideLoading();
toast(`成功上传${urls.length}张图片`);
},
});
}
function previewImage(index) {
uni.previewImage({
urls: form.value.images,
current: index
})
}
function upload(path) {
return new Promise((resolve) => {
uni.uploadFile({
url: uploadUrl, // 替换为你的上传接口地址
filePath: path,
name: 'file',
fileType: 'image',
success: (res) => {
try {
const url = JSON.parse(res.data).filePath;
resolve(url ? getFullPath(url) : '')
} catch (e) {
resolve()
}
},
fail: res => {
resolve()
}
})
})
}
function onReachBottom() {
reachBottom.value = true;
}
onLoad((options) => {
initOrder({ feeType: options.feeType, socialno: options.socialno });
uni.setNavigationBarTitle({
title: titleMap[options.feeType] || ''
})
uni.$on('on-disease-selected', onDiseaseSelected);
})
onUnload(() => {
uni.$off('on-disease-selected')
if (guessCloseTimer) clearTimeout(guessCloseTimer);
})
</script>
<style lang="scss" scoped>
.section-title {
font-weight: bold;
font-size: 32rpx;
&.is-required:before {
display: inline-block;
content: "*";
color: red;
margin-right: 10rpx;
}
}
.title-font {
font-size: 32rpx;
}
.section-sub-title {
font-size: 28rpx;
color: #555;
line-height: 42rpx;
}
.disease-tags {
display: flex;
flex-wrap: wrap;
margin-right: -20rpx;
}
.disease-tag {
padding: 10rpx 20rpx;
background-color: #f5ede0;
border-radius: 16rpx;
margin-right: 20rpx;
margin-top: 20rpx;
font-size: 28rpx;
color: #8b6f47;
border: 1px solid #d4c4a8;
@at-root &.add-tag {
border-color: #b8956a;
background-color: white;
color: #b8956a;
}
}
.disease-remove {
display: inline-block;
padding: 0 16rpx;
}
.image-uploader {
display: flex;
flex-wrap: wrap;
}
.item-guess {
font-size: 28rpx;
font-weight: bold;
}
.image-preview,
.upload-button {
position: relative;
width: 140rpx;
height: 140rpx;
margin: 10rpx 10rpx 0 0;
display: flex;
align-items: center;
justify-content: center;
}
.upload-button {
border: 1px solid #e5e5e5;
}
.close-icon {
position: absolute;
top: -20rpx;
right: -20rpx;
width: 40rpx;
height: 40rpx;
display: flex;
justify-content: flex-end;
}
.image {
width: 140rpx;
height: 140rpx;
}
.next-button {
background-color: $theme-brown-primary;
color: white;
position: fixed;
bottom: 20rpx;
/* width: 100%; */
left: 40rpx;
right: 40rpx;
}
.history-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.history-item-none {
padding: 0;
}
.history-item:last-child {
border-bottom: none;
}
.history-label {
width: 280rpx;
font-size: 14px;
color: #555;
}
.radio-group {
display: flex;
align-items: center;
justify-content: space-between;
width: 320rpx;
}
.radio-group-auto {
width: auto;
}
.radio-label {
width: 50%;
display: flex;
align-items: center;
margin-left: 15px;
font-size: 28rpx;
white-space: nowrap;
}
.custom-radio {
transform: scale(0.8);
}
.description {
width: 100%;
min-height: 84rpx;
}
.description-section {
z-index: 10;
}
.guess-popup {
position: absolute;
left: 30rpx;
right: 30rpx;
top: 100%;
z-index: 20;
box-sizing: border-box;
background: #fff;
border: 1rpx solid #d9d9d9;
box-shadow: 6rpx 6rpx 12rpx rgba(0, 0, 0, 0.25);
}
.guess-title,
.guess-option {
box-sizing: border-box;
min-height: 64rpx;
padding: 16rpx 20rpx;
border-bottom: 1rpx solid #eee;
font-size: 26rpx;
line-height: 32rpx;
color: #333;
}
.guess-title {
font-weight: bold;
}
.guess-option:last-child {
border-bottom: none;
}
.guess-option:active {
background: #f5f5f5;
}
.placeholderClass {
font-size: 28rpx;
}
.user-header {
padding: 24rpx 30rpx;
background: white;
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.flex-row {
display: flex;
align-items: center;
}
/* 长辈模式特定样式 */
.elder-mode-active {
.user-header {
font-size: 42rpx !important;
padding: 40rpx 30rpx !important;
}
.section-title {
font-size: 42rpx !important;
margin-bottom: 30rpx;
}
.title-font {
font-size: 42rpx !important;
}
.section-sub-title {
font-size: 36rpx !important;
line-height: 1.6 !important;
}
.disease-tag {
font-size: 36rpx !important;
padding: 15rpx 25rpx !important;
margin-right: 25rpx !important;
margin-bottom: 25rpx !important;
}
.description {
font-size: 36rpx !important;
min-height: 200rpx !important;
padding: 20rpx !important;
line-height: 1.6 !important;
box-sizing: border-box !important;
}
.guess-title,
.guess-option {
min-height: 84rpx;
padding: 20rpx 24rpx;
font-size: 34rpx;
line-height: 44rpx;
}
.placeholderClass {
font-size: 36rpx !important;
line-height: 1.6 !important;
}
.history-label {
font-size: 36rpx !important;
width: 320rpx !important;
}
.radio-label {
font-size: 36rpx !important;
margin-left: 20rpx !important;
}
.image-preview,
.upload-button {
width: 200rpx !important;
height: 200rpx !important;
margin: 10rpx !important;
}
.image {
width: 200rpx !important;
height: 200rpx !important;
}
}
</style>