Explorar el Código

销售端新增查询未绑定企微userId的信息采集用户列表

cgp hace 3 semanas
padre
commit
d0e4cd27eb

+ 8 - 0
src/api/qw/collectionUnBind.js

@@ -15,3 +15,11 @@ export function listUnbindCollection(queryDto) {
     data: queryDto
   })
 }
+
+export function createSimpleUserInfo(addDto) {
+  return request({
+    url: '/hisStore/collection/createSimpleUserInfo',
+    method: 'post',
+    data: addDto
+  })
+}

+ 498 - 0
src/views/qw/collectionUnBind/addCollectionDialog.vue

@@ -0,0 +1,498 @@
+<template>
+  <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="800px" @close="handleClose" append-to-body>
+    <el-form validate-on-rule-change :rules="rules" ref="form" :model="form" label-width="140px">
+      <el-form-item label="小程序" prop="appId">
+        <el-select v-model="form.appId" placeholder="小程序" clearable>
+          <el-option v-for="dict in sourceList" :key="dict.dictValue1" :label="dict.dictLabel" :value="dict.dictValue1" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="信息模板" prop="questionId">
+        <el-select @change="selectQuestion" v-model="form.questionId" placeholder="请选择问答">
+          <el-option v-for="dict in questionOptions" :key="dict.dictValue" :label="dict.dictLabel"
+                     :value="parseInt(dict.dictValue)" />
+        </el-select>
+      </el-form-item>
+
+      <!-- 动态渲染问题区域 -->
+      <div v-if="form.answers && form.answers.length > 0">
+        <div style="margin-bottom: 20px;margin-top: 20px;" v-for="(answer, index) in form.answers" :key="index">
+          <div style="margin-bottom: 20px;margin-top: 20px;">
+            <span style="font-size: 15px;font-weight: bold; margin-left: 31px">{{ answer.title }}</span>
+          </div>
+          <div style="margin-left: 31px;">
+            <el-checkbox-group
+              v-model="answer.value"
+              size="mini"
+              :disabled="!canEditAnswers"
+              @change="onAnswerChange">
+              <el-checkbox v-for="option in answer.options" :key="option.value" :label="option.value">
+                {{ option.name }}
+              </el-checkbox>
+            </el-checkbox-group>
+          </div>
+        </div>
+      </div>
+
+      <el-form-item label="用户姓名" prop="userName">
+        <el-input v-model="form.userName" placeholder="请输入用户姓名"></el-input>
+      </el-form-item>
+      <el-form-item label="用户手机号后四位" prop="userPhoneFour">
+        <el-input v-model="form.userPhoneFour" placeholder="请输入手机号后四位"></el-input>
+      </el-form-item>
+      <el-form-item label="用户性别" prop="sex">
+        <el-select v-model="form.sex" placeholder="请选择用户性别">
+          <el-option label="男" :value="1" />
+          <el-option label="女" :value="0" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="年龄" prop="age">
+        <el-input-number v-model="form.age" placeholder="请输入年龄" style="width: 20%"/>
+      </el-form-item>
+
+      <el-form-item label="过敏情况" prop="allergy">
+        <el-input type="textarea" :rows="2" placeholder="请输入过敏情况" v-model="form.allergy">
+        </el-input>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input type="textarea" :rows="2" placeholder="请输入备注" v-model="form.remark">
+        </el-input>
+      </el-form-item>
+      <el-form-item v-if="form.questionId" label="是否关联产品疗法" prop="isPackage">
+        <el-radio-group v-model="form.isPackage" @change="handleIsPackageChange">
+          <el-radio :label="0">否</el-radio>
+          <el-radio :label="1">是</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item v-if="form.isPackage == 1" label="产品疗法" prop="packageId">
+        <el-select filterable v-model="form.packageId" placeholder="请选择产品疗法">
+          <el-option v-for="dict in privatePackageOptions" :key="dict.dictValue" :label="dict.dictLabel"
+                     :value="parseInt(dict.dictValue)" />
+        </el-select>
+      </el-form-item>
+      <el-form-item v-if="form.packageId && form.isPackage && form.isPackage == 1" label="支付类型" prop="payType">
+        <el-radio-group v-model="form.payType">
+          <el-radio :label="1">全款</el-radio>
+          <el-radio :label="2">物流代收</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item v-if="form.packageId && form.payType == 2 && form.isPackage && form.isPackage == 1"
+                    label="预付金额" prop="amount">
+        <el-input v-model="form.amount" placeholder="请输入物流代收金额" type="number" />
+      </el-form-item>
+    </el-form>
+    <div slot="footer" class="dialog-footer">
+      <el-button @click="dialogVisible = false">取 消</el-button>
+      <el-button type="primary" @click="submitForm">确 定</el-button>
+    </div>
+
+    <!-- 二维码弹窗 -->
+    <el-dialog :title="qrCodeTitle" :visible.sync="qrCodeVisible" width="450px" append-to-body>
+      <div style="padding-bottom:15px;">
+        <img :src="codeImage" width="400px">
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="downloadImage(codeImage, qrCodeName + '.png')">下载二维码</el-button>
+      </div>
+    </el-dialog>
+  </el-dialog>
+</template>
+
+<script>
+import { questionOptions, getAnswer } from "@/api/hisStore/answer";
+import { allPrivatePackage } from "@/api/store/package";
+import { options } from "@/api/course/coursePlaySourceConfig";
+import { getWxaCodeCollectionUnLimit } from "@/api/hisStore/collection";
+import { createSimpleUserInfo } from "@/api/qw/collectionUnBind";
+
+export default {
+  name: "AddCollectionDialog",
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    extraParams: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  data() {
+    // 自定义姓名校验规则
+    const validateName = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error('请输入用户姓名'));
+      }
+      if (value.length < 1 || value.length > 20) {
+        return callback(new Error('姓名长度在 1 到 20 个字符'));
+      }
+      // 校验不能包含数字
+      const numberRegex = /[0-9]/;
+      if (numberRegex.test(value)) {
+        return callback(new Error('姓名不能包含数字'));
+      }
+      //校验只能包含中文、英文和空格
+      const nameRegex = /^[\u4e00-\u9fa5a-zA-Z\s]+$/;
+      if (!nameRegex.test(value)) {
+        return callback(new Error('姓名只能包含中文、英文和空格'));
+      }
+      callback();
+    };
+    return {
+      // ========== 新增:答案修改标识相关字段 ==========
+      originalAnswers: null,      // 保存原始 answers 数据
+      isAnswersModified: 0,       // 0-未修改, 1-已修改
+      isSalesProxyFill: true,     // 控制问题是否可编辑(新增模式默认可编辑)
+      // =============================================
+
+      dialogVisible: false,
+      sourceList: [],
+      form: {
+        id: null,
+        questionId: null,
+        packageId: null,
+        payType: null,
+        amount: null,
+        isPackage: null,
+        answers: [],
+        userName: '',
+        userPhoneFour: '',
+        sex: null,
+        age: null,
+        allergy: '',
+        remark: '',
+        appId: null
+      },
+      questionOptions: [],
+      privatePackageOptions: [],
+      qrCodeVisible: false,
+      qrCodeTitle: "用户信息采集分享",
+      qrCodeName: null,
+      codeImage: null,
+      rules: {
+        appId: [
+          {required: true, message: '请选择分享的小程序', trigger: 'change'}
+        ],
+        questionId: [
+          {required: true, message: '请选择信息模板', trigger: 'change'}
+        ],
+        packageId: [
+          {required: true, message: '请选择套餐包', trigger: 'change'}
+        ],
+        isPackage: [
+          {required: true, message: '请选择是否关联套餐包', trigger: 'change'}
+        ],
+        payType: [
+          {required: true, message: '请选择支付类型', trigger: 'change'}
+        ],
+        amount: [
+          {required: true, message: '请填写物流代收金额', trigger: 'blur'}
+        ],
+        userName: [
+          {required: true, validator: validateName, trigger: 'blur'}
+        ],
+        userPhoneFour: [
+          {required: true, message: '请输入手机号后四位', trigger: 'blur'},
+          {pattern: /^\d{4}$/, message: '请输入正确的4位数字', trigger: 'blur'}
+        ],
+        sex: [
+          {required: true, message: '请选择用户性别', trigger: 'change'},
+          {
+            validator: (rule, value, callback) => {
+              if (value !== 0 && value !== 1) {
+                callback(new Error('性别只能为男(1)或女(0)'));
+              } else {
+                callback();
+              }
+            },
+            trigger: 'change'
+          }
+        ],
+        age: [
+          {required: true, message: '请输入年龄', trigger: 'blur'},
+          {type: 'number', min: 18, max: 150, message: '年龄必须在 18 到 150 之间', trigger: 'blur'}
+        ]
+      }
+    };
+  },
+  computed: {
+    dialogTitle() {
+      return "新增信息采集";
+    },
+    // ========== 新增:计算属性,判断问题区域是否可编辑 ==========
+    canEditAnswers() {
+      return this.isSalesProxyFill === true;
+    }
+    // ======================================================
+  },
+  watch: {
+    visible: {
+      handler(val) {
+        this.dialogVisible = val;
+        if (val) {
+          this.initDialog();
+        }
+      },
+      immediate: true
+    },
+    // ========== 新增:监听 answers 的变化,判断是否修改 ==========
+    'form.answers': {
+      handler(newVal) {
+        if (this.originalAnswers) {
+          // 比较是否修改,修改则设为1,未修改设为0
+          this.isAnswersModified = this.isAnswersEqual(this.originalAnswers, newVal) ? 0 : 1;
+        }
+      },
+      deep: true
+    }
+    // ========================================================
+  },
+  created() {
+    this.getQuestionOptions();
+    this.getAllPrivatePackge();
+    this.getSourceOptions();
+  },
+  methods: {
+    // ========== 新增:深度比较方法 ==========
+    isAnswersEqual(original, current) {
+      if (!original || !current) return original === current;
+      if (original.length !== current.length) return false;
+
+      for (let i = 0; i < original.length; i++) {
+        const origAnswer = original[i];
+        const currAnswer = current[i];
+
+        // 比较 value 数组
+        if (!origAnswer.value || !currAnswer.value) {
+          if (origAnswer.value !== currAnswer.value) return false;
+        } else {
+          if (origAnswer.value.length !== currAnswer.value.length) return false;
+
+          // 排序后比较(因为顺序可能不影响业务逻辑)
+          const sortedOrig = [...origAnswer.value].sort((a, b) => a - b);
+          const sortedCurr = [...currAnswer.value].sort((a, b) => a - b);
+
+          for (let j = 0; j < sortedOrig.length; j++) {
+            if (sortedOrig[j] !== sortedCurr[j]) return false;
+          }
+        }
+      }
+      return true;
+    },
+    // ======================================
+
+    initDialog() {
+      this.resetFormData();
+      this.$nextTick(() => {
+        if (this.$refs.form) {
+          this.$refs.form.clearValidate();
+        }
+      });
+    },
+    getSourceOptions() {
+      options().then(res => {
+        this.sourceList = res.data;
+      });
+    },
+    handleIsPackageChange(value) {
+      if (value === 0) {
+        this.form.packageId = null;
+        this.form.payType = null;
+        this.form.amount = null;
+        this.$nextTick(() => {
+          this.$refs.form.clearValidate(['packageId', 'payType', 'amount']);
+        });
+      }
+    },
+    downloadImage(imageSrc, fileName) {
+      const link = document.createElement('a');
+      link.href = imageSrc;
+      link.download = fileName || '付款二维码.png';
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+    },
+    handleShare(id, appId) {
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '生成二维码中~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+      getWxaCodeCollectionUnLimit(id, appId).then(response => {
+        this.codeImage = response.url;
+        this.qrCodeVisible = true;
+        this.qrCodeName = id;
+        loadingRock.close();
+      }).finally(() => {
+        loadingRock.close();
+      });
+    },
+    getQuestionOptions() {
+      questionOptions().then(response => {
+        this.questionOptions = response.rows;
+      });
+    },
+    getAllPrivatePackge() {
+      allPrivatePackage().then(res => {
+        this.privatePackageOptions = res.rows;
+      });
+    },
+    // 选择问答模板
+    selectQuestion(val) {
+      if (!val) return;
+
+      // 显示加载提示
+      const loading = this.$loading({
+        lock: true,
+        text: '加载问题模板中...',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+      getAnswer(val).then(response => {
+        loading.close();
+
+        // 获取 answers 数组
+        let questions = [];
+        if (response.data && response.data.answers) {
+          questions = response.data.answers;
+        } else if (response.rows) {
+          questions = response.rows;
+        } else if (response.data && Array.isArray(response.data)) {
+          questions = response.data;
+        }
+
+        if (!questions || questions.length === 0) {
+          this.$message.warning('该模板没有问题数据');
+          return;
+        }
+
+        // 构建 answers 数组
+        const answers = questions.map(item => ({
+          title: item.title,
+          options: item.options || [],
+          value: item.value || [],
+          sort: item.sort,
+          flag: item.flag || false
+        }));
+
+        // ========== 新增:保存原始 answers 的深拷贝 ==========
+        this.originalAnswers = JSON.parse(JSON.stringify(answers));
+        this.isAnswersModified = 0; // 初始化为未修改
+        this.isSalesProxyFill = true; // 新增模式,问题区域可编辑
+        // ====================================================
+
+        // 保留用户已填写的基础信息
+        const preservedFields = {
+          userName: this.form.userName,
+          userPhoneFour: this.form.userPhoneFour,
+          sex: this.form.sex,
+          age: this.form.age,
+          allergy: this.form.allergy,
+          remark: this.form.remark,
+          appId: this.form.appId
+        };
+
+        // 更新表单
+        this.form = {
+          ...preservedFields,
+          questionId: val,
+          answers: answers,
+          isPackage: null,
+          packageId: null,
+          payType: null,
+          amount: null,
+          id: null
+        };
+
+      }).catch(error => {
+        loading.close();
+        console.error('获取问题详情失败:', error);
+        this.$message.error('获取问题模板失败,请稍后重试');
+      });
+    },
+    // ========== 新增:答案修改时的回调 ==========
+    onAnswerChange() {
+      // isAnswersModified 会通过 watch 自动更新
+      console.log('答案已修改,修改标识:', this.isAnswersModified);
+    },
+    // =========================================
+
+    resetFormData() {
+      this.form = {
+        id: null,
+        questionId: null,
+        packageId: null,
+        payType: null,
+        amount: null,
+        isPackage: null,
+        answers: [],
+        userName: '',
+        userPhoneFour: '',
+        sex: null,
+        age: null,
+        allergy: '',
+        remark: '',
+        appId: null
+      };
+      // ========== 新增:重置标识相关字段 ==========
+      this.originalAnswers = null;
+      this.isAnswersModified = 0;
+      this.isSalesProxyFill = true;
+      // ==========================================
+    },
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          // 构建提交数据
+          const submitData = {
+            ...this.form,
+            companyId: this.extraParams.companyId,
+            companyUserId: this.extraParams.companyUserId,
+            source: 'pc',
+            // ========== 新增:添加修改标识 ==========
+            fillFlag: this.isAnswersModified  // 0-未修改,1-已修改
+            // ======================================
+          };
+
+          // 如果未关联产品疗法,清除相关字段
+          if (submitData.isPackage !== 1) {
+            delete submitData.packageId;
+            delete submitData.payType;
+            delete submitData.amount;
+          } else {
+            if (submitData.payType !== 2) {
+              delete submitData.amount;
+            }
+          }
+
+          const appId = this.form.appId;
+
+          // 调用你的新增接口
+          createSimpleUserInfo(submitData).then(res => {
+            this.$message.success("新增成功");
+            this.dialogVisible = false;
+            this.$emit('success');
+            this.$emit('update:visible', false);
+            // 成功后生成分享二维码
+            if (res.data) {
+              this.handleShare(res.data, appId);
+            }
+          }).catch(error => {
+            this.$message.error(error.msg || "新增失败");
+          });
+        }
+      });
+    },
+    handleClose() {
+      this.dialogVisible = false;
+      this.$emit('update:visible', false);
+      this.resetFormData();
+    }
+  }
+};
+</script>
+
+<style scoped>
+</style>

