Pārlūkot izejas kodu

销售端优化信息采集提交时的必填校验

cgp 3 nedēļas atpakaļ
vecāks
revīzija
36f1cd2d5c

+ 22 - 10
src/views/qw/collectionPendingSales/completeCollectionInfoDialog.vue

@@ -17,16 +17,19 @@
                   {{ option.name }}
                   {{ option.name }}
                 </el-checkbox>
                 </el-checkbox>
 
 
-                <!-- 如果选项的open为true且选项被选中,显示备注输入框 -->
-                <el-input
-                  v-if="option.open && isOptionSelected(answer, option)"
-                  v-model="option.remarkText"
-                  placeholder="请输入备注信息"
-                  size="mini"
-                  maxlength="20"
-                  show-word-limit
-                  style="width: 200px; margin-left: 5px;"
-                  @blur="onRemarkBlur(option)"/>
+                <!-- 备注输入区域(含必填提示) -->
+                <div v-if="option.open && isOptionSelected(answer, option)" style="display: inline-block;">
+                  <el-input
+                    v-model="option.remarkText"
+                    placeholder="请输入备注信息"
+                    size="mini"
+                    maxlength="20"
+                    show-word-limit
+                    style="width: 200px; margin-left: 5px;"
+                    :class="{ 'remark-required': !option.remarkText || option.remarkText.trim() === '' }"
+                    @blur="onRemarkBlur(option)"/>
+                  <div v-if="!option.remarkText || option.remarkText.trim() === ''" class="remark-error-tip">此项为必填</div>
+                </div>
               </div>
               </div>
             </el-checkbox-group>
             </el-checkbox-group>
           </div>
           </div>
