关于企微群聊天工具功能的开发---PHP+JS+CSS+layui (手把手教学)

文章目录

        • 前言
        • 准备工作
        • PHP代码示例
        • 前端代码示例 主要是js
        • 踩的小坑&笔记
        • 最终达成的效果
        • 总结

前言

公司要求开发企微群聊天工具。首先一个客户一个群,其余群成员都是公司销售、设计师、工长、售后等人员。要求开发一个群聊天工具,工长点击进来以后就可以看到群内客户的合同信息,可以上传每天的施工进度等等。
实现思路:获取当前群聊id,将群聊id和客户合同id进行关联。有了合同id,什么就都有了。
本人是后端人员,但是公司要让我前后端都搞。我也没办法,只能用几年前的layui和最基本的js。

准备工作
  1. 登录到企业微信管理后台官网
  2. 应用管理-应用-自建-创建应用在这里插入图片描述
  3. 复制保存好应用的AgentId和Secret。
  4. 配置到聊天工具栏在这里插入图片描述
  5. 配置应用最开始进入时候加载的页面在这里插入图片描述
  6. 配置企业可信IP、启用JS-SDK工具在这里插入图片描述
  7. 找到我的企业-企业ID在这里插入图片描述
  8. 客户与上下游-点击API-配置可调用接口的应用-选择自己刚才的创建应用。让它有调用客户信息的权限。在这里插入图片描述
    准备工作完成!接下来就是代码示例!
