Browse Source

1.管理端增加微信绑定及登录功能。
2.企业端增加微信绑定及登录功能。

tomatozq 5 years ago
parent
commit
f20569641d

+ 25 - 1
src/api/sys/user.js

@@ -55,6 +55,30 @@ function userInfo() {
   return request.get(constant.serverUrl + "/userInfo");
 }
 
+
+function getLoginQrcode(loginCode){
+	return request.get(constant.serverUrl + `/pub/qrcode/login/create?loginCode=${loginCode}`);
+}
+
+function queryWXLoginStatus(loginCode){
+	return request.get(constant.serverUrl + `/pub/qrcode/login/loop?loginCode=${loginCode}`);
+}
+
+function getBindingQrcode() {
+	return request.get(constant.serverUrl + `/qrcode/binding/create`);
+}
+
+function scanQrcodeLogin(data) {
+  var formData = new FormData();
+
+  for (var key in data) {
+    formData.append(key, data[key]);
+  }
+
+  return request.post(constant.serverUrl + '/pub/qrcode/login', formData);
+}
+
 export default {
-  login, pageList, create, edit, add, update, remove, batchRemove, userInfo
+  login, pageList, create, edit, add, update, remove, batchRemove, userInfo,
+  getLoginQrcode,queryWXLoginStatus,getBindingQrcode,scanQrcodeLogin
 }

+ 29 - 0
src/assets/iconfont/iconfont.css

