feat: 诊所问题优化

This commit is contained in:
李琦
2026-07-30 07:37:29 +08:00
parent 5629955dd3
commit f9dd9ad3a2
6 changed files with 400 additions and 254 deletions

View File

@@ -115,21 +115,30 @@
v-else-if="showQuestionButtons && currentQuestion && !isSubmitting && !showWaiting && answerMode === 'multi'"
class="action-footer multi-footer safe-area-inset-bottom"
>
<!-- 多选适用症:点选 toggling,确认后再提交 -->
<!-- 多选适用症:点选 toggling,确认后再提交;选「其他」可填自定义症状 -->
<view class="multi-options">
<button
v-for="(answer, index) in currentQuestionAnswers"
:key="index"
:class="['multi-option-btn', { selected: !!multiSelectedMap[index] }]"
hover-class="none"
:class="['multi-option-btn', { selected: !!multiSelectedFlag[index] }]"
@click="toggleMultiAnswer(index)"
>
{{ answer }}
</button>
</view>
<input
v-if="multiHasOtherSelected"
class="multi-other-input"
v-model="multiOtherText"
placeholder="请填写具体症状"
:maxlength="100"
/>
<!-- 不用原生 disabled,避免微信小程序卡死无法点击;未达标时 toast -->
<button
class="action-btn yes-btn confirm-btn"
:disabled="multiSelectedCount === 0"
:class="{ disabled: multiSelectedCount === 0 }"
hover-class="none"
:class="{ disabled: !multiConfirmEnabled }"
@click="confirmMultiAnswer"
>
确认
@@ -142,8 +151,9 @@
<button
v-for="(answer, index) in currentQuestionAnswers"
:key="index"
hover-class="none"
:class="['action-btn', answerButtonClass(answer, index)]"
@click="$emit('answer', answer)"
@click="emitSingleAnswer(answer)"
>
{{ answer }}
</button>
@@ -259,17 +269,25 @@ export default {
},
data() {
return {
/** 多选模式下已选中的选项下标映射,避免模板里写 indexOf */
multiSelectedMap: {},
/** 多选已选下标列表(整表替换,微信小程序下比 object+$set 更稳) */
multiSelectedIndexes: [],
/** 选「其他」时的自定义症状文案 */
multiOtherText: '',
/** 防双击:emit 后立刻锁,题目切换解锁 */
answeringLock: false,
};
},
watch: {
// 题目切换时清空多选,避免上一题选中态残留
currentQuestion() {
this.multiSelectedMap = {};
this.multiSelectedIndexes = [];
this.multiOtherText = '';
this.answeringLock = false;
},
answerMode() {
this.multiSelectedMap = {};
this.multiSelectedIndexes = [];
this.multiOtherText = '';
this.answeringLock = false;
},
},
computed: {
@@ -281,8 +299,37 @@ export default {
this.$emit('update:showAgreement', val)
},
},
/** 供模板判断选中,避免 :class 里写 indexOf */
multiSelectedFlag() {
const map = {};
const list = this.multiSelectedIndexes || [];
for (let i = 0; i < list.length; i++) {
map[list[i]] = true;
}
return map;
},
multiSelectedCount() {
return Object.keys(this.multiSelectedMap).filter((k) => this.multiSelectedMap[k]).length;
return (this.multiSelectedIndexes || []).length;
},
/** 是否选中了「其他」选项 */
multiHasOtherSelected() {
const answers = this.currentQuestionAnswers || [];
const list = this.multiSelectedIndexes || [];
for (let i = 0; i < list.length; i++) {
const idx = list[i];
if (answers[idx] === '其他') {
return true;
}
}
return false;
},
/** 多选确认是否可提交:至少选一项;选了其他则自定义文案非空 */
multiConfirmEnabled() {
if (this.multiSelectedCount === 0) return false;
if (this.multiHasOtherSelected) {
return !!(this.multiOtherText && String(this.multiOtherText).trim());
}
return true;
},
},
methods: {
@@ -306,27 +353,54 @@ export default {
if (index === 0) return 'yes-btn'
return 'no-btn'
},
/** 单选:点一下即提交,防双击重复 emit */
emitSingleAnswer(answer) {
if (this.answeringLock || this.isSubmitting) return;
this.answeringLock = true;
this.$emit('answer', answer);
},
/** 多选:切换某个适用症的选中状态 */
toggleMultiAnswer(index) {
if (this.multiSelectedMap[index]) {
this.$delete(this.multiSelectedMap, index);
if (this.answeringLock || this.isSubmitting) return;
const list = this.multiSelectedIndexes || [];
const pos = list.indexOf(index);
if (pos === -1) {
this.multiSelectedIndexes = list.concat([index]);
} else {
this.$set(this.multiSelectedMap, index, true);
this.multiSelectedIndexes = list.filter((i) => i !== index);
if (this.currentQuestionAnswers[index] === '其他') {
this.multiOtherText = '';
}
}
},
/** 多选确认:把选中标签用顿号拼接后交给父组件 */
/**
* 多选确认:选中标签用顿号拼接;「其他」替换为自定义填写内容
*/
confirmMultiAnswer() {
const indexes = Object.keys(this.multiSelectedMap)
.filter((k) => this.multiSelectedMap[k])
.map((k) => Number(k))
.sort((a, b) => a - b);
if (this.answeringLock || this.isSubmitting) return;
if (!this.multiConfirmEnabled) {
if (this.multiSelectedCount === 0) {
uni.showToast({ title: '请至少选择一项', icon: 'none' });
} else if (this.multiHasOtherSelected) {
uni.showToast({ title: '请填写具体症状', icon: 'none' });
}
return;
}
const indexes = (this.multiSelectedIndexes || []).slice().sort((a, b) => a - b);
if (!indexes.length) return;
const otherText = (this.multiOtherText || '').trim();
const labels = indexes
.map((i) => this.currentQuestionAnswers[i])
.map((i) => {
const label = this.currentQuestionAnswers[i];
if (label === '其他') return otherText;
return label;
})
.filter(Boolean);
if (!labels.length) return;
this.answeringLock = true;
this.$emit('answer', labels.join('、'));
this.multiSelectedMap = {};
this.multiSelectedIndexes = [];
this.multiOtherText = '';
},
},
}
@@ -531,19 +605,22 @@ export default {
font-weight: 500;
border: none;
white-space: normal;
/* 覆盖微信 button 默认白底/按下灰底,避免按钮组背景错乱 */
background-color: #0a84ff !important;
color: #fff !important;
&::after {
border: none;
}
&.yes-btn {
background: #0a84ff;
color: #fff;
background-color: #0a84ff !important;
color: #fff !important;
}
&.no-btn {
background: #fff;
color: #333;
background-color: #fff !important;
color: #333 !important;
border: 2rpx solid #ddd;
}
@@ -563,6 +640,18 @@ export default {
gap: 16rpx;
}
.multi-other-input {
width: 100%;
box-sizing: border-box;
padding: 16rpx 24rpx;
min-height: 72rpx;
border-radius: 12rpx;
background: #f8fafc;
font-size: 28rpx;
color: #333;
border: 1rpx solid #e2e8f0;
}
.multi-option-btn {
min-width: 140rpx;
padding: 0 28rpx;
@@ -570,8 +659,8 @@ export default {
line-height: 64rpx;
border-radius: 32rpx;
font-size: 26rpx;
background: rgba(10, 132, 255, 0.08);
color: #475569;
background-color: rgba(10, 132, 255, 0.08) !important;
color: #475569 !important;
border: 2rpx solid transparent;
&::after {
@@ -579,14 +668,16 @@ export default {
}
&.selected {
background: #0a84ff;
color: #fff;
background-color: #0a84ff !important;
color: #fff !important;
}
}
.confirm-btn {
width: 100%;
flex: none;
background-color: #0a84ff !important;
color: #fff !important;
}
}
}