ct 2 недель назад
Родитель
Сommit
864565fca5

+ 18 - 0
src/api/store/user.js

@@ -125,3 +125,21 @@ export function enabledBlackUsers(data) {
   })
 }
 
+// 发送验证码
+export function sendCode(phone) {
+  return request({
+    url: '/store/user/sendCode',
+    method: 'get',
+    params: { phone }
+  })
+}
+
+export function bindPhone(data) {
+  return request({
+    url: '/store/user/bindPhone',
+    method: 'post',
+    data:data
+  })
+}
+
+

+ 1 - 0
src/views/qw/externalContact/deptIndex.vue

@@ -343,6 +343,7 @@
     <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="企微客户ID" align="center" prop="id" />
+      <el-table-column label="小程序ID" align="center" prop="fsUserId"/>
       <el-table-column label="企微客户头像" align="center" prop="avatar" width="100px">
         <template slot-scope="scope">
           <el-popover

+ 1 - 0
src/views/qw/externalContact/index.vue

@@ -378,6 +378,7 @@
     <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="企微客户ID" align="center" prop="id" />
+      <el-table-column label="小程序ID" align="center" prop="fsUserId"/>
       <el-table-column label="企微客户头像" align="center" prop="avatar" width="100px">
         <template slot-scope="scope">
           <el-popover

+ 44 - 3
src/views/qw/externalContact/myExternalContact.vue

@@ -354,6 +354,7 @@
     <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="企微客户ID" align="center" prop="id"/>
+      <el-table-column label="小程序ID" align="center" prop="fsUserId"/>
       <el-table-column label="企微客户头像" align="center" prop="avatar" width="100px">
         <template slot-scope="scope">
           <el-popover
@@ -988,6 +989,15 @@
 	  <info  ref="Details" />
 	</el-drawer>
     <el-dialog :title="user.title" :visible.sync="user.open" width="800px" append-to-body>
+      <el-form ref="bindForm" :model="bindForm" :rules="bindRules" label-width="100px">
+        <el-form-item label="手机号" prop="phone">
+          <el-input v-model="bindForm.phone" placeholder="请输入手机号" style="width: 220px; margin-right: 10px;"></el-input>
+          <el-button @click="sendCode">发送验证码</el-button>
+        </el-form-item>
+        <el-form-item label="验证码" prop="code">
+          <el-input v-model="bindForm.code" placeholder="请输入验证码" style="width: 220px;"></el-input>
+        </el-form-item>
+      </el-form>
       <selectUser ref="selectUser" @bindMiniCustomerId="bindMiniCustomerId"></selectUser>
     </el-dialog>
     <el-dialog :title="collection.title" :visible.sync="collection.open"   width="1100px" append-to-body>
@@ -1283,6 +1293,19 @@ export default {
       // 表单校验
       rules: {
       },
+      bindForm: {
+        phone: '',
+        code: ''
+      },
+      bindRules: {
+        phone: [
+          { required: true, message: '请输入手机号', trigger: 'blur' },
+          { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
+        ],
+        code: [
+          { required: true, message: '请输入验证码', trigger: 'blur' }
+        ]
+      },
       fsUserId: null,
     };
   },
