企业微信最新的jssdk使用说明 WECOM-JSSDK Demo
发表于:2025-08-16 09:29:33浏览:31次
企业微信的WECOM-JSSDK与JS-SDK的异同,官方是这样描述的:
旧版本(原JS-SDK)仍支持使用,相较旧版本WECOM-JSSDK提供了Typescript类型支持、npm引入等新能力。但企业微信官方推荐使用的是最新的WECOM-JSSDK,WECOM-JSSDK能做什么?简而言之,WECOM-JSSDK为网页应用提供了调用原生能力的通道,网页应用通过 WECOM-JSSDK 可以调起拍照、选择图片、录音、获取地理位置信息等手机系统能力。同时可以使用企业微信分享、扫一扫等企业微信微信特有能力,为企业微信用户提供更优质的网页应用体验。
使用WECOM-JSSDK最关键的一步就是鉴权
,其他接口调用就是正常的api调用即可,在调用 JSAPI 前,需要先通过 ww.register 注册当前页面的身份信息。身份信息分为两种:
企业身份与权限
应用(自建应用/第三方应用等)身份与权限。之所以有两种,是有些api使用企业身份即可,有些api需要使用应用身份。总体应用身份能做的事情更多一些。
注册身份信息时,需要提供对应的签名函数,签名是根据当前页面的 URL 和 jsapi_ticket 等信息生成的。
jsapi_ticket敏感信息,需要在服务端完成签名操作。
JS-SDK 签名算法企业微信官方文档:https://developer.work.weixin.qq.com/document/path/96909
具体根据企业微信官方文档开发即可,这里贴出基于thinkphp的完整代码:
创建QyWechatService.php
文件
<?php
namespace app\qiye;
use think\facade\Cache;
use think\facade\Log;
class QyWechatService
{
// 获取access_token
public static function getAccessToken()
{
$cacheKey = 'qywx_access_token';
$token = Cache::get($cacheKey);
if (!$token) {
$config = config('workchat');
$url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$config['corpid']}&corpsecret={$config['corpsecret']}";
$response = json_decode(file_get_contents($url), true);
if (empty($response['access_token'])) {
Log::error('获取access_token失败: ' . json_encode($response));
throw new \Exception("获取access_token失败");
}
$token = $response['access_token'];
// 缓存7000秒(官方有效期7200秒)
Cache::set($cacheKey, $token, 7000);
}
return $token;
}
// 获取企业jsapi_ticket
public static function getJsapiTicket()
{
$cacheKey = 'qywx_jsapi_ticket';
$ticket = Cache::get($cacheKey);
if (!$ticket) {
$accessToken = self::getAccessToken();
$url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token={$accessToken}";
$response = json_decode(file_get_contents($url), true);
if (empty($response['ticket'])) {
Log::error('获取jsapi_ticket失败: ' . json_encode($response));
throw new \Exception("获取jsapi_ticket失败");
}
$ticket = $response['ticket'];
// 缓存7000秒
Cache::set($cacheKey, $ticket, 7000);
}
return $ticket;
}
// 生成企业JS-SDK签名
public static function getSignature($url)
{
$ticket = self::getJsapiTicket();
$nonceStr = self::createNonceStr(16); // 随机字符串
$timestamp = time();
// 按字典序拼接参数
$string = "jsapi_ticket={$ticket}&noncestr={$nonceStr}×tamp={$timestamp}&url={$url}";
$signature = sha1($string);
return [
'corpid' => config('workchat.corpid'), // 企业微信的CorpID
'timestamp' => $timestamp,
'nonceStr' => $nonceStr,
'signature' => $signature,
'url' => $url // 可选,前端需校验URL一致性
];
}
// 获取应用 jsapi_ticket
public static function getAgentJsapiTicket()
{
$cacheKey = 'qywx_jsapi_ticket_a';
$ticket = Cache::get($cacheKey);
if (!$ticket) {
$accessToken = self::getAccessToken();
$url = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token={$accessToken}&type=agent_config";
$response = json_decode(file_get_contents($url), true);
if (empty($response['ticket'])) {
Log::error('获取jsapi_ticket失败: ' . json_encode($response));
throw new \Exception("获取jsapi_ticket失败");
}
$ticket = $response['ticket'];
// 缓存7000秒
Cache::set($cacheKey, $ticket, 7000);
}
return $ticket;
}
// 生成应用JS-SDK签名
public static function getAgentConfigSignature($url)
{
$ticket = self::getAgentJsapiTicket();
$nonceStr = self::createNonceStr(16); // 随机字符串
$timestamp = time();
// 按字典序拼接参数
$string = "jsapi_ticket={$ticket}&noncestr={$nonceStr}×tamp={$timestamp}&url={$url}";
$signature = sha1($string);
return [
'corpid' => config('workchat.corpid'), // 企业微信的CorpID
'timestamp' => $timestamp,
'nonceStr' => $nonceStr,
'signature' => $signature,
'url' => $url // 可选,前端需校验URL一致性
];
}
// 生成随机字符串
private static function createNonceStr($length = 16)
{
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
}
创建Api.php文件
<?php
declare (strict_types = 1);
namespace app\qiye\controller;
use app\qiye\BaseController;
use app\qiye\QyWechatService;
class Api extends BaseController
{
/**
* 构造函数
*/
public function __construct()
{
$this->workchat = get_config('workchat');
}
//jssdk
public function jssdk()
{
try {
$param = get_params();
$currentUrl = $param['url']; // 前端传递当前页面URL
if (empty($currentUrl)) {
return json(['code' => 400, 'msg' => 'URL参数缺失']);
}
$config = QyWechatService::getSignature($currentUrl);
return json(['code' => 0, 'data' => $config]);
} catch (\Exception $e) {
return json(['code' => 500, 'msg' => $e->getMessage()]);
}
}
//jssdk
public function jssdkww()
{
try {
$param = get_params();
$currentUrl = $param['url']; // 前端传递当前页面URL
if (empty($currentUrl)) {
return json(['code' => 400, 'msg' => 'URL参数缺失']);
}
$config = QyWechatService::getAgentConfigSignature($currentUrl);
return json(['code' => 0, 'data' => $config]);
} catch (\Exception $e) {
return json(['code' => 500, 'msg' => $e->getMessage()]);
}
}
}
前端文件:
<html>
<head>
<meta charset="utf-8">
<title>企业微信JS-SDK Demo</title>
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
<style type="text/css">
html {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-webkit-user-select: none;
user-select: none;
}
body {
line-height: 1.6;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
background-color: #f1f0f6;
}
* {
margin: 0;
padding: 0;
}
button {
font-family: inherit;
font-size: 100%;
margin: 0;
*font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
ul,
ol {
padding-left: 0;
list-style-type: none;
}
a {
text-decoration: none;
}
.label_box {
background-color: #ffffff;
}
.label_item {
padding-left: 15px;
}
.label_inner {
padding-top: 10px;
padding-bottom: 10px;
min-height: 24px;
position: relative;
}
.label_inner:before {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 200%;
height: 1px;
border-top: 1px solid #ededed;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scale(0.5);
transform: scale(0.5);
top: auto;
bottom: -2px;
}
.lbox_close {
position: relative;
}
.lbox_close:before {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 200%;
height: 1px;
border-top: 1px solid #ededed;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scale(0.5);
transform: scale(0.5);
}
.lbox_close:after {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 200%;
height: 1px;
border-top: 1px solid #ededed;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scale(0.5);
transform: scale(0.5);
top: auto;
bottom: -2px;
}
.lbox_close .label_item:last-child .label_inner:before {
display: none;
}
.btn {
display: block;
margin-left: auto;
margin-right: auto;
padding-left: 14px;
padding-right: 14px;
font-size: 18px;
text-align: center;
text-decoration: none;
overflow: visible;
height: 42px;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
color: #ffffff;
line-height: 42px;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
}
.btn.btn_inline {
display: inline-block;
}
.btn_primary {
background-color: #437DBA;
}
.btn_primary:not(.btn_disabled):visited {
color: #ffffff;
}
.btn_primary:not(.btn_disabled):active {
color: rgba(255, 255, 255, 0.9);
background-color: #3b78b9;
}
button.btn {
width: 100%;
border: 0;
outline: 0;
-webkit-appearance: none;
}
button.btn:focus {
outline: 0;
}
.wxapi_container {
font-size: 16px;
}
h1 {
font-size: 14px;
font-weight: 400;
line-height: 2em;
padding-left: 15px;
color: #8d8c92;
}
.desc {
font-size: 14px;
font-weight: 400;
line-height: 2em;
color: #8d8c92;
}
.wxapi_index_item a {
display: block;
color: #3e3e3e;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.wxapi_form {
background-color: #ffffff;
padding: 0 15px;
margin-top: 30px;
padding-bottom: 15px;
}
h3 {
padding-top: 16px;
margin-top: 25px;
font-size: 16px;
font-weight: 400;
color: #3e3e3e;
position: relative;
}
h3:first-child {
padding-top: 15px;
}
h3:before {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 200%;
height: 1px;
border-top: 1px solid #ededed;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scale(0.5);
transform: scale(0.5);
}
.btn {
margin-bottom: 15px;
}
</style>
</style>
</head>
<body ontouchstart="">
<div class="wxapi_container">
<div class="wxapi_index_container">
<ul class="label_box lbox_close wxapi_index_list">
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-basic">基础接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-enterprise">通讯录接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-chat">会话接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-share">分享接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-webview">界面接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-sys-webview">系统界面接口</a>
</li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-image">图像接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-voice">录音接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-open">开放接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-file">文件接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-clipboard">剪贴板接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-network">网络接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-location">地理位置接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-client">客户联系接口</a> </li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-schedule">日程接口</a>
</li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-meeting">会议接口</a>
</li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-living">直播接口</a>
</li>
<li class="label_item wxapi_index_item"> <a class="label_inner" href="#menu-approval">审批接口</a>
</li>
</ul>
</div>
<div class="lbox_close wxapi_form">
<h3 id="menu-basic">基础接口</h3>
<span class="desc">判断当前客户端是否支持指定JS接口</span>
<button class="btn btn_primary" data-type="checkJsApi"> checkJsApi </button>
<span class="desc">判断用户是从哪个入口打开页面</span>
<button class="btn btn_primary" data-type="getContext"> getContext </button>
<h3 id="menu-enterprise">通讯录接口</h3>
<span class="desc">选择通讯录成员</span>
<button class="btn btn_primary" data-type="selectEnterpriseContact">selectEnterpriseContact</button>
<span class="desc">调起个人信息页面</span>
<button class="btn btn_primary" data-type="openUserProfile">openUserProfile</button>
<h3 id="menu-chat">会话接口</h3>
<span class="desc">打开会话</span>
<button class="btn btn_primary" data-type="openEnterpriseChat">openEnterpriseChat</button>
<h3 id="menu-share">分享接口</h3>
<span class="desc">监听「转发」按钮点击</span>
<button class="btn btn_primary" data-type="onMenuShareAppMessage">onMenuShareAppMessage</button>
<span class="desc">监听「微信」按钮点击</span>
<button class="btn btn_primary" data-type="onMenuShareWechat">onMenuShareWechat</button>
<span class="desc">监听「朋友圈」按钮点击</span>
<button class="btn btn_primary" data-type="onMenuShareTimeline">onMenuShareTimeline</button>
<span class="desc">自定义转发到会话</span>
<button class="btn btn_primary" data-type="shareAppMessage">shareAppMessage</button>
<span class="desc">自定义转发到微信</span>
<button class="btn btn_primary" data-type="shareWechatMessage">shareWechatMessage</button>
<h3 id="menu-webview">界面接口</h3>
<span class="desc">监听页面返回</span>
<button class="btn btn_primary" data-type="onHistoryBack">onHistoryBack</button>
<span class="desc">隐藏右上角菜单</span>
<button class="btn btn_primary" data-type="hideOptionMenu">hideOptionMenu</button>
<span class="desc">显示右上角菜单</span>
<button class="btn btn_primary" data-type="showOptionMenu">showOptionMenu</button>
<span class="desc">关闭当前窗口</span>
<button class="btn btn_primary" data-type="closeWindow">closeWindow</button>
<span class="desc">批量隐藏功能按钮</span>
<button class="btn btn_primary" data-type="hideMenuItems">hideMenuItems</button>
<span class="desc">批量显示功能按钮</span>
<button class="btn btn_primary" data-type="showMenuItems">showMenuItems</button>
<span class="desc">隐藏非基础按钮</span>
<button class="btn btn_primary" data-type="hideAllNonBaseMenuItem">hideAllNonBaseMenuItem</button>
<span class="desc">显示非基础按钮</span>
<button class="btn btn_primary" data-type="showAllNonBaseMenuItem">showAllNonBaseMenuItem</button>
<span class="desc">打开默认浏览器(仅支持PC端)</span>
<button class="btn btn_primary" data-type="openDefaultBrowser">openDefaultBrowser</button>
<h3 id="menu-sys-webview">系统界面接口</h3>
<span class="desc">调起扫一扫</span>
<button class="btn btn_primary" data-type="scanQRCode">scanQRCode</button>
<span class="desc">跳转认证界面</span>
<button class="btn btn_primary" data-type="enterpriseVerify">enterpriseVerify</button>
<span class="desc">调起应用管理界面</span>
<button class="btn btn_primary" data-type="openAppManage">openAppManage</button>
<h3 id="menu-image">图像接口</h3>
<span class="desc">选择图片</span>
<button class="btn btn_primary" data-type="chooseImage"> chooseImage </button>
<div class="image_container" id="imageContainer"></div>
<span class="desc">预览图片</span>
<button class="btn btn_primary" data-type="previewImage"> previewImage </button>
<span class="desc">上传图片</span>
<button class="btn btn_primary" data-type="uploadImage"> uploadImage </button>
<span class="desc">下载图片</span>
<button class="btn btn_primary" data-type="downloadImage"> downloadImage </button>
<div class="image_container" id="imageContainerForDownload"></div>
<h3 id="menu-voice">录音接口</h3>
<div class="desc" id="voiceToast"></div>
<span class="desc">开始录音</span>
<button class="btn btn_primary" data-type="startRecord"> startRecord </button>
<span class="desc">停止录音</span>
<button class="btn btn_primary" data-type="stopRecord"> stopRecord </button>
<span class="desc">播放语音</span>
<button class="btn btn_primary" data-type="playVoice"> playVoice </button>
<span class="desc">暂停播放</span>
<button class="btn btn_primary" data-type="pauseVoice"> pauseVoice </button>
<span class="desc">停止播放</span>
<button class="btn btn_primary" data-type="stopVoice"> stopVoice </button>
<span class="desc">上传语音</span>
<button class="btn btn_primary" data-type="uploadVoice"> uploadVoice </button>
<span class="desc">下载语音</span>
<button class="btn btn_primary" data-type="downloadVoice"> downloadVoice </button>
<span class="desc">语音转文字</span>
<button class="btn btn_primary" data-type="translateVoice"> translateVoice </button>
<h3 id="menu-open">开放接口</h3>
<span class="desc">创建企业微信登录面板</span>
<button class="btn btn_primary" data-type="createWWLoginPanel"> createWWLoginPanel </button>
<div id="ww_login"></div>
<h3 id="menu-file">文件接口</h3>
<span class="desc">预览文件</span>
<button class="btn btn_primary" data-type="previewFile"> previewFile </button>
<h3 id="menu-clipboard">剪贴板接口</h3>
<span class="desc">设置剪贴板内容</span>
<button class="btn btn_primary" data-type="setClipboardData"> setClipboardData </button>
<span class="desc">获取剪贴板内容</span>
<button class="btn btn_primary" data-type="getClipboardData"> getClipboardData </button>
<h3 id="menu-network">网络接口</h3>
<span class="desc">获取网络状态</span>
<button class="btn btn_primary" data-type="getNetworkType"> getNetworkType </button>
<span class="desc">监听网络状态</span>
<button class="btn btn_primary" data-type="onNetworkStatusChange"> onNetworkStatusChange </button>
<h3 id="menu-location">地理位置接口</h3>
<div class="desc" id="locationToast"></div>
<span class="desc">打开内置地图</span>
<button class="btn btn_primary" data-type="openLocation"> openLocation </button>
<span class="desc">获取地理位置</span>
<button class="btn btn_primary" data-type="getLocation"> getLocation </button>
<span class="desc">打开持续定位</span>
<button class="btn btn_primary" data-type="startAutoLBS"> startAutoLBS </button>
<span class="desc">停止持续定位</span>
<button class="btn btn_primary" data-type="stopAutoLBS"> stopAutoLBS </button>
<span class="desc">监听地理位置</span>
<button class="btn btn_primary" data-type="onLocationChange"> onLocationChange </button>
<h3 id="menu-client">客户联系接口</h3>
<span class="desc">调起外部联系人列表</span>
<button class="btn btn_primary" data-type="selectExternalContact"> selectExternalContact </button>
<span class="desc">群发消息给客户</span>
<button class="btn btn_primary" data-type="shareToExternalContact"> shareToExternalContact </button>
<span class="desc">群发消息到客户群</span>
<button class="btn btn_primary" data-type="shareToExternalChat"> shareToExternalChat </button>
<span class="desc">调起添加客户界面</span>
<button class="btn btn_primary" data-type="navigateToAddCustomer"> navigateToAddCustomer </button>
<span class="desc">发表内容到客户朋友圈</span>
<button class="btn btn_primary" data-type="shareToExternalMoments"> shareToExternalMoments </button>
<span class="desc">设置朋友圈封面与签名</span>
<button class="btn btn_primary" data-type="updateMomentsSetting"> updateMomentsSetting </button>
<h3 id="menu-schedule">日程接口</h3>
<span class="desc">查看日程闲忙</span>
<button class="btn btn_primary" data-type="checkSchedule"> checkSchedule </button>
<h3 id="menu-meeting">会议接口</h3>
<span class="desc">创建会议并调起会议室页面</span>
<button class="btn btn_primary" data-type="startMeeting"> startMeeting </button>
<h3 id="menu-living">直播接口</h3>
<span class="desc">创建直播并调起直播页面</span>
<button class="btn btn_primary" data-type="startLiving"> startLiving </button>
<span class="desc">调起直播间回放</span>
<button class="btn btn_primary" data-type="replayLiving"> replayLiving </button>
<span class="desc">调起直播回放下载页面</span>
<button class="btn btn_primary" data-type="downloadLivingReplay"> downloadLivingReplay </button>
<h3 id="menu-approval">审批接口</h3>
<span class="desc">应用发起审批</span>
<button class="btn btn_primary" data-type="thirdPartyOpenPage"> thirdPartyOpenPage </button>
</div>
</div>
// alert(ww.SDK_VERSION)
const messageDiv = document.getElementById('message');
const chooseImageButton = document.getElementById('chooseImage');
// basic info
corpId = 'your_corp_id';
agentId = 1000005; // change to your agent id
jsApiList = ['checkJsApi', 'get、、Context',
'selectEnterpriseContact', 'openUserProfile',
'openEnterpriseChat',
'onMenuShareAppMessage', 'onMenuShareWechat', 'onMenuShareTimeline', 'shareAppMessage', 'shareWechatMessage',
'onHistoryBack', 'hideOptionMenu', 'showOptionMenu', 'closeWindow', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'openDefaultBrowser', 'onUserCaptureScreen',
'scanQRCode', 'enterpriseVerify', 'openAppManage',
'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getLocalImgData',
'startRecord', 'stopRecord', 'playVoice', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'translateVoice',
'createWWLoginPanel',
'previewFile',
'setClipboardData', 'getClipboardData',
'getNetworkType', 'onNetworkStatusChange',
'openLocation', 'getLocation', 'startAutoLBS', 'stopAutoLBS', 'onLocationChange',
'selectExternalContact', 'shareToExternalContact', 'shareToExternalChat', 'navigateToAddCustomer', 'shareToExternalMoments', 'updateMomentsSetting',
'checkSchedule',
'startMeeting',
'startLiving', 'replayLiving', 'downloadLivingReplay',
'thirdPartyOpenPage',];
// // 企业身份与权限
// ww.register({
// corpId: corpId, // 必填,当前用户企业所属企业ID
// jsApiList: jsApiList, // 必填,需要使用的JSAPI列表
// getConfigSignature // 必填,根据url生成企业签名的回调函数
// })
// 应用身份与权限
ww.register({
corpId: corpId, // 必填,当前用户企业所属企业ID
agentId: agentId, // 必填,当前应用的AgentID
jsApiList: jsApiList, // 必填,需要使用的JSAPI列表
getConfigSignature, // 必填,根据url生成企业签名的回调函数
getAgentConfigSignature // 必填,根据url生成应用签名的回调函数
})
async function getConfigSignature(url) {
// 根据 url 生成企业签名
// 生成方法参考 https://developer.work.weixin.qq.com/document/14924
const response = await fetch('/amyu/get_corp_jssdk_config', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ url })
})
if (!response.ok) {
throw new Error('Network response was not ok ' + response.statusText);
}
const data = await response.json();
const { timestamp, nonceStr, signature } = data;
return { timestamp, nonceStr, signature }
}
async function getAgentConfigSignature(url) {
// 根据 url 生成应用签名,生成方法同上,但需要使用应用的 jsapi_ticket
const response = await fetch('/amyu/get_app_jssdk_config', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ url })
})
if (!response.ok) {
throw new Error('Network response was not ok ' + response.statusText);
}
const data = await response.json();
const { timestamp, nonceStr, signature } = data;
return { timestamp, nonceStr, signature }
}
images = { localId: [], serverId: [] };
voice = { localId: "", serverId: "" };
userids = [];
livingIds = [];
var shareConfig = {
title: "互联网之子",
desc: "在长大的过程中,我才慢慢发现,我身边的所有事,别人跟我说的所有事,那些所谓本来如此,注定如此的事,它们其实没有非得如此,事情是可以改变的。更重要的是,有些事既然错了,那就该做出改变。",
link: "http://movie.douban.com/subject/25785114/",
imgUrl: "http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg",
success: function (e) {
alert("已分享");
},
cancel: function (e) {
alert("已取消");
},
fail: function (e) {
alert(JSON.stringify(e));
},
};
// 调用 register 后可以立刻调用其他 JS 接口
$("[data-type]").on("click", function (e) {
switch ($(e.target).attr("data-type")) {
case "checkJsApi":
ww.checkJsApi({
jsApiList: jsApiList,
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
break;
case "getContext":
ww.getContext({
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
break;
case "selectEnterpriseContact":
ww.selectEnterpriseContact({
fromDepartmentId: -1, // -1 表示从自己所在部门开始
mode: 'multi',
type: ['user'], // ['department', 'user']
success: function (res) {
userids.length = 0
res.result.userList.forEach(user => {
userids.push(user.id)
})
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
break;
case "openUserProfile":
if (userids.length == 0) {
alert("先调用selectEnterpriseContact接口选中一个成员")
}
else {
ww.openUserProfile({
type: 1, // 1 是企业成员
userid: userids[0],
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
}
break;
case "openEnterpriseChat":
if (userids.length == 0) {
alert("先调用selectEnterpriseContact接口选择成员")
}
else {
ww.openEnterpriseChat({
userIds: userids,
fail: function (res) {
alert(JSON.stringify(res));
}
});
}
break;
case "onMenuShareAppMessage":
ww.onMenuShareAppMessage(shareConfig);
alert("已注册获取“转发给同事”状态事件");
break;
case "onMenuShareWechat":
ww.onMenuShareWechat(shareConfig);
alert("已注册获取“微信分享给朋友”状态事件");
break;
case "onMenuShareTimeline":
ww.onMenuShareTimeline(shareConfig);
alert("已注册获取“分享到朋友圈”状态事件");
break;
case "shareAppMessage":
ww.shareAppMessage(shareConfig);
break;
case "shareWechatMessage":
ww.shareWechatMessage(shareConfig);
break;
case "onHistoryBack":
ww.onHistoryBack(function () {
return confirm("确定要放弃当前页面的修改?");
});
alert("已注册获取“页面返回”状态事件");
break;
case "hideOptionMenu":
ww.hideOptionMenu({
success: function (res) {
alert("hideOptionMenu success!" + JSON.stringify(res));
},
fail: function (res) {
alert("hideOptionMenu fail!" + JSON.stringify(res));
},
});
break;
case "showOptionMenu":
ww.showOptionMenu({
success: function (res) {
alert("showOptionMenu success!" + JSON.stringify(res));
},
fail: function (res) {
alert("showOptionMenu fail!" + JSON.stringify(res));
},
});
break;
case "closeWindow":
ww.closeWindow();
break;
case "hideMenuItems":
ww.hideMenuItems({
menuList: [
"menuItem:share:appMessage",
"menuItem:share:wechat",
"menuItem:favorite",
],
success: function (e) {
alert("已隐藏“转发”,“微信”,“收藏”按钮");
},
fail: function (e) {
alert(JSON.stringify(e));
},
});
break;
case "showMenuItems":
ww.showMenuItems({
menuList: [
"menuItem:share:appMessage",
"menuItem:share:wechat",
"menuItem:favorite",
]
});
break;
case "hideAllNonBaseMenuItem":
ww.hideAllNonBaseMenuItem({
success: function (res) {
alert("hideAllNonBaseMenuItem success!" + JSON.stringify(res));
},
fail: function (res) {
alert("hideAllNonBaseMenuItem fail!" + JSON.stringify(res));
},
});
break;
case "showAllNonBaseMenuItem":
ww.showAllNonBaseMenuItem();
break;
case "openDefaultBrowser":
ww.openDefaultBrowser({
url: 'https://work.weixin.qq.com/',
fail: function (res) {
alert("openDefaultBrowser fail!" + JSON.stringify(res));
},
});
break;
case "onUserCaptureScreen":
ww.onUserCaptureScreen(function () {
alert('用户截屏了')
});
break;
case "scanQRCode":
ww.scanQRCode({
needResult: true,
scanType: ['qrCode'],
success: function (res) {
alert("scanQRCode success!" + JSON.stringify(res));
},
fail: function (res) {
alert("scanQRCode fail!" + JSON.stringify(res));
},
cancel: function (res) {
alert("scanQRCode cancel!" + JSON.stringify(res));
}
});
break;
case "enterpriseVerify":
ww.enterpriseVerify({
success: function (res) {
alert("enterpriseVerify success!" + JSON.stringify(res));
},
fail: function (res) {
alert("enterpriseVerify fail!" + JSON.stringify(res));
}
});
break;
case "openAppManage":
ww.openAppManage({
fail: function (res) {
alert("openAppManage fail!" + JSON.stringify(res));
}
});
break;
case "chooseImage":
ww.chooseImage({
count: 1,
sizeType: ["original", "compressed"],
sourceType: ["album", "camera"],
success: function (res) {
images.localId = res.localIds;
alert("已选择 " + res.localIds.length + " 张图片");
// show images
$('#imageContainer').empty();
res.localIds.forEach(localId => {
const imgElement = document.createElement('img');
imgElement.src = localId;
imgElement.alt = 'Response_image';
imgElement.className = 'responsive_image';
$("#imageContainer").append(imgElement);
})
},
fail: function (res) {
alert("chooseImage fail!" + JSON.stringify(res));
},
});
break;
case "previewImage":
ww.previewImage({
current:
"http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg",
urls: [
"http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg",
"https://image14.m1905.cn/uploadfile/2013/1119/20131119113613957229.jpg",
"https://img2.baidu.com/it/u=3076280632,1757512582&fm=253&fmt=auto&app=120&f=JPEG",
],
fail: function (res) {
alert("previewImage fail!" + JSON.stringify(res));
},
});
break;
case "uploadImage":
if (0 == images.localId.length)
return void alert("请先使用 chooseImage 接口选择图片");
var a = 0,
o = images.localId.length;
(images.serverId = []);
(function e() {
ww.uploadImage({
localId: images.localId[a],
success: function (s) {
a++, images.serverId.push(s.serverId);
a < o && e();
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
})();
break;
case "downloadImage":
if (0 === images.serverId.length)
return void alert("请先使用 uploadImage 上传图片");
(a = 0), (o = images.serverId.length);
(images.localId = []);
$('#imageContainerForDownload').empty();
(function e() {
ww.downloadImage({
serverId: images.serverId[a],
success: function (s) {
a++, alert("已下载:" + a + "/" + o);
images.localId.push(s.localId);
showDownloadImage(s.localId);
a < o && e();
},
});
})();
break;
case "startRecord":
$('#voiceToast').text("正在录音,点击 stopRecord 完成录音...");
ww.startRecord({
cancel: function (res) {
alert("用户拒绝授权录音" + JSON.stringify(res));
},
});
break;
case "stopRecord":
$('#voiceToast').empty();
ww.stopRecord({
success: function (res) {
voice.localId = res.localId;
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "playVoice":
if ("" == voice.localId)
return void alert("请先使用 startRecord 接口录制一段声音");
ww.playVoice({
localId: voice.localId,
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "pauseVoice":
if ("" == voice.localId)
return void alert("请先使用 startRecord 接口录制一段声音");
ww.pauseVoice({
localId: voice.localId,
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "stopVoice":
if ("" == voice.localId)
return void alert("请先使用 startRecord 接口录制一段声音");
ww.stopVoice({
localId: voice.localId,
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "uploadVoice":
if ("" == voice.localId)
return void alert("请先使用 startRecord 接口录制一段声音");
ww.uploadVoice({
localId: voice.localId,
success: function (res) {
alert("上传语音成功,serverId 为" + res.serverId);
voice.serverId = res.serverId;
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "downloadVoice":
if ("" == voice.serverId)
return void alert("请先使用 uploadVoice 上传声音");
ww.downloadVoice({
serverId: voice.serverId,
success: function (res) {
alert("下载语音成功,localId 为" + res.localId);
voice.localId = res.localId;
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "translateVoice":
if ("" == voice.localId)
return void alert("请先使用 startRecord 接口录制一段声音");
ww.translateVoice({
localId: voice.localId,
success: function (res) {
alert("识别的文字为:" + res.translateResult);
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "createWWLoginPanel":
ww.createWWLoginPanel({
el: '#ww_login',
params: {
login_type: 'CorpApp',
appid: corpId,
agentid: agentId,
redirect_uri: 'http://bendell02.top/amyu/hello', // change your domain url
state: 'loginState',
redirect_type: 'self', // can be callback / top / self
panel_size: 'small'
},
onCheckWeComLogin({ isWeComLogin }) {
alert(isWeComLogin)
},
onLoginSuccess(code) {
alert(JSON.stringify(code))
},
onLoginFail(err) {
alert(JSON.stringify(err))
},
})
break;
case "previewFile":
ww.previewFile({
url: 'http://open.work.weixin.qq.com/wwopen/downloadfile/wwapi.zip',
name: 'Android开发工具包集合',
size: 22189,
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "setClipboardData":
ww.setClipboardData({
data: 'data',
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "getClipboardData":
ww.getClipboardData({
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "getNetworkType":
ww.getNetworkType({
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "onNetworkStatusChange":
ww.onNetworkStatusChange(function (event) {
alert(JSON.stringify(event))
});
break;
case "openLocation":
ww.openLocation({
latitude: 23.099994,
longitude: 113.32452,
name: "TIT 创意园",
address: "广州市海珠区新港中路 397 号",
scale: 14,
infoUrl: "http://weixin.qq.com",
});
break;
case "getLocation":
ww.getLocation({
success: function (res) {
alert(JSON.stringify(res));
},
cancel: function (res) {
alert("用户拒绝授权获取地理位置" + JSON.stringify(res));
},
});
break;
case "startAutoLBS":
ww.startAutoLBS({
success: function (res) {
$('#locationToast').text("已开启持续定位...");
},
cancel: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "stopAutoLBS":
ww.stopAutoLBS({
success: function (res) {
$('#locationToast').empty();
},
cancel: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "onLocationChange":
origin_text = $('#locationToast').text();
ww.onLocationChange(function (res) {
const latitude = res.latitude;
const longitude = res.longitude;
const accuracy = res.accuracy;
$('#locationToast').text(origin_text + `纬度: ${latitude}, 经度: ${longitude}, 精度: ${accuracy}`);
});
break;
case "selectExternalContact":
ww.selectExternalContact({
filterType: 0,
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "shareToExternalContact":
// 为防止滥用,同一个成员每日向一个客户最多可群发一条消息,每次群发最多可选 20000 个客户
ww.shareToExternalContact({
text: {
content: '企业微信'
},
attachments: [
{
msgtype: 'image',
image: {
imgUrl: 'https://res.mail.qq.com/node/ww/wwmng/style/images/index_share_logo$13c64306.png'
}
}
],
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "shareToExternalChat":
// 为防止滥用,同一个成员每日向一个客户最多可群发一条消息,每次群发最多可选 20000 个客户
ww.shareToExternalChat({
text: {
content: '企业微信'
},
attachments: [
{
msgtype: 'image',
image: {
imgUrl: 'https://res.mail.qq.com/node/ww/wwmng/style/images/index_share_logo$13c64306.png'
}
}
],
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "navigateToAddCustomer":
ww.navigateToAddCustomer({
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "shareToExternalMoments":
ww.shareToExternalMoments({
text: {
content: '企业微信'
},
attachments: [
{
msgtype: 'image',
image: {
imgUrl: 'https://res.mail.qq.com/node/ww/wwmng/style/images/index_share_logo$13c64306.png'
}
}
],
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "updateMomentsSetting":
ww.updateMomentsSetting({
signature: '个性签名',
imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "checkSchedule":
if (userids.length == 0) {
alert("先调用selectEnterpriseContact接口选中一个成员")
$('[data-type="selectEnterpriseContact"]')[0].scrollIntoView({
behavior: 'smooth'
});
}
else {
// 应用需具有日程使用权限
ww.checkSchedule({
start_time: 1667232000,
end_time: 1667318400,
users: [userids[0]],
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
}
break;
case "startMeeting":
// 应用需具有日程使用权限
if (userids.length == 0) {
alert("先调用selectEnterpriseContact接口选择入会成员")
$('[data-type="selectEnterpriseContact"]')[0].scrollIntoView({
behavior: 'smooth'
});
}
else {
ww.startMeeting({
meetingType: 1,
theme: '员工大会',
attendees: userids,
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
}
break;
case "startLiving":
// 应用需具有直播使用权限
ww.startLiving({
liveType: 1,
theme: '新同学培训',
success: function (res) {
alert(JSON.stringify(res));
livingIds.push(res.livingId);
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
case "replayLiving":
// 应用需具有直播使用权限
if (livingIds.length == 0) {
alert("先调用 startLiving 开始一场直播")
}
else {
ww.replayLiving({
livingId: livingIds[livingIds.length - 1],
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
}
break;
case "downloadLivingReplay":
// 应用需具有直播使用权限
if (livingIds.length == 0) {
alert("先调用 startLiving 开始一场直播")
}
else {
ww.downloadLivingReplay({
livingId: livingIds[livingIds.length - 1],
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
}
break;
case "thirdPartyOpenPage":
// 应用需具有审批权限
ww.thirdPartyOpenPage({
oaType: '10001',
// template_id 可在第三方应用-审批接口中创建模板获取
templateId: '598180d72a842404ba872768c873a1a0_2131911712',
thirdNo: 'thirdNo',
extData: {
fieldList: [
{
type: 'text',
title: '采购类型',
value: '市场活动'
},
{
type: 'link',
title: '订单链接',
value: 'https://work.weixin.qq.com'
}
]
},
success: function (res) {
alert(JSON.stringify(res));
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
break;
}
})
function showDownloadImage(localId) {
ww.getLocalImgData({
localId: localId,
success: function (res) {
const imgElement = document.createElement('img');
// Get correct imageBase64
const localData = res.localData;
let imageBase64 = '';
if (localData.indexOf('data:image') == 0) {
//苹果的直接赋值,默认生成'data:image/jpeg;base64,'的头部拼接
imageBase64 = localData;
} else {
//此处是安卓中的唯一得坑!在拼接前需要对localData进行换行符的全局替换
//此时一个正常的base64图片路径就完美生成赋值到img的src中了
imageBase64 = 'data:image/jpeg;base64,' + localData.replace(/\n/g, '');
}
imgElement.src = imageBase64;
imgElement.alt = 'Response_image';
imgElement.className = 'responsive_image';
$("#imageContainerForDownload").append(imgElement);
},
fail: function (res) {
alert("getLocalImgData fail!" + JSON.stringify(res));
}
})
}