PHP代码示例
function getToken(){//获取access_token$url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" . $company_id . "&corpsecret=" . $secret;$result = sendCurlRequest($url);if ($result['errcode'] == 0) {return ajax_return(200, '获取成功', $result);}return ajax_return(500, 'token获取失败');
}
//这个方法很重要  验签!
function getJsApiTicket(){$access_token = $_REQUEST['access_token'];//获取企业的jsapi_ticket--这个没用到
//    $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=".$access_token;//获取应用内的jsapi_ticket$url = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token=" . $access_token . "&type=agent_config";$result = sendCurlRequest($url);if ($result['errcode'] == 0) {$result['company_id'] = $company_id;$result['agentid'] = $agentid;$result['timestamp'] = $time;$result['nonceStr'] = $nonceStr;$str = "jsapi_ticket=" . $result['ticket'] . "&noncestr=" . $nonceStr . "&timestamp=" . $time . "&url=" . $sign_url;$result['signature'] = sha1($str);$result['url'] = $sign_url;return ajax_return(200, '获取成功', $result);}return ajax_return(500, 'jsapi_ticket获取失败', $result);
}//返回json
function ajax_return($code, $msg, $data = [])
{exit(json_encode(['code' => $code,'msg' => $msg,'data' => $data]));
}//发送curl请求
function sendCurlRequest($url, $data = array(), $method = 'GET')
{$ch = curl_init();//1.初始化curl_setopt($ch, CURLOPT_URL, $url);//2.请求地址curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);//3.请求方式//4.参数如下curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);if ($method == "POST") {//5.post方式的时候添加数据$data = json_encode($data);curl_setopt($ch, CURLOPT_POSTFIELDS, $data);}curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);$output = curl_exec($ch);curl_close($ch);return json_decode($output, true);
}
//生成随机16位的字符串
function generateRandomString($length = 16)
{$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';$charactersLength = strlen($characters);$randomString = '';for ($i = 0; $i < $length; $i++) {$randomString .= $characters[rand(0, $charactersLength - 1)];}return $randomString;
}
前端代码示例 主要是js

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>Document</title><link rel="stylesheet" href="https://cdn.staticfile.org/layui/2.5.7/css/layui.css" media="all">
</head>
<body><div class="layui-container" style="padding: 10px"><div class="layui-row"><div class="layui-col-xs12"><div id="search" style="display: none"><div class="layui-input-inline" style="display: flex;justify-content: space-between;"><input type="text" id="searchInput" name="title" required lay-verify="required"placeholder="请输入合同号" autocomplete="off" class="layui-input"><button class="layui-btn" id="searchBtn" style="margin-left: 10px;">搜索</button></div></div><div id="content" style="display: none"><div class="layui-input-inline" style="display: flex;justify-content: space-between;margin-top: 10px"><button class="layui-btn" id="contractDetails">合同详情</button><button class="layui-btn" id="broadcast">施工播报</button><button class="layui-btn" id="acceptLog">验收日志</button></div><div class="layui-input-inline" style="display: flex;justify-content: space-between;margin-top: 10px"><button class="layui-btn" id="complaint">客诉整改</button><button class="layui-btn" id="satisfaction">满意度评价</button><button class="layui-btn" id="change">变更管理</button></div></div><input type="hidden" id="access_token" name="access_token" class="layui-input"><input type="hidden" id="group_id" name="group_id" value="" class="layui-input"></div></div><div id="myTable"><table class="layui-table" id="simple" lay-filter="simple"></table></div><script type="text/html" id="barDemo"><div class="layui-btn-container"><button class="layui-btn layui-btn-sm" lay-event="bind">绑定</button></div></script>
</div></body>
<script src="https://cdn.staticfile.org/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/layui/2.5.7/layui.js"></script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js" referrerpolicy="origin"></script>
<script>//定义参数let access_token = "";$(document).ready(function () {let group_id = window.sessionStorage.getItem('group_id')if(!group_id){//获取tokengetAccessToken();}else{checkBandContract(group_id)}})// 获取AccessToken,这通常需要企业微信的CorpID和Secretfunction getAccessToken() {$.ajax({url: "http://",type: "GET",dataType: 'json',contentType: 'application/json',success: function (res) {$('#access_token').val(res.data.access_token)access_token = res.data.access_tokenconsole.log('access_token:',access_token)//获取企业的jsapi_ticketgetJsApiTicket(access_token);},error: function (e) {console.log(e)}})}//获取ticket以及群idfunction getJsApiTicket(access_token){$.ajax({url: "http://getJsApiTicket", //对应php代码中的getJsApiTicket方法type: "GET",dataType: 'json',contentType: 'application/json',data: {access_token:access_token,},success: function (res) {wx.agentConfig({beta:true,debug:true,corpid: res.data.company_id, // 必填,企业微信的corpid,必须与当前登录的企业一致agentid: res.data.agentid, // 必填,企业微信的应用id (e.g. 1000247)timestamp: res.data.timestamp, // 必填,生成签名的时间戳nonceStr: res.data.nonceStr, // 必填,生成签名的随机串signature: res.data.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法jsApiList: ['getCurExternalChat'], //必填,传入需要使用的接口名称success: function (res) {wx.invoke('getCurExternalChat', { }, function (res) {if (res.err_msg === 'getCurExternalChat:ok') {let group_id = res.chatId //返回当前外部群的群聊ID//判断当前群聊是否绑定了合同checkBandContract(group_id)//存入到sessionwindow.sessionStorage.setItem('group_id',res.chatId)} else {//错误处理console.log(888888)}})// 回调},fail: function (res) {if (res.err_msg.indexOf('function not exist') > -1) {alert('版本过低请升级')}alert('获取企微群id失败')},})},error: function (e) {console.log(e)}})}//判断当前群聊是否绑定了合同function checkBandContract(group_id){$.ajax({url: "http://",type: "GET",dataType: 'json',data:{group_id:group_id},contentType: 'application/json',success: function (res) {if(res.data == 1){//未绑定$('#search').css('display','block')}else if(res.data == 2){//已绑定$('#content').css('display','block')}else{layer.msg('系统出错!请联系管理员')}},error: function (e) {console.log(e)}})}layui.use(['form', 'layer','table'], function () {let layer = layui.layer;let table = layui.table;//搜索点击事件$('#searchBtn').on('click', function () {let searchText = $('#searchInput').val();$.ajax({url: "http",type: "GET",dataType: 'json',data:{sn:searchText},contentType: 'application/json',success: function (res) {if(res.code === 200){// getTableData(res.data)table.render({elem: '#simple',cellMinWidth: 80,  // 全局定义常规单元格的最小宽度,layui2.2.1新增cols: [[// 表头,对应数据格式,此示例只设置3格// 若不填写width列宽将自动分配{field: 'cid', title: 'ID', width: 80, fixed: 'left'},{field: 'sn', title: 'SN', width: 120},{field: 'customer_name', title: '姓名', width: 80},{field: 'address', title: '地址', width: 220},{title: '操作', toolbar: "#barDemo"}]],// 默认不开启分页(即false),若要开启,设置:page: true,// 若不想通过url获取数据也可用data设置赋值已知数据data: res.data,toolbar:'#barDemo'});console.log('tableData:',res)}else{layer.msg(res.msg);}},error: function (e) {console.log(e)}})});//工具列点击事件table.on('tool(simple)', function (obj) {let event = obj.event;if (event === 'bind') {let id = obj.data.cid;let group_id = window.sessionStorage.getItem('group_id')console.log('group_id:',group_id)if (id === '' || id === 'undefined') {layer.msg('id不能为空');return;}if (group_id === '' || group_id === 'undefined') {layer.msg('group_id不能为空');return;}layer.confirm('绑定后不可更改,确定绑定吗?', {btn: ['确定', '取消'] //按钮}, function () {$.post('http', {id: id,group_id: group_id}, function (data) {if (data.code == 200) {layer.msg(data.msg);setTimeout(function () {$('#myTable').css('display','none')$('#search').css('display','none')$('#content').css('display','block')}, '1000');} else {layer.msg(data.msg);}}, 'JSON');});}});//合同详情$('#contractDetails').on('click', function () {let group_id = window.sessionStorage.getItem('group_id')$.ajax({url: "http:",type: "GET",dataType: 'json',data:{group_id:group_id},contentType: 'application/json',success: function (res) {if(res.code === 200){console.log('res===',res)window.location.href = "";}else{console.log('res=====',res)layer.msg(res.msg);}},error: function (e) {console.log(e)}})});//施工播报//验收日志//客诉整改//变更管理});</script>
</html>
踩的小坑&笔记
  1. html文件必须在企微环境下运行,不然报错 “wx.invoke is not a function”。(这个很恶心,搞了大半天才知道。)
  2. 企微错误码查询工具
  3. 官方文档的提示:请确保在服务上线前一定全局缓存access_token和jsapi_ticket,两者有效期均为7200秒(以返回结果中的expires_in为准),否则一旦上线触发频率限制,服务将不再可用。
  4. 官方文档中的:常见错误以及解决方法
  5. 客户端调试工具 这个很重要!!!
  6. 当点击页面中某个按钮后,企微会自动登录然后跳转到首页。这时候需要修改企微登录的逻辑。(这是我当前项目中的逻辑,不适用于每一个人!
  7. 一定要先执行wx.agentConfig验签通过后才可以调用wx.invoke.
  8. 要注意,获取群列表的时候,只可以获取当前应用下的群列表!
  9. 在不同应用中获取的同一个群的id也是不同的!(不太确定,记得在文档中看到这句话了)。
最终达成的效果

每一个都是一个自建应用。在手机上显示的话,就会显示到聊天窗口的上面。

在这里插入图片描述

总结

其实这玩意就是企微内嵌了一个浏览器。
还是等于是页面开发。
主要就是验签的那一步,其实也没啥。
就是一开始不知道在企微还得下载一个安装包才可以进行调试。
能够进行调试以后,就一马平川了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/391671.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ReentrantLock源码分析

文章目录 一、AQS1、state属性2、等待队列3、条件变量 二、ReentrantLock1、非公平锁实现原理1.1 获取锁1.2 释放锁1.3 可重入原理1.4 可打断原理不可打断可打断 1.5 公平锁实现原理1.6 条件变量原理awaitsignal 一、AQS AQS全称是 AbstractQueuedSynchronizer&#xff0c;是阻…

Python面试宝典第27题:全排列

题目 给定一个不含重复数字的数组nums&#xff0c;返回其所有可能的全排列 。备注&#xff1a;可以按任意顺序返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]] 示例 2&#xff1a; 输…

FPGA开发——数码管的使用(二)

一、概述 在上一篇文章中我们针对单个数码管的静态显示和动态显示进行了一个设计和实现&#xff0c;这篇文章中我们针对多个数码管同时显示进行一个设计。这里和上一篇文章唯一不同的是就是数码管位选进行了一个改变&#xff0c;原来是单个数码管的显示&#xff0c;所以位选就直…

详细说明Java中Map和Set接口的使用方法

Map与Set的基本概念与场景 Map和set是一种专门用来进行搜索的容器或者数据结构&#xff0c;其搜索的效率与其具体的实例化子类有关。以前常见的搜索方式有&#xff1a; 1. 直接遍历&#xff0c;时间复杂度为O(N)&#xff0c;元素如果比较多效率会非常慢。 2. 二分查找&#x…

WordPress网站被入侵,劫持收录事件分析

7.15&#xff0c;网站被入侵&#xff0c;但是直到7月17日&#xff0c;我才发现被入侵。 16日&#xff0c;17日正常更新文章&#xff0c;17日查询网站收录数据时&#xff0c;在站长资源平台【流量与关键词】查询上&#xff0c;我发现了比较奇怪的关键词。 乱码关键词排名 起初…

JavaDS —— AVL树

前言 本文章将介绍 AVL 树的概念&#xff0c;重点介绍AVL 树的插入代码是如何实现的&#xff0c;如果大家对 AVL 树的删除&#xff08;还是和二叉搜索树一样使用的是替换删除法&#xff0c;然后需要判断是否进行旋转调整&#xff09;感兴趣的话&#xff0c;可以自行去翻阅其他…

关于Unity转微信小程序的流程记录

1.准备工作 1.unity微信小程序转换工具&#xff0c;minigame插件&#xff0c;导入后工具栏出现“微信小游戏" 2.微信开发者工具稳定版 3.MP微信公众平台申请微信小游戏&#xff0c;获得游戏appid 4.unity转webgl开发平台&#xff0c;Player Setting->Other Setting…

市场主流 AI 视频生成技术的迭代路径

AI视频生成技术的迭代路径经历了从GANVAE、Transformer、Diffusion Model到Sora采用的DiT架构&#xff08;TransformerDiffusion&#xff09;等多个阶段&#xff0c;每个阶段的技术升级都在视频处理质量上带来了飞跃性的提升。这些技术进步不仅推动了AI视频生成领域的快速发展&…

评估生成分子/对接分子的物理合理性工具 PoseBusters 评测

最近在一些分子生成或者对接模型中&#xff0c;出现了新的评估方法 PoseBusters&#xff0c;用于评估生成的分子或者对接的分子是否符合化学有效性和物理合理性。以往的分子生成&#xff0c;经常以生成分子的有效性、新颖性、化学空间分布&#xff0c;与口袋的结合力等方面进行…

微软蓝屏事件揭示的网络安全深层问题与未来应对策略

目录 微软蓝屏事件揭示的网络安全深层问题与未来应对策略 一、事件背景 二、事件影响 2.1、跨行业连锁反应 2.2、经济损失和社会混乱 三、揭示的网络安全问题 3.2、软件更新管理与风险评估 3.2、系统复杂性与依赖关系 3.3、网络安全意识与培训 四、未来的网络安全方向…

网络云相册实现--nodejs后端+vue3前端

目录 主页面 功能简介 系统简介 api 数据库表结构 代码目录 运行命令 主要代码 server apis.js encry.js mysql.js upload.js client3 index.js 完整代码 主页面 功能简介 多用户系统&#xff0c;用户可以在系统中注册、登录及管理自己的账号、相册及照片。 每…

众人帮蚂蚁帮任务平台修复版源码,含搭建教程。

全修复运营版本的任务平台&#xff0c;支持垂直领域细分&#xff0c;定向导流&#xff0c;带有排行榜功能&#xff0c;任务发布上传审核&#xff0c;用户信用等级&#xff0c;充值接口等等均完美可用。支付对接Z支付免签接口&#xff0c;环境配置及安装教程都已经打包。 搭建环…

C语言调试宏全面总结(六大板块)

C语言调试宏进阶篇&#xff1a;实用指南与案例解析C语言调试宏高级技巧与最佳实践C语言调试宏的深度探索与性能考量C语言调试宏在嵌入式系统中的应用与挑战C语言调试宏在多线程环境中的应用与策略C语言调试宏在并发编程中的高级应用 C语言调试宏进阶篇&#xff1a;实用指南与案…

【Linux】网络基础_4

文章目录 十、网络基础5. socket编程网络翻译服务 未完待续 十、网络基础 5. socket编程 网络翻译服务 基于UDP&#xff0c;我们实现一个简单的翻译。 我们导入之前写的代码&#xff1a; InetAddr.hpp&#xff1a; #pragma once#include <iostream> #include <sys…

开源智能低代码自动化助手:Obsei

**Obsei&#xff1a;**低代码&#xff0c;高效率&#xff0c;Obsei让AI自动化触手可及。- 精选真开源&#xff0c;释放新价值。 概览 Obsei是一款开源的低代码人工智能自动化工具&#xff0c;它为企业提供了一套灵活的解决方案&#xff0c;以应对日益增长的数据处理需求。该工…

uvm_config_db 和 uvm_resource_db :

uvm_config_db class my_driver extends uvm_driver;int my_param;function new(string name, uvm_component parent);super.new(name, parent);endfunctionvirtual task run_phase(uvm_phase phase);// 在组件内部获取配置值if (!uvm_config_db#(int)::get(this, ""…

[Git][远程操作]详细讲解

1.理解分布式版本控制系统 形象理解&#xff1a;每个⼈的电脑上都是⼀个完整的版本库 这样⼯作的时候&#xff0c;就不需要联⽹了&#xff0c; 因为版本库就在⾃⼰的电脑上 既然每个⼈电脑上都有⼀个完整的版本库&#xff0c;那多个⼈如何协作呢&#xff1f; 例如&#xff1a;…

ajax图书管理项目

bootstrap弹框 不离开当前页面&#xff0c;显示单独内容&#xff0c;让用户操作 功能&#xff1a;不离开当前页面&#xff0c;显示单独内容&#xff0c;供用户操作步骤&#xff1a; 1.引入bootstrap.css和bootstrap.js …

Stegdetect教程:如何用Stegdetect检测和破解JPG图像隐写信息

一、Stegdetect简介 Stegdetect 是一个开源工具&#xff0c;专门设计用于检测图像文件&#xff08;JPG格式&#xff09;中的隐写信息。Stegdetect 可以检测多种常见的隐写方法&#xff0c;比如 JSteg、JPHide 和 OutGuess 等。 二、使用Stegdetect检测图像隐写 官方描述&#…

NSS [SWPUCTF 2022 新生赛]file_master

NSS [SWPUCTF 2022 新生赛]file_master 开题&#xff0c;一眼文件上传。 network看看返回包。后端语言是PHP。 除了文件上传还有个查看文件功能。 起手式查询/etc/passwd&#xff0c;发现查询方法是GET提交参数&#xff0c;后端使用file_get_contents()函数包含文件。同时有op…