| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- <!-- DEPRECATED: 已由 ComprehensiveSurvey.vue 替代,待确认无引用后清理(2026-10-16 标记) -->
- <template>
- <view class="medical-step">
- <view class="step-title-row">
- <text class="step-title">疾病史与用药</text>
- <text class="step-sub">选择过往疾病与当前用药,如无请勾选「无长期用药」</text>
- </view>
- <!-- 疾病史 -->
- <view class="form-card">
- <view class="card-head">
- <text class="card-title">疾病史</text>
- <text class="card-count">已选 {{ inner.selectedDiseases.length }} 项</text>
- </view>
- <view v-for="(group, gi) in diseaseGroups" :key="group.key" class="disease-group">
- <view class="group-head" @click="toggleGroup(group.key)">
- <text class="group-title">{{ group.title }}</text>
- <text class="group-arrow">{{ expandedGroups.indexOf(group.key) >= 0 ? '收起' : '展开' }}</text>
- </view>
- <view v-if="expandedGroups.indexOf(group.key) >= 0" class="tag-wrap">
- <view
- v-for="(item, ii) in group.items"
- :key="item.name"
- class="tag-item"
- :class="{ 'tag-active': selectedNames.indexOf(item.name) >= 0 }"
- @click="toggleDisease(item.name)"
- >
- <text>{{ item.name }}</text>
- <text v-if="item.risk" class="risk-badge">★</text>
- </view>
- </view>
- </view>
- <!-- 自定义疾病 -->
- <view class="custom-row">
- <input class="custom-input" type="text" v-model="diseaseInput" placeholder="输入其他疾病" />
- <text class="add-link" @click="addCustomDisease">添加</text>
- </view>
- <!-- 已选疾病 + 确诊时间 -->
- <view v-if="inner.selectedDiseases.length > 0" class="selected-area">
- <view class="selected-title">已选疾病</view>
- <view v-for="(item, si) in inner.selectedDiseases" :key="getSelKey(si)" class="sel-row">
- <text class="sel-name">{{ item.name }}</text>
- <picker mode="date" fields="month" :value="item.diagnosedAt || currentMonth" :end="monthEnd" @change="onDiagChange(si, $event)">
- <view class="sel-diag">{{ item.diagnosedAt ? item.diagnosedAt : '设确诊时间' }}</view>
- </picker>
- <text class="sel-del" @click="removeSelected(si)">×</text>
- </view>
- </view>
- </view>
- <!-- 在服药物/治疗 -->
- <view class="form-card">
- <view class="card-head">
- <text class="card-title">在服药物/治疗</text>
- <text class="card-count">{{ inner.medRows.length }} 条</text>
- </view>
- <view v-for="(med, idx) in inner.medRows" :key="getMedKey(idx)" class="med-row">
- <view class="med-line">
- <input class="med-name" type="text" v-model="med.name" placeholder="药物品牌,如 立普妥"
- @input="emitInput" />
- <text class="med-del" @click="removeMed(idx)">删除</text>
- </view>
- <view class="med-line">
- <picker mode="date" fields="month" :value="med.startDate || currentMonth" :end="monthEnd" @change="onMedStartChange(idx, $event)">
- <view class="med-picker">{{ med.startDate ? med.startDate : '选择开始日期' }}</view>
- </picker>
- <text class="med-forget" @click="onForgetClick(idx)">记不清</text>
- </view>
- <view class="med-line" v-if="med.durationText">
- <text class="med-duration">已服时长:{{ med.durationText }}</text>
- </view>
- <view class="med-line">
- <input class="med-time" type="text" v-model="med.time" placeholder="服药时间,如 早饭后一次"
- @input="emitInput" />
- </view>
- </view>
- <text class="add-link" @click="addMed">+ 添加药物/治疗</text>
- </view>
- <!-- 快捷:无长期用药 -->
- <view class="form-card">
- <view
- class="quick-chip"
- :class="{ 'quick-chip-on': noMedication }"
- @click="toggleNoMedication"
- >
- <text>{{ noMedication ? '✓ 已选' : '无长期用药' }}</text>
- </view>
- <text class="unit-hint" v-if="noMedication">已标记无长期用药,可跳过药物填写</text>
- </view>
- </view>
- </template>
- <script>
- // 预置疾病清单(与 health-plan-summary.vue 保持一致的 8 组)
- var DISEASE_GROUPS = [
- { key: 'cardio', title: '心血管代谢', items: [
- { name: '高血压', risk: false },
- { name: '糖尿病', risk: false },
- { name: '血脂异常', risk: false },
- { name: '冠心病', risk: false },
- { name: '脑卒中', risk: false },
- { name: '心力衰竭', risk: false },
- { name: '心房颤动', risk: false },
- { name: '慢阻肺', risk: false },
- { name: '心脑血管疾病', risk: true },
- { name: 'II型糖尿病', risk: true },
- { name: '肥胖', risk: true },
- { name: '超重', risk: false },
- { name: '高尿酸血症', risk: false },
- { name: '骨质疏松', risk: false }
- ]},
- { key: 'digest', title: '消化系统', items: [
- { name: '幽门螺杆菌感染', risk: false },
- { name: '脂肪肝', risk: false },
- { name: '慢性胃炎', risk: false },
- { name: '胃食管反流', risk: false },
- { name: '肠易激综合征', risk: true },
- { name: '炎症性肠炎', risk: true },
- { name: '慢性便秘', risk: true },
- { name: '感染性腹泻', risk: true },
- { name: '胆结石', risk: false },
- { name: '炎症性肠病', risk: false },
- { name: '肝病', risk: true },
- { name: '胃病', risk: true },
- { name: '胆病', risk: true },
- { name: '肾病', risk: true },
- { name: '腹胀', risk: true }
- ]},
- { key: 'immune', title: '过敏免疫', items: [
- { name: '过敏性鼻炎', risk: true },
- { name: '哮喘', risk: false },
- { name: '湿疹', risk: false },
- { name: '食物过敏', risk: false },
- { name: '自体免疫病', risk: true }
- ]},
- { key: 'neuro', title: '精神神经', items: [
- { name: '抑郁症', risk: true },
- { name: '失眠', risk: true },
- { name: '焦虑障碍', risk: false },
- { name: '偏头痛', risk: false },
- { name: '自闭症', risk: true }
- ]},
- { key: 'resp', title: '呼吸系统', items: [
- { name: '肺部感染或疾病', risk: true },
- { name: '肺部疾病', risk: true }
- ]},
- { key: 'tumor', title: '肿瘤', items: [
- { name: '结直肠癌', risk: true },
- { name: '肺癌', risk: false },
- { name: '甲状腺癌', risk: false },
- { name: '肝癌', risk: false },
- { name: '胃癌', risk: false },
- { name: '乳腺癌', risk: false },
- { name: '食管癌', risk: false }
- ]},
- { key: 'child', title: '儿童青少年', items: [
- { name: '近视', risk: false },
- { name: '龋齿', risk: false },
- { name: '注意缺陷多动障碍', risk: false },
- { name: '甲状腺疾病', risk: true }
- ]},
- { key: 'other', title: '其他', items: [
- { name: '缺铁性贫血', risk: false },
- { name: '贫血', risk: false }
- ]}
- ]
- export default {
- name: 'MedicalHistoryStep',
- props: {
- value: {
- type: Object,
- default: function() { return {} }
- }
- },
- data() {
- return {
- diseaseGroups: DISEASE_GROUPS,
- expandedGroups: [],
- diseaseInput: '',
- currentMonth: '',
- monthEnd: ''
- }
- },
- computed: {
- inner: function() {
- return this.value || {}
- },
- noMedication: function() {
- return !!this.inner.noMedication
- },
- selectedNames: function() {
- var list = this.inner.selectedDiseases || []
- return list.map(function(d) { return d.name })
- }
- },
- created: function() {
- var now = new Date()
- var y = now.getFullYear()
- var m = now.getMonth() + 1
- var mStr = m < 10 ? '0' + m : '' + m
- this.currentMonth = y + '-' + mStr
- var lastDay = new Date(y, m, 0).getDate()
- this.monthEnd = y + '-' + mStr + '-' + (lastDay < 10 ? '0' + lastDay : '' + lastDay)
- // 默认展开前 3 组
- this.expandedGroups = DISEASE_GROUPS.slice(0, 3).map(function(g) { return g.key })
- // 已有选中项时展开对应组
- var self = this
- ;(this.inner.selectedDiseases || []).forEach(function(d) {
- var gk = self.findGroupKey(d.name)
- if (gk && self.expandedGroups.indexOf(gk) < 0) self.expandedGroups.push(gk)
- })
- },
- methods: {
- emitInput: function() {
- this.$emit('input', this.inner)
- },
- findGroupKey: function(name) {
- for (var i = 0; i < DISEASE_GROUPS.length; i++) {
- var items = DISEASE_GROUPS[i].items
- for (var j = 0; j < items.length; j++) {
- if (items[j].name === name) return DISEASE_GROUPS[i].key
- }
- }
- return ''
- },
- toggleGroup: function(key) {
- var idx = this.expandedGroups.indexOf(key)
- if (idx >= 0) this.expandedGroups.splice(idx, 1)
- else this.expandedGroups.push(key)
- },
- toggleDisease: function(name) {
- var list = this.inner.selectedDiseases || []
- var idx = -1
- for (var i = 0; i < list.length; i++) {
- if (list[i].name === name) { idx = i; break }
- }
- var next
- if (idx >= 0) {
- next = list.slice(0, idx).concat(list.slice(idx + 1))
- } else {
- next = list.concat([{ name: name, diagnosedAt: '', custom: false }])
- }
- this.$emit('input', Object.assign({}, this.inner, { selectedDiseases: next }))
- },
- addCustomDisease: function() {
- var name = (this.diseaseInput || '').trim()
- if (!name) return
- var list = this.inner.selectedDiseases || []
- var exists = list.some(function(d) { return d.name === name })
- if (!exists) {
- var next = list.concat([{ name: name, diagnosedAt: '', custom: true }])
- this.$emit('input', Object.assign({}, this.inner, { selectedDiseases: next }))
- }
- this.diseaseInput = ''
- },
- getSelKey: function(i) { return 's' + i },
- getMedKey: function(i) { return 'm' + i },
- removeSelected: function(idx) {
- var list = this.inner.selectedDiseases || []
- var next = list.slice(0, idx).concat(list.slice(idx + 1))
- this.$emit('input', Object.assign({}, this.inner, { selectedDiseases: next }))
- },
- onDiagChange: function(idx, e) {
- var list = this.inner.selectedDiseases || []
- var item = Object.assign({}, list[idx], { diagnosedAt: e.detail.value })
- var next = list.slice()
- next[idx] = item
- this.$emit('input', Object.assign({}, this.inner, { selectedDiseases: next }))
- },
- addMed: function() {
- var rows = (this.inner.medRows && this.inner.medRows.length > 0 ? this.inner.medRows.slice() : [])
- rows.push({ name: '', startDate: '', durationText: '', time: '' })
- this.$emit('input', Object.assign({}, this.inner, { medRows: rows }))
- },
- removeMed: function(idx) {
- var rows = (this.inner.medRows || []).slice()
- rows.splice(idx, 1)
- this.$emit('input', Object.assign({}, this.inner, { medRows: rows }))
- },
- onMedStartChange: function(idx, e) {
- var start = e.detail.value
- var rows = (this.inner.medRows || []).slice()
- rows[idx] = Object.assign({}, rows[idx], { startDate: start, durationText: this.calcDuration(start) })
- this.$emit('input', Object.assign({}, this.inner, { medRows: rows }))
- },
- onForgetClick: function(idx) {
- var self = this
- uni.showModal({
- title: '记不清开始日期',
- editable: true,
- placeholderText: '如:约 3 个月',
- success: function(res) {
- if (res.confirm && res.content) {
- var rows = (self.inner.medRows || []).slice()
- rows[idx] = Object.assign({}, rows[idx], { durationText: res.content.trim() })
- self.$emit('input', Object.assign({}, self.inner, { medRows: rows }))
- }
- }
- })
- },
- calcDuration: function(startDate) {
- if (!startDate) return ''
- var parts = startDate.split('-')
- if (parts.length !== 2) return ''
- var sy = parseInt(parts[0], 10)
- var sm = parseInt(parts[1], 10)
- var now = new Date()
- var months = (now.getFullYear() - sy) * 12 + (now.getMonth() + 1 - sm)
- if (months < 1) months = 1
- if (months < 12) return '已服 ' + months + ' 个月'
- return '已服 ' + Math.floor(months / 12) + ' 年'
- },
- toggleNoMedication: function() {
- this.$emit('input', Object.assign({}, this.inner, { noMedication: !this.noMedication }))
- }
- }
- }
- </script>
- <style scoped>
- .medical-step {
- padding: 10rpx 0 30rpx;
- }
- .step-title-row {
- margin-bottom: 20rpx;
- }
- .step-title {
- font-size: 34rpx;
- font-weight: 700;
- color: #333;
- }
- .step-sub {
- display: block;
- font-size: 24rpx;
- color: #999;
- margin-top: 8rpx;
- }
- .form-card {
- background: #fff;
- border-radius: 20rpx;
- padding: 24rpx;
- margin-bottom: 20rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
- }
- .card-head {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 16rpx;
- }
- .card-title {
- font-size: 28rpx;
- font-weight: 600;
- color: #333;
- }
- .card-count {
- font-size: 22rpx;
- color: #F97316;
- background: #FFF3E0;
- padding: 4rpx 16rpx;
- border-radius: 20rpx;
- }
- .group-head {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 16rpx 0 8rpx;
- }
- .group-title {
- font-size: 26rpx;
- font-weight: 600;
- color: #475569;
- }
- .group-arrow {
- font-size: 22rpx;
- color: #94A3B8;
- }
- .tag-wrap {
- display: flex;
- flex-wrap: wrap;
- }
- .tag-item {
- padding: 12rpx 24rpx;
- border-radius: 999rpx;
- background: #F1F5F9;
- font-size: 24rpx;
- color: #334155;
- margin: 0 14rpx 14rpx 0;
- position: relative;
- }
- .tag-active {
- background: #FFF3E0;
- color: #F97316;
- font-weight: 600;
- }
- .risk-badge {
- color: #EF4444;
- margin-left: 6rpx;
- }
- .custom-row {
- display: flex;
- align-items: center;
- margin-top: 10rpx;
- }
- .custom-input {
- flex: 1;
- border: 2rpx solid #E2E8F0;
- border-radius: 12rpx;
- padding: 14rpx 20rpx;
- font-size: 26rpx;
- background: #F8FAFC;
- }
- .add-link {
- color: #F97316;
- font-size: 26rpx;
- font-weight: 600;
- padding: 14rpx 10rpx;
- margin-left: 10rpx;
- }
- .selected-area {
- margin-top: 16rpx;
- border-top: 2rpx solid #F1F5F9;
- padding-top: 16rpx;
- }
- .selected-title {
- font-size: 24rpx;
- color: #94A3B8;
- margin-bottom: 10rpx;
- }
- .sel-row {
- display: flex;
- align-items: center;
- margin-bottom: 12rpx;
- }
- .sel-name {
- flex: 1;
- font-size: 26rpx;
- color: #333;
- }
- .sel-diag {
- font-size: 22rpx;
- color: #F97316;
- background: #FFF3E0;
- padding: 8rpx 20rpx;
- border-radius: 999rpx;
- }
- .sel-del {
- color: #EF4444;
- font-size: 32rpx;
- padding: 0 10rpx;
- }
- .med-row {
- border: 2rpx solid #F1F5F9;
- border-radius: 12rpx;
- padding: 16rpx;
- margin-bottom: 16rpx;
- }
- .med-line {
- display: flex;
- align-items: center;
- margin-bottom: 10rpx;
- }
- .med-line:last-child {
- margin-bottom: 0;
- }
- .med-name,
- .med-time {
- flex: 1;
- border: 2rpx solid #E2E8F0;
- border-radius: 10rpx;
- padding: 12rpx 16rpx;
- font-size: 26rpx;
- background: #F8FAFC;
- }
- .med-del {
- color: #EF4444;
- font-size: 24rpx;
- padding: 0 10rpx;
- }
- .med-picker {
- font-size: 24rpx;
- color: #F97316;
- background: #FFF3E0;
- padding: 10rpx 20rpx;
- border-radius: 999rpx;
- }
- .med-forget {
- font-size: 22rpx;
- color: #94A3B8;
- margin-left: 16rpx;
- }
- .med-duration {
- font-size: 22rpx;
- color: #64748B;
- }
- .quick-chip {
- display: inline-flex;
- align-items: center;
- padding: 14rpx 28rpx;
- border-radius: 999rpx;
- background: #F1F5F9;
- font-size: 26rpx;
- color: #64748B;
- }
- .quick-chip-on {
- background: #FFF3E0;
- color: #F97316;
- font-weight: 600;
- }
- .unit-hint {
- display: block;
- font-size: 22rpx;
- color: #999;
- margin-top: 10rpx;
- }
- </style>
|