微信企业号在线客服
需求
因企微信企业号后台暂时只提供,历史消息模块,无法适用客服模式,很难及时反馈用户提问的消息,基于企业微信二次开发客服系统,可实现消息实时触达,多客服,知识库等功能
1.新建项目wechatWork
2.python 安装wechatpy
官方文档:https://wechatpy.readthedocs.io/zh_CN/master/
pip install wechatpy # with cryptography (推荐) pip install wechatpy[cryptography] # with pycryptodome pip install wechatpy[pycrypto]
3.企业号后台设置消息http接口
4.设计model.py 应用管理表 客服用户管理表
from django.contrib.auth.models import User from django.db import models from django.utils.crypto import random # Create your models here. from django.utils.html import format_html def rename(newname): def decorator(fn): fn.__name__ = newname return fn return decorator # 客服人员 class KF(models.Model): agent = models.ForeignKey(\'agent\', null=True, to_field="id", on_delete=models.CASCADE, verbose_name="应用名称") username = models.CharField(max_length=225, verbose_name="姓名", blank=True, default="") userid = models.CharField(max_length=225, verbose_name="UM", blank=True, default="") status = models.BooleanField(verbose_name="是否在线") avatar = models.URLField(max_length=225, verbose_name="头像", blank=True, default="") createTime = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") lastTime = models.DateTimeField(auto_now=True, verbose_name="修改时间") author = models.CharField(max_length=64, verbose_name="创建者", blank=True, default="") editor = models.ForeignKey(User, null=True, on_delete=models.CASCADE, verbose_name="修改者") class Meta: verbose_name_plural = "在线客服" ordering = [\'id\'] @rename("头像") def showAvatar(self): return format_html("<img src=\'{}\' class=\'showAvatar\'", self.avatar) def __str__(self): return self.username # 行内员工 def randomSign(): switch = { 0: "只要还有明天,今天就永远是起跑线。", 1: "只要还有明天,今天就永远是起跑线。", 2: "只要还有明天,今天就永远是起跑线。" } return switch[random.randint(0, len(switch) - 1)] class userList(models.Model): username = models.CharField(max_length=225, verbose_name="姓名", blank=True, default="") userid = models.CharField(max_length=225, verbose_name="UM", blank=True, default="") avatar = models.URLField(max_length=225, verbose_name="头像", blank=True, default="") sign = models.CharField(max_length=225, verbose_name="个性签名", blank=True, default=randomSign) agent = models.ForeignKey(\'agent\', null=True, to_field="id", on_delete=models.CASCADE, verbose_name="应用名称") createTime = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") lastTime = models.DateTimeField(auto_now=True, verbose_name="修改时间") author = models.CharField(max_length=64, verbose_name="创建者", default="weChat") editor = models.ForeignKey(User, null=True, on_delete=models.CASCADE, verbose_name="修改者") @rename("头像") def showAvatar(self): return format_html("<img src=\'{}\' class=\'showAvatar\'", self.avatar) class Meta: verbose_name_plural = "用户列表" ordering = [\'id\'] def __str__(self): return self.username # 接受的消息 class Message(models.Model): ToUserName = models.CharField(max_length=225, verbose_name="企业号ID", blank=True, default="") FromUserName = models.CharField(max_length=225, verbose_name="发送者", blank=True, default="") CreateTime = models.DateTimeField(verbose_name="发送时间", blank=True, default=None) MsgId = models.CharField(max_length=225, verbose_name="消息ID", blank=True, default="") AgentID = models.CharField(max_length=225, verbose_name="应用ID", blank=True, default="") MsgType = models.CharField(max_length=225, verbose_name="消息类型", blank=True, default="") content = models.TextField(max_length=2000, verbose_name="消息内容", blank=True, default="") userList = models.ForeignKey(\'userList\', null=True, to_field="id", on_delete=models.CASCADE) class Meta: verbose_name_plural = "所有消息" ordering = [\'id\'] def __str__(self): return self.FromUserName
# 企业号应用管理,支持多个应用接入客服系统 class agent(models.Model): name = models.CharField(max_length=225, verbose_name="应用名称", blank=True, default="") agentid = models.CharField(max_length=225, verbose_name="应用ID", blank=True, default="") secret = models.CharField(max_length=225, verbose_name="应用密钥", blank=True, default="") avatar = models.URLField(max_length=225, verbose_name="部门Logo", blank=True, default="") welcomeText = models.TextField(max_length=2000, verbose_name="欢迎语", blank=True, default="") firstText = models.TextField(max_length=2000, verbose_name="会话提示语", blank=True, default="您好,很高兴为您服务!") conversationTime = models.IntegerField(verbose_name="会话时长(分钟)", default=20) notuserText = models.TextField(max_length=2000, verbose_name="客服不在线提示语", blank=True, default="非常抱歉,客服处于离线状态,您的消息我们已发送IT服务台,马上会有IT同事跟进处理!") webhook_url = models.URLField(verbose_name="群机器人地址", default="") createTime = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") lastTime = models.DateTimeField(auto_now=True, verbose_name="修改时间") author = models.CharField(max_length=64, verbose_name="创建者") editor = models.ForeignKey(User, null=True, on_delete=models.CASCADE, verbose_name="修改者") @rename("部门Logo") def showAvatar(self): return format_html("<img src=\'{}\' class=\'showAvatar\'", self.avatar) @rename("详情") def checkMessage(self): return format_html("<a href=\'/work/index/{}.html\' target=\'blank\'>回复</a>", self.id) class Meta: verbose_name_plural = "应用管理" ordering = [\'id\'] def __str__(self): return self.name # 客服知识库 class knowledgeBase(models.Model): questionType = models.CharField(max_length=225, verbose_name="问题类型", blank=True, default="") key = models.CharField(max_length=225, verbose_name="关键字", blank=True, default="") rule = models.IntegerField(choices=((0, \'包含\'), (1, \'完全匹配\')), default=0, verbose_name=\'规则\') answerType = models.IntegerField(choices=((0, \'文字\'), (1, \'图文\'), (2, \'图片\'), (3, \'语音\'), (4, \'视频\')), default=0, verbose_name=\'发送类型\') content = models.TextField(max_length=2000, verbose_name="消息内容", blank=True, default="") createTime = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") lastTime = models.DateTimeField(auto_now=True, verbose_name="修改时间") author = models.CharField(max_length=64, verbose_name="创建者") editor = models.ForeignKey(User, null=True, on_delete=models.CASCADE, verbose_name="修改者") class Meta: verbose_name_plural = "知识库" ordering = [\'id\'] def __str__(self): return self.name
5.admin.py 代码
from django.contrib import admin # Register your models here. from import_export import resources from import_export.admin import ImportExportModelAdmin from wechatpy.enterprise import WeChatClient from wechatpy.enterprise.crypto import WeChatCrypto from wechatpy.exceptions import InvalidSignatureException import weChatWork as config from work.models import * admin.site.site_title = "企业号后台管理" admin.site.site_header = "企业号后台管理" # 企业号ID corpid = config.settings.weChatWork["corpid"] class agentResource(resources.ModelResource): def get_export_headers(self): # 是你想要的导出头部标题headers return [\'应用名称\', \'欢迎语\', \'会话提示语\', \'部门Logo\', \'创建时间\', \'修改时间\', \'创建者\', \'修改者\'] class Meta: field = (\'name\', \'welcomeText\', \'firstText\', \'avatar\', \'createTime\', \'lastTime\', \'author\', \'editor\') model = agent fields = field export_order = field @admin.register(agent) class agentAdmin(ImportExportModelAdmin): fields = (\'agentid\', \'secret\', \'welcomeText\', \'firstText\', \'notuserText\', \'webhook_url\', \'conversationTime\') # 需要显示的字段信息 list_display = (\'showAvatar\', \'name\', \'welcomeText\', \'firstText\', \'notuserText\', \'webhook_url\', \'conversationTime\', \'createTime\', \'lastTime\', \'author\', \'editor\', \'checkMessage\') exclude = (\'avatar\', \'author\', \'editor\') # 设置哪些字段可以点击进入编辑界面,默认是第一个字段 list_display_links = (\'showAvatar\', \'name\') model_icon = "fa fa-tag" list_per_page = 10 resource_class = agentResource def save_model(self, request, obj, form, change): if form.is_valid(): if not change: obj.author = request.user.username obj.editor = request.user client = WeChatClient(corpid, obj.secret) agent = client.agent.get(obj.agentid) obj.name = agent["name"] obj.avatar = agent["square_logo_url"] print(agent) obj.save() super().save_model(request, obj, form, change) class KFResource(resources.ModelResource): def get_export_headers(self): # 是你想要的导出头部标题headers return [\'姓名\', \'UM\', \'头像\'] class Meta: field = (\'username\', \'userid\', \'sign\', \'avatar\',) model = KF fields = field export_order = field @admin.register(KF) class KFAdmin(ImportExportModelAdmin): fields = ("agent", \'userid\',) # 需要显示的字段信息 list_display = ( \'id\', "agent", "showAvatar", \'username\', \'userid\', \'status\', \'createTime\', \'lastTime\', \'author\', \'editor\') exclude = (\'username\', \'status\', \'avatar\', \'author\', \'editor\') # 设置哪些字段可以点击进入编辑界面,默认是第一个字段 list_display_links = (\'id\', \'username\') model_icon = "fa fa-tag" list_per_page = 10 resource_class = KFResource def save_model(self, request, obj, form, change): if form.is_valid(): if not change: obj.author = request.user.username obj.userid = obj.userid.upper() obj.editor = request.user obj.status = False agentInfo = agent.objects.filter(agentid=obj.agent.agentid).first() client = WeChatClient(corpid, agentInfo.secret) user = client.user.get(obj.userid) obj.username = user["name"] obj.avatar = user["avatar"] obj.save() super().save_model(request, obj, form, change) class userListResource(resources.ModelResource): def get_export_headers(self): # 是你想要的导出头部标题headers return [\'姓名\', \'UM\', \'头像\'] class Meta: field = (\'username\', \'userid\', \'avatar\', \'createTime\', \'lastTime\', \'author\', \'editor\') model = userList fields = field export_order = field @admin.register(userList) class userListAdmin(ImportExportModelAdmin): fields = () # 需要显示的字段信息 list_display = (\'id\', \'agent\', \'showAvatar\', \'username\', \'userid\', \'createTime\', \'lastTime\', \'author\', \'editor\') # 设置哪些字段可以点击进入编辑界面,默认是第一个字段 list_display_links = (\'id\', \'username\') search_fields = (\'username\', \'userid\') model_icon = "fa fa-tag" list_per_page = 50 resource_class = userListResource def save_model(self, request, obj, form, change): if form.is_valid(): obj.editor = request.user obj.save() super().save_model(request, obj, form, change) class MessageResource(resources.ModelResource): def get_export_headers(self): # 是你想要的导出头部标题headers return [\'企业号ID\', \'发送者\', \'发送时间\', \'消息ID\', \'应用ID\', \'消息类型\', \'消息内容\'] class Meta: field = (\'FromUserName\', \'CreateTime\', \'MsgId\', \'AgentID\', \'MsgType\', \'content\') model = Message fields = field export_order = field # Register your models here. @admin.register(Message) class MessageAdmin(ImportExportModelAdmin): fields = (\'FromUserName\', \'CreateTime\', \'MsgId\', \'AgentID\', \'MsgType\', \'content\') # 需要显示的字段信息 list_display = (\'id\', \'FromUserName\', \'CreateTime\', \'MsgId\', \'AgentID\', \'MsgType\', \'content\') # 设置哪些字段可以点击进入编辑界面,默认是第一个字段 list_display_links = (\'id\', \'FromUserName\') model_icon = "fa fa-tag" list_per_page = 10 resource_class = MessageResource class knowledgeBaseResource(resources.ModelResource): def get_export_headers(self): # 是你想要的导出头部标题headers return [\'问题类型\', \'关键字\', \'规则\', \'发送类型\', \'消息内容\', \'创建时间\', \'修改时间\', \'创建者\', \'修改者\'] class Meta: field = (\'questionType\', \'key\', \'rule\', \'answerType\', \'content\', \'createTime\', \'lastTime\', \'author\', \'editor\') model = knowledgeBase fields = field export_order = field # Register your models here. @admin.register(knowledgeBase) class knowledgeBaseAdmin(ImportExportModelAdmin): fields = (\'questionType\', \'key\', \'rule\', \'answerType\', \'content\') # 需要显示的字段信息 list_display = (\'id\', \'questionType\', \'key\', \'rule\', \'answerType\', \'content\') # 设置哪些字段可以点击进入编辑界面,默认是第一个字段 list_display_links = (\'id\', \'questionType\') model_icon = "fa fa-tag" list_per_page = 10 resource_class = knowledgeBaseResource
6.Channels的安装和使用(web socket 及时通讯)
Channels是针对 Django 项目的一个增强框架,它可以是的同步的 Django 项目转变为异步的项目。它可以使得 Django 项目不仅支持 HTTP 请求,还可以支持 Websocket, chat协议,IOT协议 ,甚至是你自定义的协议,同时也整合了 Django 的 auth 以及 session 系統等等
Channels 提供从 PYPI 直接pip下载安装
pip install -U channels==2.0.2 Django==2.0.4 channels_redis==2.1.1
参考文档:https://www.vimiix.com/post/63/?from=timeline&isappinstalled=0
7.liunx安装redis
windows 下安装redis: https://www.runoob.com/redis/redis-install.html
liunx 安装redis: https://blog.csdn.net/qq_39135287/article/details/83474865
8.接受微信API发送的消息
import wechatpy from django.contrib import auth from wechatpy.enterprise.client.api import WeChatOAuth from wechatpy.enterprise.exceptions import InvalidCorpIdException from wechatpy import enterprise, parse_message from django.shortcuts import render, redirect from django.http import JsonResponse, HttpResponse, HttpResponseRedirect from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import login_required from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User import uuid, datetime, json, time import weChatWork as config from django.utils.safestring import mark_safe from wechatpy.enterprise.crypto import WeChatCrypto from wechatpy.exceptions import InvalidSignatureException import os import urllib import work from work.models import * from django.core.cache import cache from wechatpy.enterprise import WeChatClient from wechatpy.session.redisstorage import RedisStorage from redis import Redis from urllib.parse import quote from comm import libary from django.utils.safestring import mark_safe import json import urllib3 corpid = config.settings.weChatWork["corpid"] sourceFile = config.settings.weChatWork["sourceFile"] soucketGroupName = config.settings.weChatWork["soucketGroupName"] # 群消息提问内容 def template_string(**kwargs): return """<font color="warning">新消息</font> > 姓名:{username} > UM:{um} > 发送内容:{content} > 点击查看:{url} """.format(**kwargs) # 查看请求信息 @login_required def requestInfo(request): result = request.environ.items() return render(request, \'requestInfo.html\', {\'rinfo\': result}) # 登录功能 def login(request): code = request.GET.get(\'code\', None) next = request.GET.get(\'next\', \'/\') agentid = request.GET.get(\'state\', "1000030") redirect_uri = quote(request.get_raw_uri(), \'utf-8\') agentInfo = agent.objects.filter(agentid=agentid).first() agentid = agentInfo.agentid secret = agentInfo.secret client = WeChatClient(corpid, secret) if libary.checkMobile(request): # 微信登录 url = client.oauth.authorize_url(redirect_uri, state=agentid) if code: try: user_info = client.oauth.get_user_info(code) if user_info["errcode"] != "0" and user_info["errmsg"] != "ok": return redirect("/static/error/500.html") registered(request, user_info["UserId"]) return redirect(next) except Exception as e: print(e.args) else: return redirect(url) else: # PC网站登录 url = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid={0}&agentid={1}&redirect_uri={2}&state={3}".format( corpid, agentid, redirect_uri, agentid) if code: try: print(client.access_token) user_info = client.user.get_info(agentid, code) if user_info["errcode"] != "0" and user_info["errmsg"] != "ok": return redirect("/static/error/500.html") UserId = user_info["UserId"].upper() registered(request, UserId) kfUser = KF.objects.filter(userid=UserId) kfUser.update(status=True) return redirect(next) except Exception as e: print(e.errmsg, e.errcode) # 这里需要处理请求里包含的 code 无效的情况 pass else: return redirect(url) # 注销 def logout(request): kfUser = KF.objects.filter(userid=request.user.username).first() kfUser.status = False kfUser.save() auth.logout(request) return redirect(\'/admin/login/\') # 注册 def registered(request, userid): user = User.objects.filter(username=userid).first() if not user: user = User.objects.create_user(username=userid, email=str(userid) + "@pingan.com.cn", password=uuid.uuid1(), is_staff=True, is_active=True) auth.login(request, user) return user # 403 未授权页面 def rorbidden(request): return redirect("/static/error/403.html") # Create your tests here. @login_required def index(request): method = request.method.upper() if method == "GET": return render(request, "work/index.html") elif method == "POST": UserId = request.user.username kfUser = KF.objects.filter(userid=UserId).first() kfUser.status = True kfUser.save() print(request.POST) Content = request.POST.get(\'mine[content]\') userid = request.POST.get(\'mine[id]\') FromUserName = request.POST.get(\'to[userid]\') agentInfo = kfUser.agent agentid = agentInfo.agentid secret = agentInfo.secret client = WeChatClient(corpid, secret) result = client.message.send_text(agentid, FromUserName, Content) print(result) return JsonResponse(result) @login_required def chatMobile(request): return render(request, "work/mobile.html") @login_required def GetUserList(request): loginUser = request.user.username user = KF.objects.filter(userid=loginUser).first() mine = {"username": user.username, "id": user.userid, "status": "online", "sign": "嘻哈哈", "avatar": user.avatar} ulist = list( work.models.userList.objects.filter(agent__agentid=user.agent.agentid).values("id", "username", "userid", "avatar", "sign")) friend = [{"groupname": "今天", "id": 1, "online": len(ulist), "list": ulist}, {"groupname": "前天", "id": 2, "online": 0, "list": []}, {"groupname": "三天前", "id": 4, "online": 0, "list": []}, {"groupname": "已回复", "id": 5, "online": 0, "list": []}, {"groupname": "未回复", "id": 6, "online": 0, "list": []}] return JsonResponse({\'code\': 0, \'msg\': "", "data": {"mine": mine, "friend": friend, "group": []}}) # 微信企业号 接收消息服务器配置 from django.views.decorators.csrf import csrf_exempt @csrf_exempt def weChatIndex(request): method = request.method.upper() TOKEN = "###" EncodingAESKey = "####" crypto = WeChatCrypto(TOKEN, EncodingAESKey, corpid) echostr = request.GET.get("echostr") signature = request.GET.get("msg_signature") timestamp = request.GET.get("timestamp") nonce = request.GET.get("nonce") if method == "GET": try: echo_str = crypto.check_signature(signature, timestamp, nonce, echostr) return HttpResponse(echo_str) except InvalidSignatureException: pass elif method == "POST": try: decrypted_xml = crypto.decrypt_message(request.body, signature, timestamp, nonce) except (InvalidSignatureException, InvalidCorpIdException): raise # 处理异常情况 else: msg = parse_message(decrypted_xml) MsgType = msg._data["MsgType"] ToUserName = msg._data["ToUserName"] FromUserName = msg._data["FromUserName"] CreateTime = msg._data["CreateTime"] tl = time.localtime(int(CreateTime)) cTime = time.strftime("%Y-%m-%d %H:%M:%S", tl) AgentID = msg._data["AgentID"] Message.objects.create(ToUserName=ToUserName, FromUserName=FromUserName, userList=userList.objects.filter(userid=FromUserName.upper()).first(), CreateTime=cTime, AgentID=AgentID, MsgType=MsgType, content=json.dumps(msg._data)) swm = switch_wechat_messages() swm.case_to_function(MsgType)(msg._data) return JsonResponse({"msg": "OK"}) def setWeChatRedis(data, Content): ToUserName = data["ToUserName"] FromUserName = data["FromUserName"] CreateTime = data["CreateTime"] MsgType = data["MsgType"] MsgId = data["MsgId"] AgentID = data["AgentID"] currentUser = createUser(FromUserName, AgentID) chatlog = [] print("currentUser=", currentUser) print("FromUserName=", FromUserName) chatInfo = {"AgentID": AgentID, "username": currentUser.username, "userid": FromUserName, "avatar": currentUser.avatar, "id": currentUser.id, "type": "friend", "content": Content, "timestamp": CreateTime, "mine": True, "MsgType": MsgType} # 查询当前应用信息 agentInfo = agent.objects.filter(agentid=AgentID).first() # 获得一个在线客服 currentKF = KF.objects.filter(agent__agentid=AgentID, status=True).order_by("lastTime").first() # 判断当前用户是否在线 if currentKF: # 判断会话是否过期 userStateKey = AgentID + "&" + FromUserName conversationTime = agentInfo.conversationTime * 60 # 首次会话自动推送欢迎语 kfuser = cache.get(userStateKey) print("kfuser=", kfuser) if not kfuser: cache.set(userStateKey, currentKF.userid.upper(), timeout=conversationTime) if agentInfo.firstText: client = WeChatClient(corpid, agentInfo.secret) client.message.send_text(AgentID, FromUserName, agentInfo.firstText) else: cache.set(userStateKey, kfuser, timeout=conversationTime) # 选择在线客服推送消息 完成 # 用户发送的消息 制定到客服 完成 # 客服离线 消息转发到其他在线客服 完成 (历史消息未完成) from work.consumers import sendContent message = sendContent(chatInfo) sendUser = currentKF.userid.upper() isLogin = KF.objects.filter(agent__agentid=AgentID, status=True, userid=kfuser).first() if isLogin: sendUser = kfuser else: currentKF.save() from channels.layers import get_channel_layer channel_layer = get_channel_layer() from asgiref.sync import async_to_sync async_to_sync(channel_layer.group_send)(soucketGroupName + sendUser, {"type": "chat_message", \'message\': message}) else: redisKey = AgentID + "$" + FromUserName chatlog.append(chatInfo) if not cache.get(redisKey): cache.set(redisKey, chatlog, timeout=None) else: redisUser = cache.get(redisKey) redisUser.append(chatInfo) cache.set(redisKey, redisUser, timeout=None) if agentInfo.notuserText: client = WeChatClient(corpid, agentInfo.secret) client.message.send_text(AgentID, FromUserName, agentInfo.notuserText) content = template_string( username=currentUser.username, um=FromUserName, content=Content, url="[发起对话](http://w.pinganbanksz.com:8000/work/chatMobile/)" ) if agentInfo.webhook_url: encoded_data = json.dumps({"msgtype": "markdown", "markdown": {\'content\': content}}).encode(\'utf-8\') http = urllib3.PoolManager() rr = http.request(method=\'POST\', url=agentInfo.webhook_url, body=encoded_data, headers={\'Content-Type\': \'application/json\'}) print(f\'webhook response:{rr.data}\') assert json.loads(rr.data).get(\'errcode\') == 0 def downloadFile(data, fileType): AgentID = data["AgentID"] agentInfo = agent.objects.filter(agentid=AgentID).first() agentid = agentInfo.agentid secret = agentInfo.secret client = WeChatClient(corpid, secret) result = client.media.get_url(data["MediaId"]) file = str(uuid.uuid1()) + "." + fileType BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sourceUrl = os.path.join(BASE_DIR, sourceFile) LocalPath = os.path.join(sourceUrl, file) # os.path.join将多个路径组合后返回 urllib.request.urlretrieve(result, LocalPath) return "/{0}/{1}".format(sourceFile, file) class switch_wechat_messages(object): def case_to_function(self, case): fun_name = str(case) + "Message" method = getattr(self, fun_name, self.unknownMessage) return method def textMessage(self, data): Content = data["Content"] setWeChatRedis(data, Content) def imageMessage(self, data): PicUrl = data["PicUrl"] setWeChatRedis(data, PicUrl) print(data) def shortVideoMessage(self, data): print(data) def videoMessage(self, data): fileType = "avi" print(data) setWeChatRedis(data, downloadFile(data, fileType)) def voiceMessage(self, data): fileType = data["Format"] setWeChatRedis(data, downloadFile(data, fileType)) print(data) def locationMessage(self, data): print(data) def linkMessage(self, data): print(data) def eventMessage(self, data): AgentID = data["AgentID"] FromUserName = data["FromUserName"] createUser(FromUserName, AgentID) def unknownMessage(self, data): print(data) def createUser(userid, AgentID): userid = userid.upper() agentInfo = agent.objects.filter(agentid=AgentID).first() client = WeChatClient(corpid, agentInfo.secret) user = client.user.get(userid) obj = userList.objects.filter(userid=userid, agent__agentid=AgentID).first() if not obj: obj = userList.objects.create(username=user["name"], userid=userid, avatar=user["avatar"], agent=agentInfo) else: obj.username = user["name"] obj.avatar = user["avatar"] # 用户访问的时候一天推送一次提示语 if obj.lastTime.date() < datetime.datetime.now().date(): if obj: obj.save() result = client.message.send_text(AgentID, userid, agentInfo.welcomeText) return obj
8.企业微信PC扫码登录
在浏览器输入一下地址,XXXXX需要修改为企业号参数(appid, agentid, redirect_uri)
参数说明:appid 企业ID 企业号后台–>我的企业–>最底部 企业ID
agentid 应用ID 企业号后台–>应用管理–>点击XX应用–>即可查看
redirect_url 登录成功后跳转系统地址 例如在用户扫码登录后,跳转到百度 http://www.baidu.com 跳转地址需要url 编码
https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=XXXXXXX&agentid=XXXXX&redirect_uri=XXXXX&state=XXXXX
7.运行效果图
1.客户端 (微信企业号即可发起聊天)
2.客服端 (使用企业微信扫码登录系统)
2.发送和接受内容
3.PC超级管理员(使用企业微信扫码登录系统)