@@ -1755,6 +1778,8 @@ export default {
     bindMiniCustomerId(row){
 
       this.userForm.fsUserId=row;
+      this.userForm.phone = this.bindForm.phone;
+      this.userForm.code = this.bindForm.code;
       bindUserId(this.userForm).then(res=>{
          if (res.code==200){
            this.$message.success('绑定成功')
@@ -2121,9 +2146,15 @@ export default {
     },
 
     handleUpdateUser(row){
-        this.user.title="绑定客户"
-        this.user.open=true;
-        this.userForm.id=row.id;
+        this.$refs.bindForm.validate(valid => {
+          if (valid) {
+            this.user.title="绑定客户"
+            this.user.open=true;
+            this.userForm.id=row.id;
+          } else {
+            return false;
+          }
+        });
     },
 
     handleUnBindUserId(val){
@@ -2147,6 +2178,16 @@ export default {
       })
     },
 
+    sendCode() {
+      this.$refs.bindForm.validateField('phone', (valid) => {
+        if (valid) {
+          this.$message.success('验证码已发送');
+        } else {
+          return false;
+        }
+      });
+    },
+
     bindCustomerId(row){
 
       console.log("row",row)

+ 160 - 2
src/views/store/user/list.vue

@@ -84,7 +84,7 @@
     <el-table v-loading="loading" border :data="userList" @selection-change="handleSelectionChange" >
       <el-table-column type="selection" width="55" align="center" />
 
-      <el-table-column label="用户昵称" align="center" prop="nickname" width="150px"/>
+      <el-table-column label="用户昵称" align="center" prop="nickName" width="150px"/>
       <el-table-column label="用户头像" align="center" prop="avatar" >
          <template slot-scope="scope">
                  <el-image v-if="scope.row.avatar!=null"
@@ -115,6 +115,12 @@
             type="text"
             @click="handleNickName(scope.row)"
           >修改昵称</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-if="scope.row.phone==null || scope.row.phone==''"
+            @click="handleBindPhone(scope.row)"
+          >绑定手机号</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -160,18 +166,73 @@
          <userDetails  ref="userDetails" />
        </el-drawer>
 
+    <!-- 绑定用户手机号 -->
+    <el-dialog :title="bindPhone.title" :visible.sync="bindPhone.open" width="500px" append-to-body>
+      <el-form ref="bindPhoneForm" :model="bindPhoneForm"  :rules="bindRules" label-width="80px">
+        <el-form-item label="用户昵称" prop="nickName" label-width="100px">
+          <el-input v-model="bindPhoneForm.nickName" placeholder="请输入用户昵称" :disabled="true"/>
+        </el-form-item>
+        <el-form-item label="用户手机号" prop="phone" label-width="100px">
+          <el-input v-model="bindPhoneForm.phone" placeholder="请输入用户手机号">
+            <el-button
+              slot="append"
+              @click="sendCode"
+              :disabled="bindPhone.isCountingDown || bindPhone.countdown > 120"
+              :loading="bindPhone.sendCodeLoading"
+            >
+              {{ countdownText }}
+            </el-button>
+          </el-input>
+        </el-form-item>
+        <el-form-item label="验证码" prop="code" label-width="100px">
+          <el-input v-model="bindPhoneForm.code" placeholder="请输入验证码"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitBindPhoneForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
 
   </div>
 </template>
 
 <script>
-import { listUser, getUser, delUser, addUser, updateUser, exportUser } from "@/api/store/user";
+import { listUser, getUser, delUser, addUser, updateUser, exportUser,sendCode,bindPhone } from "@/api/store/user";
 import userDetails from '../components/userDetails.vue';
 export default {
   name: "User",
   components: {userDetails},
   data() {
     return {
+      orOptions:[],
+      bindRules: {
+        phone: [
+          { required: true, message: '请输入手机号', trigger: 'blur' },
+          { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
+        ],
+        code: [
+          { required: true, message: '请输入验证码', trigger: 'blur' }
+        ]
+      },
+      bindPhoneForm:{
+        nickName: '',
+        userId: null,
+        phone: '',
+        code: ''
+      },
+      bindPhone:{
+        // 弹出层标题
+        title: "",
+        // 是否显示弹出层
+        open: false,
+        // 发送验证码相关
+        countdown: 0,           // 当前倒计时秒数
+        isCountingDown: false,  // 是否正在倒计时
+        sendCodeLoading: false, // 发送中loading
+        countdownTimer: null,   // 定时器引用
+      },
       show:{
               title:"用户详情",
               open:false,
@@ -238,6 +299,22 @@ export default {
       }
     };
   },
+  computed: {
+    // 倒计时按钮文字
+    countdownText() {
+      if (this.bindPhone.sendCodeLoading) {
+        return '发送中...';
+      }
+      if (this.bindPhone.isCountingDown) {
+        return `${this.bindPhone.countdown}s后重发`;
+      }
+      return '发送验证码';
+    }
+  },
+  // 页面销毁时清除定时器
+  beforeDestroy() {
+    this.clearCountdown();
+  },
   created() {
     this.getList();
     this.getDicts("sys_user_status").then(response => {
@@ -321,6 +398,74 @@ export default {
       this.single = selection.length!==1
       this.multiple = !selection.length
     },
+    /** 开始倒计时 */
+    startCountdown(seconds) {
+      this.bindPhone.countdown = seconds;
+      this.bindPhone.isCountingDown = true;
+
+      this.clearCountdown();
+      this.bindPhone.countdownTimer = setInterval(() => {
+        this.bindPhone.countdown--;
+        if (this.bindPhone.countdown <= 0) {
+          this.clearCountdown();
+        }
+      }, 1000);
+    },
+
+    /** 清除倒计时 */
+    clearCountdown() {
+      if (this.bindPhone.countdownTimer) {
+        clearInterval(this.bindPhone.countdownTimer);
+        this.bindPhone.countdownTimer = null;
+      }
+      if (this.bindPhone.countdown <= 0) {
+        this.bindPhone.isCountingDown = false;
+        this.bindPhone.countdown = 0;
+      }
+    },
+    /** 发送验证码 */
+    sendCode(){
+      const phone = this.bindPhoneForm.phone
+      if (phone === null || phone === "") {
+        this.$message.error("请输入正确手机号");
+      }
+      console.log("-----------------",phone);
+      // 60秒内不能重复点击(倒计时 > 120 时禁止,即180-60=120)
+      if (this.bindPhone.countdown > 120) {
+        this.$message.warning(`请${this.bindPhone.countdown - 120}秒后再试`);
+        return;
+      }
+
+      // 表单验证
+      this.$refs.bindPhoneForm.validateField('phone', (errorMessage) => {
+        if (errorMessage) {
+          return;
+        }
+
+        const phone = this.bindPhoneForm.phone;
+        this.sendCodeLoading = true;
+
+        sendCode(phone).then(response => {
+          this.sendCodeLoading = false;
+          if (response.code === 200) {
+            this.$message.success('验证码已发送,有效期180秒');
+            // 开始180秒倒计时
+            this.startCountdown(180);
+          } else {
+            this.$message.error(response.msg || '发送失败');
+          }
+        }).catch(() => {
+          this.sendCodeLoading = false;
+        });
+      });
+    },
+    /** 绑定手机按钮操作 */
+    handleBindPhone(row){
+      this.bindPhoneForm.nickName = row.nickName;
+      this.bindPhoneForm.userId = row.userId;
+      this.bindPhone.title = "绑定用户手机";
+      this.bindPhone.open = true;
+    },
     /** 新增按钮操作 */
     handleNickName(row) {
       this.reset();
@@ -340,6 +485,19 @@ export default {
         this.form.status = String(this.form.status)
       });
     },
+    submitBindPhoneForm(){
+      this.$refs["bindPhoneForm"].validate(valid => {
+        if (valid) {
+          bindPhone(this.bindPhoneForm).then(response => {
+            this.msgSuccess("绑定成功");
+            this.bindPhone.open = false;
+            this.clearCountdown();
+            this.bindPhone.open = false;
+            this.getList();
+            });
+          }
+      });
+    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {

+ 160 - 2
src/views/store/user/myList.vue

@@ -84,7 +84,7 @@
     <el-table v-loading="loading" border :data="userList" @selection-change="handleSelectionChange" >
       <el-table-column type="selection" width="55" align="center" />
 
-      <el-table-column label="用户昵称" align="center" prop="nickname" width="150px"/>
+      <el-table-column label="用户昵称" align="center" prop="nickName" width="150px"/>
       <el-table-column label="用户头像" align="center" prop="avatar" >
          <template slot-scope="scope">
                  <el-image v-if="scope.row.avatar!=null"
@@ -115,6 +115,12 @@
             type="text"
             @click="handleNickName(scope.row)"
           >修改昵称</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-if="scope.row.phone==null || scope.row.phone==''"
+            @click="handleBindPhone(scope.row)"
+          >绑定手机号</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -160,18 +166,73 @@
          <userDetails  ref="userDetails" />
        </el-drawer>
 
+    <!-- 绑定用户手机号 -->
+    <el-dialog :title="bindPhone.title" :visible.sync="bindPhone.open" width="500px" append-to-body>
+      <el-form ref="bindPhoneForm" :model="bindPhoneForm"  :rules="bindRules" label-width="80px">
+        <el-form-item label="用户昵称" prop="nickName" label-width="100px">
+          <el-input v-model="bindPhoneForm.nickName" placeholder="请输入用户昵称" :disabled="true"/>
+        </el-form-item>
+        <el-form-item label="用户手机号" prop="phone" label-width="100px">
+          <el-input v-model="bindPhoneForm.phone" placeholder="请输入用户手机号">
+            <el-button
+              slot="append"
+              @click="sendCode"
+              :disabled="bindPhone.isCountingDown || bindPhone.countdown > 120"
+              :loading="bindPhone.sendCodeLoading"
+            >
+              {{ countdownText }}
+            </el-button>
+          </el-input>
+        </el-form-item>
+        <el-form-item label="验证码" prop="code" label-width="100px">
+          <el-input v-model="bindPhoneForm.code" placeholder="请输入验证码"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitBindPhoneForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
 
   </div>
 </template>
 
 <script>
-import { myListUser, getUser, delUser, addUser, updateUser, myExportUser } from "@/api/store/user";
+import { myListUser, getUser, delUser, addUser, updateUser, myExportUser,sendCode,bindPhone } from "@/api/store/user";
 import userDetails from '../components/userDetails.vue';
 export default {
   name: "User",
   components: {userDetails},
   data() {
     return {
+      orOptions:[],
+      bindRules: {
+        phone: [
+          { required: true, message: '请输入手机号', trigger: 'blur' },
+          { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
+        ],
+        code: [
+          { required: true, message: '请输入验证码', trigger: 'blur' }
+        ]
+      },
+      bindPhoneForm:{
+        nickName: '',
+        userId: null,
+        phone: '',
+        code: ''
+      },
+      bindPhone:{
+        // 弹出层标题
+        title: "",
+        // 是否显示弹出层
+        open: false,
+        // 发送验证码相关
+        countdown: 0,           // 当前倒计时秒数
+        isCountingDown: false,  // 是否正在倒计时
+        sendCodeLoading: false, // 发送中loading
+        countdownTimer: null,   // 定时器引用
+      },
       show:{
               title:"用户详情",
               open:false,
@@ -238,6 +299,22 @@ export default {
       }
     };
   },
+  computed: {
+    // 倒计时按钮文字
+    countdownText() {
+      if (this.bindPhone.sendCodeLoading) {
+        return '发送中...';
+      }
+      if (this.bindPhone.isCountingDown) {
+        return `${this.bindPhone.countdown}s后重发`;
+      }
+      return '发送验证码';
+    }
+  },
+  // 页面销毁时清除定时器
+  beforeDestroy() {
+    this.clearCountdown();
+  },
   created() {
     this.getList();
     this.getDicts("sys_user_status").then(response => {
@@ -251,6 +328,87 @@ export default {
     });
   },
   methods: {
+    /** 开始倒计时 */
+    startCountdown(seconds) {
+      this.bindPhone.countdown = seconds;
+      this.bindPhone.isCountingDown = true;
+
+      this.clearCountdown();
+      this.bindPhone.countdownTimer = setInterval(() => {
+        this.bindPhone.countdown--;
+        if (this.bindPhone.countdown <= 0) {
+          this.clearCountdown();
+        }
+      }, 1000);
+    },
+
+    /** 清除倒计时 */
+    clearCountdown() {
+      if (this.bindPhone.countdownTimer) {
+        clearInterval(this.bindPhone.countdownTimer);
+        this.bindPhone.countdownTimer = null;
+      }
+      if (this.bindPhone.countdown <= 0) {
+        this.bindPhone.isCountingDown = false;
+        this.bindPhone.countdown = 0;
+      }
+    },
+    /** 发送验证码 */
+    sendCode(){
+      const phone = this.bindPhoneForm.phone
+      if (phone === null || phone === "") {
+        this.$message.error("请输入正确手机号");
+      }
+      console.log("-----------------",phone);
+      // 60秒内不能重复点击(倒计时 > 120 时禁止,即180-60=120)
+      if (this.bindPhone.countdown > 120) {
+        this.$message.warning(`请${this.bindPhone.countdown - 120}秒后再试`);
+        return;
+      }
+
+      // 表单验证
+      this.$refs.bindPhoneForm.validateField('phone', (errorMessage) => {
+        if (errorMessage) {
+          return;
+        }
+
+        const phone = this.bindPhoneForm.phone;
+        this.sendCodeLoading = true;
+
+        sendCode(phone).then(response => {
+          this.sendCodeLoading = false;
+          if (response.code === 200) {
+            this.$message.success('验证码已发送,有效期180秒');
+            // 开始180秒倒计时
+            this.startCountdown(180);
+          } else {
+            this.$message.error(response.msg || '发送失败');
+          }
+        }).catch(() => {
+          this.sendCodeLoading = false;
+        });
+      });
+    },
+    /** 绑定手机按钮操作 */
+    handleBindPhone(row){
+      this.bindPhoneForm.nickName = row.nickName;
+      this.bindPhoneForm.userId = row.userId;
+      this.bindPhone.title = "绑定用户手机";
+      this.bindPhone.open = true;
+    },
+    submitBindPhoneForm(){
+      this.$refs["bindPhoneForm"].validate(valid => {
+        if (valid) {
+          bindPhone(this.bindPhoneForm).then(response => {
+            this.msgSuccess("绑定成功");
+            this.bindPhone.open = false;
+            this.clearCountdown();
+            this.bindPhone.open = false;
+            this.getList();
+          });
+        }
+      });
+    },
     change(){
           if(this.createTime!=null){
             this.queryParams.sTime=this.createTime[0];