@@ -304,4 +307,13 @@ export default {
 </script>
 </script>
 
 
 <style scoped>
 <style scoped>
+.remark-required >>> .el-input__inner {
+  border-color: #f56c6c !important;
+}
+.remark-error-tip {
+  color: #f56c6c;
+  font-size: 12px;
+  line-height: 1.5;
+  margin-left: 5px;
+}
 </style>
 </style>

+ 66 - 35
src/views/qw/collectionUnBind/addCollectionDialog.vue

@@ -30,17 +30,20 @@
                   {{ option.name }}
                   {{ option.name }}
                 </el-checkbox>
                 </el-checkbox>
 
 
-                <!-- 如果选项的open为true且选项被选中,显示备注输入框 -->
-                <el-input
-                  v-if="option.open && isOptionSelected(answer, option)"
-                  v-model="option.remarkText"
-                  placeholder="请输入备注信息"
-                  size="mini"
-                  maxlength="20"
-                  show-word-limit
-                  style="width: 200px; margin-left: 5px;"
-                  :disabled="!canEditAnswers"
-                  @blur="onRemarkBlur(option)"/>
+                <!-- 备注输入区域 -->
+                <div v-if="option.open && isOptionSelected(answer, option)" style="display: inline-block;">
+                  <el-input
+                    v-model="option.remarkText"
+                    placeholder="请输入备注信息"
+                    size="mini"
+                    maxlength="20"
+                    show-word-limit
+                    style="width: 200px; margin-left: 5px;"
+                    :class="{ 'remark-required': isRemarkRequired(answer, option) }"
+                    :disabled="!canEditAnswers"
+                    @blur="onRemarkBlur(option)"/>
+                  <div v-if="isRemarkRequired(answer, option)" class="remark-error-tip">此项为必填</div>
+                </div>
               </div>
               </div>
             </el-checkbox-group>
             </el-checkbox-group>
           </div>
           </div>
@@ -180,7 +183,6 @@ export default {
       qrCodeTitle: "用户信息采集分享",
       qrCodeTitle: "用户信息采集分享",
       qrCodeName: null,
       qrCodeName: null,
       codeImage: null,
       codeImage: null,
-      // 新增:加载状态
       permissionLoading: false,
       permissionLoading: false,
       rules: {
       rules: {
         appId: [
         appId: [
@@ -259,12 +261,9 @@ export default {
     this.getQuestionOptions();
     this.getQuestionOptions();
     this.getAllPrivatePackge();
     this.getAllPrivatePackge();
     this.getSourceOptions();
     this.getSourceOptions();
-    // ==========获取销售代填权限配置 ==========
     this.fetchSalesProxyFillPermission();
     this.fetchSalesProxyFillPermission();
-    // ==============================================
   },
   },
   methods: {
   methods: {
-    // ==========获取销售代填权限 ==========
     async fetchSalesProxyFillPermission() {
     async fetchSalesProxyFillPermission() {
       this.permissionLoading = true;
       this.permissionLoading = true;
       try {
       try {
@@ -278,9 +277,14 @@ export default {
       }
       }
     },
     },
 
 
+    // 判断某个选项的备注是否为必填且未填写
+    isRemarkRequired(answer, option) {
+      if (!this.isSalesProxyFill) return false;
+      return option.open && this.isOptionSelected(answer, option) && (!option.remarkText || option.remarkText.trim() === '');
+    },
+
     // 监听复选框组的变化
     // 监听复选框组的变化
     onCheckboxGroupChange(answer) {
     onCheckboxGroupChange(answer) {
-      // 遍历所有选项,如果选项未被选中,则清除其备注文本
       answer.options.forEach(option => {
       answer.options.forEach(option => {
         if (!answer.value.includes(option.value)) {
         if (!answer.value.includes(option.value)) {
           option.remarkText = '';
           option.remarkText = '';
@@ -296,7 +300,6 @@ export default {
 
 
     // 备注输入框失去焦点时的处理
     // 备注输入框失去焦点时的处理
     onRemarkBlur(option) {
     onRemarkBlur(option) {
-      // 如果备注文本为空,则清空
       if (!option.remarkText?.trim()) {
       if (!option.remarkText?.trim()) {
         option.remarkText = '';
         option.remarkText = '';
       }
       }
@@ -310,14 +313,12 @@ export default {
         const origAnswer = original[i];
         const origAnswer = original[i];
         const currAnswer = current[i];
         const currAnswer = current[i];
 
 
-        // 比较基本属性
         if (origAnswer.title !== currAnswer.title ||
         if (origAnswer.title !== currAnswer.title ||
           origAnswer.sort !== currAnswer.sort ||
           origAnswer.sort !== currAnswer.sort ||
           origAnswer.flag !== currAnswer.flag) {
           origAnswer.flag !== currAnswer.flag) {
           return false;
           return false;
         }
         }
 
 
-        // 比较选择的值
         if (!origAnswer.value || !currAnswer.value) {
         if (!origAnswer.value || !currAnswer.value) {
           if (origAnswer.value !== currAnswer.value) return false;
           if (origAnswer.value !== currAnswer.value) return false;
         } else {
         } else {
@@ -329,7 +330,6 @@ export default {
           }
           }
         }
         }
 
 
-        // 比较选项
         if (origAnswer.options && currAnswer.options) {
         if (origAnswer.options && currAnswer.options) {
           if (origAnswer.options.length !== currAnswer.options.length) return false;
           if (origAnswer.options.length !== currAnswer.options.length) return false;
 
 
@@ -337,7 +337,6 @@ export default {
             const origOption = origAnswer.options[k];
             const origOption = origAnswer.options[k];
             const currOption = currAnswer.options[k];
             const currOption = currAnswer.options[k];
 
 
-            // 比较基本选项属性
             if (origOption.name !== currOption.name ||
             if (origOption.name !== currOption.name ||
               origOption.value !== currOption.value ||
               origOption.value !== currOption.value ||
               origOption.open !== currOption.open ||
               origOption.open !== currOption.open ||
@@ -358,11 +357,13 @@ export default {
         }
         }
       });
       });
     },
     },
+
     getSourceOptions() {
     getSourceOptions() {
       options().then(res => {
       options().then(res => {
         this.sourceList = res.data;
         this.sourceList = res.data;
       });
       });
     },
     },
+
     handleIsPackageChange(value) {
     handleIsPackageChange(value) {
       if (value === 0) {
       if (value === 0) {
         this.form.packageId = null;
         this.form.packageId = null;
@@ -373,6 +374,7 @@ export default {
         });
         });
       }
       }
     },
     },
+
     downloadImage(imageSrc, fileName) {
     downloadImage(imageSrc, fileName) {
       const link = document.createElement('a');
       const link = document.createElement('a');
       link.href = imageSrc;
       link.href = imageSrc;
@@ -381,6 +383,7 @@ export default {
       link.click();
       link.click();
       document.body.removeChild(link);
       document.body.removeChild(link);
     },
     },
+
     handleShare(id, appId) {
     handleShare(id, appId) {
       let loadingRock = this.$loading({
       let loadingRock = this.$loading({
         lock: true,
         lock: true,
@@ -398,16 +401,19 @@ export default {
         loadingRock.close();
         loadingRock.close();
       });
       });
     },
     },
+
     getQuestionOptions() {
     getQuestionOptions() {
       questionOptions().then(response => {
       questionOptions().then(response => {
         this.questionOptions = response.rows;
         this.questionOptions = response.rows;
       });
       });
     },
     },
+
     getAllPrivatePackge() {
     getAllPrivatePackge() {
       allPrivatePackage().then(res => {
       allPrivatePackage().then(res => {
         this.privatePackageOptions = res.rows;
         this.privatePackageOptions = res.rows;
       });
       });
     },
     },
+
     selectQuestion(val) {
     selectQuestion(val) {
       if (!val) return;
       if (!val) return;
 
 
@@ -443,7 +449,6 @@ export default {
           flag: item.flag || false
           flag: item.flag || false
         }));
         }));
 
 
-        // 保存原始 answers
         this.originalAnswers = JSON.parse(JSON.stringify(answers));
         this.originalAnswers = JSON.parse(JSON.stringify(answers));
         this.isAnswersModified = 0;
         this.isAnswersModified = 0;
 
 
@@ -475,14 +480,12 @@ export default {
       });
       });
     },
     },
 
 
-    // 处理选项数据,添加备注相关的默认值
     processOptions(options) {
     processOptions(options) {
       return options.map(option => {
       return options.map(option => {
         return {
         return {
           name: option.name || '',
           name: option.name || '',
           value: option.value,
           value: option.value,
           open: option.open || false,
           open: option.open || false,
-          // 添加备注相关的字段
           remarkText: ''
           remarkText: ''
         };
         };
       });
       });
@@ -512,12 +515,33 @@ export default {
       this.originalAnswers = null;
       this.originalAnswers = null;
       this.isAnswersModified = 0;
       this.isAnswersModified = 0;
     },
     },
+
+    // 自定义备注必填校验
+    validateRemarksRequired() {
+      if (!this.isSalesProxyFill) return true;
+      for (const answer of this.form.answers) {
+        for (const option of answer.options) {
+          if (option.open && answer.value.includes(option.value)) {
+            if (!option.remarkText || option.remarkText.trim() === '') {
+              return false;
+            }
+          }
+        }
+      }
+      return true;
+    },
+
     submitForm() {
     submitForm() {
       this.$refs["form"].validate(valid => {
       this.$refs["form"].validate(valid => {
         if (valid) {
         if (valid) {
-          // 1. 构建提交用的 answers 副本,组装 remarksList 并清理临时字段
+          // 1. 自定义备注必填校验
+          if (!this.validateRemarksRequired()) {
+            this.$message.error('请填写所有必填的备注信息');
+            return;
+          }
+
+          // 2. 构建提交用的 answers 副本
           const answersForSubmit = this.form.answers.map(answer => {
           const answersForSubmit = this.form.answers.map(answer => {
-            // 1. 构建 remarksList
             const remarks = [];
             const remarks = [];
             answer.options.forEach(option => {
             answer.options.forEach(option => {
               if (option.remarkText && option.remarkText.trim()) {
               if (option.remarkText && option.remarkText.trim()) {
@@ -528,18 +552,15 @@ export default {
               }
               }
             });
             });
 
 
-            // 2. 清理 options,移除临时字段 remarkText
-            const cleanOptions = answer.options.map(({ remarkText, ...opt }) => opt);
+            const cleanOptions = answer.options.map(({remarkText, ...opt}) => opt);
 
 
-            // 3. 返回符合后端 AnswerVO 结构的对象
             return {
             return {
               ...answer,
               ...answer,
-              remarksList: remarks,   // 标准备注字段
-              options: cleanOptions       // 纯净的选项列表
+              remarksList: remarks,
+              options: cleanOptions
             };
             };
           });
           });
 
 
-          // 2. 构建提交数据,使用处理后的 answers
           const submitData = {
           const submitData = {
             ...this.form,
             ...this.form,
             answers: answersForSubmit,
             answers: answersForSubmit,
@@ -549,7 +570,6 @@ export default {
             fillFlag: this.isAnswersModified
             fillFlag: this.isAnswersModified
           };
           };
 
 
-          // 3. 根据是否关联套餐包清理无关字段
           if (submitData.isPackage !== 1) {
           if (submitData.isPackage !== 1) {
             delete submitData.packageId;
             delete submitData.packageId;
             delete submitData.payType;
             delete submitData.payType;
@@ -562,7 +582,6 @@ export default {
 
 
           const appId = this.form.appId;
           const appId = this.form.appId;
 
 
-          // 4. 提交请求
           createSimpleUserInfo(submitData).then(res => {
           createSimpleUserInfo(submitData).then(res => {
             this.$message.success("新增成功");
             this.$message.success("新增成功");
             this.dialogVisible = false;
             this.dialogVisible = false;
@@ -577,6 +596,7 @@ export default {
         }
         }
       });
       });
     },
     },
+
     handleClose() {
     handleClose() {
       this.dialogVisible = false;
       this.dialogVisible = false;
       this.$emit('update:visible', false);
       this.$emit('update:visible', false);
@@ -587,5 +607,16 @@ export default {
 </script>
 </script>
 
 
 <style scoped>
 <style scoped>
-/* 移除了原有的 remark-toggle 样式,因为我们不再使用 */
+/* 必填备注输入框红色边框 */
+.remark-required >>> .el-input__inner {
+  border-color: #f56c6c !important;
+}
+
+/* 必填提示文字 */
+.remark-error-tip {
+  color: #f56c6c;
+  font-size: 12px;
+  line-height: 1.5;
+  margin-left: 5px;
+}
 </style>
 </style>

+ 57 - 21
src/views/qw/externalContact/collection.vue

@@ -31,16 +31,19 @@
                 </el-checkbox>
                 </el-checkbox>
 
 
                 <!-- 如果选项的open为true且选项被选中,显示备注输入框 -->
                 <!-- 如果选项的open为true且选项被选中,显示备注输入框 -->
-                <el-input
-                  v-if="option.open && isOptionSelected(answer, option)"
-                  v-model="option.remarkText"
-                  placeholder="请输入备注信息"
-                  size="mini"
-                  maxlength="20"
-                  show-word-limit
-                  style="width: 200px; margin-left: 5px;"
-                  :disabled="!canEditAnswers"
-                  @blur="onRemarkBlur(option)"/>
+                <div v-if="option.open && isOptionSelected(answer, option)" style="display: inline-block;">
+                  <el-input
+                    v-model="option.remarkText"
+                    placeholder="请输入备注信息"
+                    size="mini"
+                    maxlength="20"
+                    show-word-limit
+                    style="width: 200px; margin-left: 5px;"
+                    :class="{ 'remark-required': isRemarkRequired(answer, option) }"
+                    :disabled="!canEditAnswers"
+                    @blur="onRemarkBlur(option)"/>
+                  <div v-if="isRemarkRequired(answer, option)" class="remark-error-tip">此项为必填</div>
+                </div>
               </div>
               </div>
             </el-checkbox-group>
             </el-checkbox-group>
           </div>
           </div>
@@ -272,7 +275,6 @@ export default {
         }
         }
       });
       });
     },
     },
-
     // 检查选项是否被选中
     // 检查选项是否被选中
     isOptionSelected(answer, option) {
     isOptionSelected(answer, option) {
       return answer.value && answer.value.includes(option.value);
       return answer.value && answer.value.includes(option.value);
@@ -487,6 +489,7 @@ export default {
     selectQuestion(val) {
     selectQuestion(val) {
       // 保留用户已填写的基础信息
       // 保留用户已填写的基础信息
       const preservedFields = {
       const preservedFields = {
+        appId: this.form.appId,
         userName: this.form.userName,
         userName: this.form.userName,
         userPhoneFour: this.form.userPhoneFour,
         userPhoneFour: this.form.userPhoneFour,
         sex: this.form.sex,
         sex: this.form.sex,
@@ -563,10 +566,35 @@ export default {
       });
       });
     },
     },
 
 
+    isRemarkRequired(answer, option) {
+      if (!this.isSalesProxyFill) return false;
+      return option.open && this.isOptionSelected(answer, option) && (!option.remarkText || option.remarkText.trim() === '');
+    },
+    validateRemarksRequired() {
+      if (!this.isSalesProxyFill) return true;
+      for (const answer of this.form.answers) {
+        for (const option of answer.options) {
+          if (option.open && answer.value.includes(option.value)) {
+            if (!option.remarkText || option.remarkText.trim() === '') {
+              return false;
+            }
+          }
+        }
+      }
+      return true;
+    },
+
+
     submitForm() {
     submitForm() {
       this.$refs["form"].validate(valid => {
       this.$refs["form"].validate(valid => {
         if (valid) {
         if (valid) {
-          // 构建基础提交数据
+          // 1. 自定义备注必填校验
+          if (!this.validateRemarksRequired()) {
+            this.$message.error('请填写必填的备注信息');
+            return;
+          }
+
+          // 2. 构建基础提交数据(原有逻辑不变)
           const submitData = {
           const submitData = {
             ...this.form,
             ...this.form,
             userId: this.userId,
             userId: this.userId,
@@ -576,9 +604,8 @@ export default {
             fillFlag: this.isAnswersModified
             fillFlag: this.isAnswersModified
           };
           };
 
 
-          // 处理答案:将 option.remarkText 转换为 remarksList 格式
+          // 3. 处理答案数据,组装 remarksList
           const processedAnswers = this.form.answers.map(answer => {
           const processedAnswers = this.form.answers.map(answer => {
-            // 1. 构建 remarksList
             const remarksList = [];
             const remarksList = [];
             answer.options.forEach(option => {
             answer.options.forEach(option => {
               if (option.remarkText && option.remarkText.trim()) {
               if (option.remarkText && option.remarkText.trim()) {
@@ -589,23 +616,21 @@ export default {
               }
               }
             });
             });
 
 
-            // 2. 清理 options,移除临时字段 remarkText
             const cleanOptions = answer.options.map(({ remarkText, ...opt }) => opt);
             const cleanOptions = answer.options.map(({ remarkText, ...opt }) => opt);
 
 
-            // 3. 返回符合后端 AnswerVO 结构的对象
             return {
             return {
               title: answer.title,
               title: answer.title,
               value: [...answer.value],
               value: [...answer.value],
               sort: answer.sort,
               sort: answer.sort,
               flag: answer.flag,
               flag: answer.flag,
-              remarksList: remarksList,   // 标准备注字段
-              options: cleanOptions       // 纯净的选项列表
+              remarksList: remarksList,
+              options: cleanOptions
             };
             };
           });
           });
 
 
           submitData.answers = processedAnswers;
           submitData.answers = processedAnswers;
 
 
-          // 处理套餐关联逻辑(原逻辑不变
+          // 4. 处理套餐关联逻辑(原有
           if (submitData.isPackage !== 1) {
           if (submitData.isPackage !== 1) {
             delete submitData.packageId;
             delete submitData.packageId;
             delete submitData.payType;
             delete submitData.payType;
@@ -618,7 +643,7 @@ export default {
 
 
           const appId = this.form.appId;
           const appId = this.form.appId;
 
 
-          // 根据 id 判断新增或修改(原逻辑不变
+          // 5. 提交请求(原有
           if (submitData.id != null) {
           if (submitData.id != null) {
             updateCollection(submitData).then(res => {
             updateCollection(submitData).then(res => {
               this.msgSuccess("修改成功");
               this.msgSuccess("修改成功");
@@ -647,5 +672,16 @@ export default {
 </script>
 </script>
 
 
 <style scoped>
 <style scoped>
-/* 移除了原有的 remark-toggle 样式,因为我们不再使用 */
+/* 必填备注输入框红色边框 */
+.remark-required >>> .el-input__inner {
+  border-color: #f56c6c !important;
+}
+
+/* 必填提示文字 */
+.remark-error-tip {
+  color: #f56c6c;
+  font-size: 12px;
+  line-height: 1.5;
+  margin-left: 5px;
+}
 </style>
 </style>