Преглед на файлове

处理多选填空bug及回显问题

wzz преди 1 седмица
родител
ревизия
069f82fa76
променени са 2 файла, в които са добавени 85 реда и са изтрити 35 реда
  1. 14 9
      src/pages/sickForm/historyDetail.vue
  2. 71 26
      src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue

+ 14 - 9
src/pages/sickForm/historyDetail.vue

@@ -9,7 +9,7 @@
 					    <view v-if="item.pic_url">
 							 <image :src="globalUrl + item.pic_url" mode="aspectFit" style="width: 95%;height: 230rpx;" @click="preview(globalUrl + item.pic_url)"></image>
 						</view>
-						<uni-data-checkbox v-model="item.answer" :multiple="item.type" :localdata="item.items" @change="change(idx,item,$event)" v-if="item.type!=3"/>
+						<uni-data-checkbox v-model="item.answer" :multiple="!!item.type" :localdata="item.items" @change="change(idx,item,$event)" v-if="item.type!=3"/>
 					</uni-forms-item>
 					<uni-forms-item label="( 1 ) 头痛的时间" isBold="bold"  v-if="isHeadacheItem(item)" >
 						<view class="display-between" style="width:350rpx">
@@ -220,14 +220,15 @@ export default {
 				}
 			})
 		}else {
+			// 防御:e.detail.data 理论上单选时应该是选中项对象,但个别情况下可能拿不到,
+			// 直接取 .item_number 会报错,拿不到就保留原本的 e.detail.value,不让它整个崩掉
 			if(!e.detail.value){
-				valArr = e.detail.data.item_number
+				valArr = e.detail.data ? e.detail.data.item_number : valArr
 			}
 		}
-		if(e.detail.isInput){
-			e.detail.value[e.detail.value.length -1] = that.makeOtherDataFn(item,e.detail.value[e.detail.value.length -1])
-			valArr = e.detail.value
-		}
+		// 现在不管单选还是多选,可填写选项都已经在 uni-data-checkbox 组件内部(inputChange)按每一项自己
+		// 拼成了 "id#文本#" 的自描述格式,上面"多选"/"单选"分支里的 valArr 已经是正确内容了。
+		// 这里原来还会再用 makeOtherDataFn 把最后一项重新拼一遍,两边都拼的话单选场景会被套两层,删掉。
 		if(valArr && valArr.includes(':')){
 			valArr = valArr.replace(/:/g, '__')
 		}