+ 36 - 0
src/views/qw/collectionUnBind/index.vue

@@ -35,6 +35,11 @@
       </el-form-item>
     </el-form>
 
+    <!-- 新增按钮单独一行 -->
+    <div style="margin-bottom: 16px;">
+      <el-button type="success" icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
+    </div>
+
     <!-- 数据表格 -->
     <el-table border v-loading="loading" :data="collectionList">
       <el-table-column label="用户姓名" align="center" prop="userName" />
@@ -64,14 +69,25 @@
       :limit.sync="queryParams.pageSize"
       @pagination="getList"
     />
+
+    <!-- 新增弹窗 - 不传递 userId -->
+    <add-collection-dialog
+      :visible.sync="addDialogVisible"
+      :extra-params="extraParams"
+      @success="getList"
+    />
   </div>
 </template>
 
 <script>
 import { listUnbindCollection } from "@/api/qw/collectionUnBind";
+import AddCollectionDialog from "./addCollectionDialog.vue";
 
 export default {
   name: "UnbindCollection",
+  components: {
+    AddCollectionDialog
+  },
   data() {
     return {
       // 遮罩层
@@ -89,11 +105,19 @@ export default {
         userName: null,
         doctorName: null,
         companyUserName: null,
+      },
+      // 新增弹窗可见性
+      addDialogVisible: false,
+      // 额外参数(公司ID、销售ID等)
+      extraParams: {
+        companyId: null,
+        companyUserId: null
       }
     };
   },
   created() {
     this.getList();
+    this.getCurrentUserInfo();
   },
   methods: {
     /** 查询未绑定的信息采集列表 */
@@ -118,6 +142,18 @@ export default {
     /** 性别格式化 */
     sexFormat(sex) {
       return sex === 1 ? "男" : sex === 0 ? "女" : "";
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.addDialogVisible = true;
+    },
+    /** 获取当前用户信息(用于 extraParams) */
+    getCurrentUserInfo() {
+      const userInfo = this.$store.state.user?.userInfo;
+      if (userInfo) {
+        this.extraParams.companyId = userInfo.companyId;
+        this.extraParams.companyUserId = userInfo.userId;
+      }
     }
   }
 };

+ 49 - 2
src/views/qw/externalContact/collection.vue

@@ -126,6 +126,8 @@ export default {
       callback();
     };
     return {
+      originalAnswers: null, // 保存原始 answers 数据
+      isAnswersModified: 0, // 0-未修改, 1-已修改
       isSalesProxyFill: true, // 控制问题是否可编辑
       sourceList:[],
       extraParams: {
@@ -216,6 +218,18 @@ export default {
       return this.isSalesProxyFill === true;
     }
   },
+// 监听 answers 的变化
+  watch: {
+    'form.answers': {
+      handler(newVal) {
+        if (this.originalAnswers) {
+          // 比较是否修改,修改则设为1,未修改设为0
+          this.isAnswersModified = this.isAnswersEqual(this.originalAnswers, newVal) ? 0 : 1;
+        }
+      },
+      deep: true
+    }
+  },
   methods: {
     // 新增:用于接收主页面传来的公司id和销售id
     setExtraParams(params) {
@@ -287,9 +301,13 @@ export default {
       if (data.answers && Array.isArray(data.answers)) {
         processedAnswers = data.answers.map(answer => ({
           ...answer,
-          value: Array.isArray(answer.value) ? answer.value : []
+          value: Array.isArray(answer.value) ? [...answer.value] : [] // 深拷贝
         }));
       }
+
+      // 保存原始数据的深拷贝
+      this.originalAnswers = JSON.parse(JSON.stringify(processedAnswers));
+      this.isAnswersModified = 0; // 初始化为未修改
       this.isSalesProxyFill = data.isSalesProxyFill === true;
 
       this.form = {
@@ -329,8 +347,35 @@ export default {
       };
       this.extraParams = { companyId: null, companyUserId: null };
       this.isSalesProxyFill = true;
+      this.originalAnswers = null;
+      this.isAnswersModified = 0; // 重置为未修改
     },
+    // 深度比较方法
+    isAnswersEqual(original, current) {
+      if (!original || !current) return original === current;
+      if (original.length !== current.length) return false;
+
+      for (let i = 0; i < original.length; i++) {
+        const origAnswer = original[i];
+        const currAnswer = current[i];
 
+        // 比较 value 数组
+        if (!origAnswer.value || !currAnswer.value) {
+          if (origAnswer.value !== currAnswer.value) return false;
+        } else {
+          if (origAnswer.value.length !== currAnswer.value.length) return false;
+
+          // 排序后比较(因为顺序可能不影响业务逻辑)
+          const sortedOrig = [...origAnswer.value].sort((a,b) => a-b);
+          const sortedCurr = [...currAnswer.value].sort((a,b) => a-b);
+
+          for (let j = 0; j < sortedOrig.length; j++) {
+            if (sortedOrig[j] !== sortedCurr[j]) return false;
+          }
+        }
+      }
+      return true;
+    },
     //选择问答模板
     selectQuestion(val) {
       // 保留用户已填写的基础信息
@@ -377,7 +422,9 @@ export default {
             userId: this.userId,
             companyId: this.extraParams.companyId,
             companyUserId: this.extraParams.companyUserId,
-            source: 'pc'  // 添加标识符
+            source: 'pc',
+            // 添加修改标识
+            fillFlag: this.isAnswersModified// 添加修改标识:0-未修改,1-已修改
           };
           submitData.userId = this.userId;