@@ -0,0 +1,29 @@
+@font-face {font-family: "iconfont";
+  src: url('iconfont.eot?t=1582177544808'); /* IE9 */
+  src: url('iconfont.eot?t=1582177544808#iefix') format('embedded-opentype'), /* IE6-IE8 */
+  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAMkAAsAAAAABvgAAALXAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAqCBIIDATYCJAMICwYABCAFhG0HMBspBsgOJUHy2IBhBgVgBPX7oXvvvxCASzwACgcFxba2KroSyLgaU5Z1merq/3/7/bq4Jw6TwL82TPy+Lz5vELeonvAm2nwttE17NmPA5fRblMg8oBzX3rawwOKAAhpjWLSFC6TAuGHsJoIHeJxArUGBjNbjU3PBUgbGBeKxQlYFlgWd3FEcqoXKhqV5x2iSmer0Oj0DuOOfj38giWqSigIoO76Oq4XI+wWYVrwqO5VSAn85C5xVFJgHMnHeaDtkImPzTNRGMVOj4FjFwb20/Ka8w/7xCKISKKwH/TrvmfhY8Ki/TCCjElfAk0lhKmvqYNcBZ1XXzvBp59nILoo06+Evnds2brPi6tT8Devhb6/Q6blmPfzJ23senZhb8B5dPz9sRr6/Yedrbl7+a+3wj/fo7ORGj0tRWVCp6GLLyvHeo+nN0JKDx32/pIFQ0j/dX+v+ufDPyb1quaB0rijoQdzm8La1R197c5fo27rOr1Vql6/L9HiS0tBbMx2T1hgt9pIZwvNcfSpXMkqH1gzPSmZlKV4xDJEA5WqeKcr+93f0/k9/KxxC/1fXZfCHhVtywTAHqL4re/B3K/I0KL/zjCsE0ZTRwTNSyRXzu5bWxk4lAFerP1NVHa9iCdUFvoOkygAK1cZJmTaPCnUWUanaEmrNSVhdpw1lInINZvVpCM0OkTT6ikKzF1Km/UaFTn9RqTkK1LoMly3rTMYD6xiKVQxrSXUTUdTotBwyMmtRnI2yOnUVzQs5Ix8prwgSsUBUTiagFukSM/h6mYQxjnBUpyHx2mmoVuuInuqUWMMEcsb0wUIh13QlQY1OA9bWUKgKg2oR1ZoQCjV0tDjamrGuvD8bkqmjVoV21I248yGKp+icEBMQDSAlyLSD6h7lEl49GQmG4RAcSkeDiNcsSA1jOoS+eZASqsEIyCdE9IIJjUbcUJlge4Xm77ZBLaBOAfsVKl+iolGhBQAA') format('woff2'),
+  url('iconfont.woff?t=1582177544808') format('woff'),
+  url('iconfont.ttf?t=1582177544808') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
+  url('iconfont.svg?t=1582177544808#iconfont') format('svg'); /* iOS 4.1- */
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-weixin:before {
+  content: "\e933";
+}
+
+.el-menu .iconfont{
+  vertical-align: middle;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 24px;
+  text-align: center;
+  font-size: 18px;
+}

BIN
src/assets/iconfont/iconfont.eot


File diff suppressed because it is too large
+ 0 - 0
src/assets/iconfont/iconfont.js


+ 16 - 0
src/assets/iconfont/iconfont.json

@@ -0,0 +1,16 @@
+{
+  "id": "1648001",
+  "name": "picc",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "",
+  "glyphs": [
+    {
+      "icon_id": "7736497",
+      "name": "weixin",
+      "font_class": "weixin",
+      "unicode": "e933",
+      "unicode_decimal": 59699
+    }
+  ]
+}

+ 29 - 0
src/assets/iconfont/iconfont.svg

@@ -0,0 +1,29 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<!--
+2013-9-30: Created.
+-->
+<svg>
+<metadata>
+Created by iconfont
+</metadata>
+<defs>
+
+<font id="iconfont" horiz-adv-x="1024" >
+  <font-face
+    font-family="iconfont"
+    font-weight="500"
+    font-stretch="normal"
+    units-per-em="1024"
+    ascent="896"
+    descent="-128"
+  />
+    <missing-glyph />
+    
+    <glyph glyph-name="weixin" unicode="&#59699;" d="M331.428571 632.571429q0 23.428571-14.285714 37.714285t-37.714286 14.285715q-24.571429 0-43.428571-14.571429T217.142857 632.571429q0-22.285714 18.857143-36.857143t43.428571-14.571429q23.428571 0 37.714286 14t14.285714 37.428572z m424.571429-289.714286q0 16-14.571429 28.571428t-37.428571 12.571429q-15.428571 0-28.285714-12.857143T662.857143 342.857143q0-16 12.857143-28.857143t28.285714-12.857143q22.857143 0 37.428571 12.571429t14.571429 29.142857zM621.142857 632.571429q0 23.428571-14 37.714285T569.714286 684.571429q-24.571429 0-43.428572-14.571429T507.428571 632.571429q0-22.285714 18.857143-36.857143t43.428572-14.571429q23.428571 0 37.428571 14T621.142857 632.571429z m362.857143-289.714286q0 16-14.857143 28.571428t-37.142857 12.571429q-15.428571 0-28.285714-12.857143T890.857143 342.857143q0-16 12.857143-28.857143t28.285714-12.857143q22.285714 0 37.142857 12.571429t14.857143 29.142857z m-152 226.857143q-17.714286 2.285714-40 2.285714-96.571429 0-177.714286-44T486.571429 408.857143 440 244.571429q0-44.571429 13.142857-86.857143-20-1.714286-38.857143-1.714286-14.857143 0-28.571428 0.857143t-31.428572 3.714286-25.428571 4-31.142857 6-28.571429 6L124.571429 104l41.142857 124.571429q-165.714286 116-165.714286 280 0 96.571429 55.714286 177.714285t150.857143 127.714286T414.285714 860.571429q100.571429 0 190-37.714286t149.714286-104.285714T832 569.714286z m338.285714-320.571429q0-66.857143-39.142857-127.714286T1025.142857 10.857143l31.428572-103.428572-113.714286 62.285715q-85.714286-21.142857-124.571429-21.142857-96.571429 0-177.714285 40.285714T512.857143 98.285714 466.285714 249.142857t46.571429 150.857143T640.571429 509.428571t177.714285 40.285715q92 0 173.142857-40.285715t130-109.714285T1170.285714 249.142857z"  horiz-adv-x="1170" />
+
+    
+
+
+  </font>
+</defs></svg>

BIN
src/assets/iconfont/iconfont.ttf


BIN
src/assets/iconfont/iconfont.woff


BIN
src/assets/iconfont/iconfont.woff2


BIN
src/assets/wx.png


+ 1 - 0
src/main.js

@@ -4,6 +4,7 @@ import router from './routers'
 import store from './store'
 import './plugins/element.js'
 import AxiosPlugin from './plugins/AxiosPlugin'
+import './assets/iconfont/iconfont.css'
 
 Vue.config.productionTip = false
 Vue.use(AxiosPlugin)

+ 11 - 0
src/routers/modules/sys.js

@@ -50,6 +50,17 @@ var routers = [
                 // this generates a separate chunk (about.[hash].js) for this route
                 // which is lazy-loaded when the route is visited.
                 component: () => import('@/views/sys/dataDictionary-list.vue'),
+                meta: {
+                roles: ["admin"]
+                }
+        },
+        {
+                path: '/sys/user/bindwx',
+                name: 'sys-user-bindwx',
+                // route level code-splitting
+                // this generates a separate chunk (about.[hash].js) for this route
+                // which is lazy-loaded when the route is visited.
+                component: () => import('@/views/sys/user-bindwx.vue'),
                 meta: {
                         roles: ["admin"]
                 }

+ 11 - 10
src/styles/mixin.scss

@@ -6,15 +6,16 @@
 }
 
 @mixin clearfix {
-    &:after {
-      content: "";
-      display: table;
-      clear: both;
-    }
+  &:after {
+    content: "";
+    display: table;
+    clear: both;
   }
+}
+
+@mixin relative {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
 
-  @mixin relative {
-    position: relative;
-    width: 100%;
-    height: 100%;
-  }

+ 110 - 18
src/views/Login.vue

@@ -36,20 +36,41 @@
             />
             <i class="el-icon-view" @click="showPwd"></i>
           </el-form-item>
-          <el-button
-            type="primary"
-            style="width:100%;margin-bottom:30px;"
-            :loading="loading"
-            @click.native.prevent="handleLogin"
-          >登录</el-button>
+          <el-row>
+            <el-col :span="3">
+              <a style="cursor:pointer;">
+								<img src="../assets/wx.png" width="32" @click="wxLogin"/>
+							</a>
+            </el-col>
+            <el-col :span="21">
+              <el-button
+                type="primary"
+                style="width:100%;margin-bottom:30px;"
+                :loading="loading"
+                @click.native.prevent="handleLogin"
+              >登录</el-button>
+            </el-col>
+          </el-row>
         </el-form>
       </el-card>
     </div>
+    
+		<el-dialog
+			title="微信扫码登录"
+			:modal-append-to-body="false"
+			width="30%"
+			:visible.sync="wxDialogVisible">
+			<div v-loading="wxLoading">
+				<img :src="wxLoginQrcode" width="100%" height="auto"/>
+			</div>
+		</el-dialog>
   </div>
 </template>
 <script>
 import Constant from "@/constant";
 import { Message } from "element-ui";
+import userApi from '@/api/sys/user';
+import {setToken} from '@/utils/auth'
 
 export default {
   name: "login",
@@ -57,7 +78,8 @@ export default {
     return {
       loginForm: {
         userName: "",
-        password: ""
+        password: "",
+        openId: ""
       },
       loginRules: {
         userName: [
@@ -75,7 +97,12 @@ export default {
       },
       pwdType: "password",
       loading: false,
-      redirect: undefined
+      redirect: undefined,
+      wxDialogVisible: false,
+      wxLoading: false,
+      wxLoginQrcode: '',
+      wxQueryHandler: 0,
+      loginCode: Math.random().toFixed(6)*1000000
     };
   },
   watch: {
@@ -107,25 +134,90 @@ export default {
           self.$store
             .dispatch("user/login", self.loginForm)
             .then(() => {
-              self.$router.push({ path: this.redirect || "/home" });
               self.loading = false;
+              self.$message.success("登录成功!");
+              
+              self.$router.push({ path: this.redirect || "/home" });
             })
             .catch(error => {
               self.loading = false;
-              // self.$message.error(error || 'Has Error')
-
               self.$message.error(error);
-
-              // self.$notify({
-              //   title: "系统提示",
-              //   message: error || "Has Error",
-              //   type: "warning"
-              // });
             });
         }
       });
     },
-    afterQRScan() {}
+    wxLogin() {
+      var self = this;
+
+				self.wxDialogVisible = true;
+
+				self.wxLoading = true;
+
+				userApi.getLoginQrcode(self.loginCode).then((resp)=>{
+					var jsonData = resp.data;
+
+					self.wxLoading = false;
+
+					if(jsonData!=null){
+						if(jsonData.result) {
+							self.wxLoginQrcode = jsonData.data;
+							clearTimeout(self.wxQueryHandler);
+
+							self.queryWXLoginStatus();
+						}
+					}
+					else{
+						self.$message.error("获取二维码失败!");
+					}
+				});
+    },
+    queryWXLoginStatus() {
+      var self = this;
+      
+      userApi.queryWXLoginStatus(self.loginCode).then((resp)=>{
+        var jsonData = resp.data;
+        console.log(jsonData);
+
+        if(jsonData.data!=null && jsonData.data.length>0) {
+          var openId = jsonData.data;
+
+          self.loginForm.openId = openId;
+
+          self.loading = true;
+
+          self.scanQrcodeLogin();
+        }
+        else {
+          self.wxQueryHandler = setTimeout(self.queryWXLoginStatus,3000);
+        }
+      });
+    },
+    scanQrcodeLogin() {
+      var self = this;
+
+      self.loading = true;
+
+      console.log(self.loginForm.openId);
+
+      userApi.scanQrcodeLogin({
+        openId : self.loginForm.openId
+      }).then(resp => {
+        self.loading = false;
+
+        var jsonData = resp.data;
+
+        if(jsonData.result){
+          self.$message.success("登录成功!");
+            
+          self.$store.commit('SET_TOKEN', jsonData.data);
+          setToken(jsonData.data);
+          self.$router.push({ path: self.redirect || "/home" });
+        }
+        else{
+          Message.error(jsonData.message || 'Has Error')
+        }
+      })
+    }
   },
   created() {
     // window.addEventListener('hashchange', this.afterQRScan)

+ 1 - 1
src/views/sys/role-list.vue

@@ -80,7 +80,7 @@
         sortable="custom"
         width="180"
       ></el-table-column>
-      <el-table-column label="操作">
+      <el-table-column label="操作" width="350" fixed="right">
         <template slot-scope="{row}">
           <el-button size="mini" type="warn" @click="handleEdit(row)">编辑</el-button>
           <el-button size="mini" type="primary" @click="allocApiPerm(row)">分配接口</el-button>

+ 140 - 0
src/views/sys/user-bindwx.vue

@@ -0,0 +1,140 @@
+<template>
+	<div>
+		<el-breadcrumb separator=">">
+		<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
+		<el-breadcrumb-item>
+			<a href="#">微信绑定</a>
+		</el-breadcrumb-item>
+		</el-breadcrumb>
+		<el-divider></el-divider>
+		<div class="main-body bindwxbody">
+			<el-card class="box-card" style="color:#909399">
+				<div style="margin:5px 0;">说明</div>
+				• 此功能是为了帮助业务员更及时的收到待办事项提醒,通过公众号推送消息形式提醒业务员及时处理待办事项。
+			</el-card>
+			<div class="bindwxstep">
+				<div class="step">
+					<div class="title">
+						<el-tag size="small">第一步</el-tag>打开微信【扫一扫】,扫描下方二维码
+					</div>
+					<div class="img" v-loading="loading">
+						<img :src="bindingQrcode" width="200" height="200" />
+					</div>
+				</div>
+
+				<div class="step">
+					<div class="title">
+						<el-tag size="small">第二步</el-tag>在微信中点击“确认绑定”按钮
+					</div>
+				</div>
+
+				<div class="step">
+					<div class="title">
+						<el-tag size="small">第三步</el-tag>完成绑定,我们会将待办事项提醒通过“荆州人才超市”公众号推送给您。
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+<script>
+	import userApi from '@/api/sys/user';
+
+	export default {
+		data() {
+			return {
+				loading: false,
+				bindingQrcode: ''
+			}
+		},
+		mounted() {
+			this.loading = true;
+			
+			userApi.getBindingQrcode().then(resp=>{
+				var jsonData = resp.data;
+
+				if(jsonData!=null && jsonData.result){
+					this.loading = false;
+					this.bindingQrcode = jsonData.data;
+				}
+			});
+		},
+		methods: {
+			//页面标签切换
+			handleClick(tab, event) {
+				console.log(tab, event);
+				this.$router.push({
+					name: tab.name
+				})
+			},
+			//表单提交
+			submitForm(formName) {
+				this.$refs[formName].validate((valid) => {
+					if (valid) {
+						alert('submit!');
+					} else {
+						console.log('error submit!!');
+						return false;
+					}
+				});
+			},
+			//重置表单
+			resetForm(formName) {
+				this.$refs[formName].resetFields();
+			},
+
+			//图片上传
+			handleAvatarSuccess(res, file) {
+				this.imageUrl = URL.createObjectURL(file.raw);
+			},
+			beforeAvatarUpload(file) {
+				const isJPG = file.type === 'image/jpeg';
+				const isLt2M = file.size / 1024 / 1024 < 2;
+
+				if (!isJPG) {
+					this.$message.error('上传头像图片只能是 JPG 格式!');
+				}
+				if (!isLt2M) {
+					this.$message.error('上传头像图片大小不能超过 2MB!');
+				}
+				return isJPG && isLt2M;
+			}
+
+		},
+		computed: {}
+	}
+</script>
+<style lang="scss" scoped="scoped">
+	@import "@/styles/mixin.scss";
+
+	.el-breadcrumb {
+		margin: 10px;
+		line-height: 20px;
+	}
+
+	.el-divider {
+		margin: 5px 0;
+	}
+
+	.bindwxbody {
+		text-align: left;
+		@include clearfix;
+	}
+
+
+	.bindwxstep {
+		margin: 30px 0 0 20px;
+	}
+
+	.step {
+		margin: 10px 0;
+	}
+
+	.step .title {
+		margin: 5px 0;
+	}
+
+	.img{
+		text-align: left;
+	}
+</style>

Some files were not shown because too many files changed in this diff