@@ -370,8 +371,12 @@ export default {
 				}
 			})
 			return filterArr.every((item)=>{
-				    item.answer = "" + item.answer;
-					let as = item.answer.split("#");
+				    // 修复:这里原来直接把 item.answer 重新赋值成字符串,只是为了校验方便,
+				    // 但 item.answer 是 checkbox 组件 v-model 绑定的真实数据,多选题被改成字符串后,
+				    // uni-data-checkbox 会把它当成"没有选中任何项"处理,导致校验不通过、停留在原页面时
+				    // 多选题的勾选状态全部被清空显示。改成用局部变量校验,不改动 item.answer 本身。
+				    let answerStr = "" + item.answer;
+					let as = answerStr.split("#");
 					if(as[as.length-1] === ''){
 						as.pop()
 					}
@@ -382,7 +387,7 @@ export default {
 							return false;
 						}
 					}
-				return item.answer !== ''
+				return answerStr !== ''
 			})
    },
 	submit() {

+ 71 - 26
src/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue

@@ -270,20 +270,18 @@
 					nowItemObj:{}
 				}
 				if (this.multiple) {
-					this.range.forEach(item => { 
+					// 改成遍历 this.dataList 而不是 this.range:range 是原始选项模板,没有 inputValue,
+					// dataList 才是当前实际维护着每个可填写选项文本的那份数据。这样切换勾选(而不是编辑文字)
+					// 触发这里时,已经填过的内容也能跟着一起自描述地拼进 value,不会因为"最后一次操作是勾选
+					// 而不是打字"就把已经填的内容弄丢。
+					this.dataList.forEach(item => {
 						if (values.includes(item[this.map.value] + '')) {
-							// if(item.content==='其他##'){
-							// 	detail.value.push('other')
-							// 	detail.data.push(item)
-							// }else {
-								// if(item.content.includes('##')){ //清除第一次勾选的默认值展示
-								// 	detail.nowItemObj = item;
-								// 	item.value = ''
-								// }
+							if (item.content && item.content.includes('##')) {
+								detail.value.push(item.value + '#' + (item.inputValue || '') + '#')
+							} else {
 								detail.value.push(item[this.map.value])
-								detail.data.push(item)
-							// }
-
+							}
+							detail.data.push(item)
 						}
 					})
 				} else {
@@ -337,11 +335,17 @@
 				// 		// item.selected =
 				// 	}
 				// })
+				// 修复:这里之前不管是哪个输入框触发的编辑,只要是"已勾选+可填写"的选项,
+				// 全部塞的都是 e.detail.value(这次触发编辑的那个输入框的值),导致同时勾选两个可填写项时,
+				// 提交/回显用的这份 detail.value 里两项内容会被写成一样的。
+				// 改成每一项都自己拼成 "id#文本#" 的自描述格式(用自己的 item.value 当 id、自己的 item.inputValue 当文本),
+				// 不再依赖"数组最后一项"这种位置假设 —— 单选场景下本来就只有一项,格式和之前父组件里 makeOtherDataFn
+				// 拼出来的结果是一样的,行为不变。
 				this.dataList.forEach((item)=>{
 					if(item.selected){
 						detail.data.push(item)
 						if(item.content.includes('##')){
-							detail.value.push(e.detail.value);
+							detail.value.push(item.value + '#' + (item.inputValue || '') + '#');
 						}else {
 							detail.value.push(item.value);
 						}
@@ -392,18 +396,29 @@
 					}
 				})
 			},
-			showOtherInputVal(valList,isMultiple){
+			showOtherInputVal(valList,isMultiple,currentItemValue){
+				// currentItemValue:多选场景下,要查的是"这一个"选项自己的填写内容。
+				// 之前不管 value 数组里有几条"id#文本#"格式的记录,都用同一对 startVal/endVal 变量每轮覆盖,
+				// 循环完只剩最后一条的结果,同时多个可填写项被勾选时,前面几个的内容会被找不回来。
+				// 现在按 currentItemValue 找数组里真正属于这一项的那一条,找到就不再继续覆盖。
 				let arr = valList, startVal = '', endVal= '';
 				if(!isMultiple && arr){
 					arr = [arr];
 				}
 				if(Array.isArray(arr)){
-					arr.forEach((item)=>{
-					   if(item.length > 1){
+					for (let i = 0; i < arr.length; i++) {
+						let item = arr[i]
+					   if(item && item.length > 1){
 						   if(typeof item === 'string'){
 							   if(isMultiple){
-								   startVal = item.substring(0,1)
-								   endVal = item.substring(2,item.length-1)
+								   let s = item.substring(0,1)
+								   let e = item.substring(2,item.length-1)
+								   if (currentItemValue === undefined || s === currentItemValue) {
+									   startVal = s
+									   endVal = e
+									   if (currentItemValue !== undefined) break
+								   }
+								   continue
 							   }
                                else {
 								     console.log('inputVal====>>>>>009999',item)
@@ -411,14 +426,19 @@
 									   startVal = item.substring(0,1)
 									   endVal = item.substring(2,item.length-1)
 								   }else {
-									   startVal = item.split(':')[1].substring(0,1)
-									   endVal = item.split(':')[1].substring(2,(item.split(':')[1].length)-2)
+									   // 防御:单选答案不是预期的 "xxx:yyy" 格式时,split(':')[1] 会是 undefined,
+									   // 直接调 .substring 会报错,这里拿不到就跳过,保留 startVal/endVal 默认空字符串
+									   let afterColon = item.split(':')[1]
+									   if(afterColon){
+										   startVal = afterColon.substring(0,1)
+										   endVal = afterColon.substring(2,afterColon.length-2)
+									   }
 								   }
-								   
-							   }   
+
+							   }
 						   }
 					   }	
-					})	
+					}
 					return {
 						start:startVal,
 						end:endVal
@@ -436,6 +456,20 @@
 			 * @param {Object} value 选中内容
 			 */
 			getDataList(value) {
+				// 多选场景下,勾选状态每变化一次这里都会把 dataList 整个重新克隆重建一遍,
+				// 而"##"可填写选项的文本(item.inputValue)只是输入时临时存在旧 dataList 里、并没有回写进 value,
+				// showOtherInputVal 在多选下也只能反推出最后一条,重建后其余已填的内容就找不回来了。
+				// 这里在重建前先把旧 dataList 里已经填了内容的"##"选项记下来,重建后原样兜底填回去,避免被冲掉。
+				// 按下标缓存,不依赖 value/content 具体字段名 —— 新旧 dataList 都是从同一份 this.range
+				// 按相同顺序重新克隆出来的,下标天然一一对应,比按字段取值当 key 更可靠
+				let prevInputMap = {}
+				if (this.multiple && Array.isArray(this.dataList)) {
+					this.dataList.forEach((item, i) => {
+						if (item.content && item.content.includes('##') && item.inputValue) {
+							prevInputMap[i] = item.inputValue
+						}
+					})
+				}
 				// 解除引用关系,破坏原引用关系,避免污染源数据
 				let dataList = JSON.parse(JSON.stringify(this.range))
 				let list = []
@@ -448,7 +482,9 @@
 					item.disabled = item.disable || item.disabled || false
 					if (this.multiple) {
 						if (value.length > 0) {
-							let have = value.find(val => val === item[this.map.value])
+							// 可填写的选项存进 value 数组里的是自描述的 "id#文本#" token(见 inputChange 的修复),
+							// 不再是裸的 id,这里匹配的时候要多兼容一下按 "#" 取前半段再比较,不然填过字的选项会被判定成"未勾选"
+							let have = value.find(val => val === item[this.map.value] || (typeof val === 'string' && val.indexOf('#') > -1 && val.split('#')[0] === item[this.map.value]))
 							item.selected = have !== undefined
 						} else {
 							item.selected = false
@@ -471,15 +507,24 @@
 						// item.selected = value === item[this.map.value]
 					}
 					if(item.content && item.content.includes('##')){
-						let otherObj = this.showOtherInputVal(value,this.multiple)
+						// 多选场景下把这一项自己的 value 传进去,让 showOtherInputVal 只找属于这一项的那条记录,
+						// 不再是数组里随便哪条(单选只有一项,传不传都一样,不影响原逻辑)
+						let otherObj = this.showOtherInputVal(value,this.multiple,item[this.map.value])
 						// console.log('testRadioInputValue222',item,otherObj)
 						// console.log('otherObj77777',otherObj)
 						item.inputValue = otherObj.end
 						// console.log('otherObj77777',item)
-						if(otherObj.start === item.value){
+						// 多选下 item.selected 上面按 value 数组已经正确算过了,这里不再需要、也不能再用 item.value = otherObj.end
+						// 去覆盖 —— item.value 是这个 checkbox 原生 value 属性绑定的标识,多选场景下改成填写的文本内容,
+						// 会导致下一次勾选变化时对不上号,选中状态跟着丢
+						if(!this.multiple && otherObj.start === item.value){
 							item.selected = true;
 							item.value = otherObj.end;
 						}
+						// showOtherInputVal 反推不出来时,用重建前缓存的内容(按下标)兜底,避免多选下切换勾选把已填文本冲掉
+						if (this.multiple && !item.inputValue && prevInputMap[index]) {
+							item.inputValue = prevInputMap[index]
+						}
 					}
 					list.push(item)
 				})