Initial project files: BESCMS full source

This commit is contained in:
bes
2026-08-13 23:37:46 +08:00
parent fa6cddb540
commit 2e26f85723
2166 changed files with 396625 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
<?php
return [
'type' => 'app',
'name' => '微信',
'author' => '迅睿云软件',
'icon' => 'fa fa-weixin',
];
+11
View File
@@ -0,0 +1,11 @@
<?php
if (!method_exists(\Phpcmf\Service::M('table'), 'install_schema')) {
return dr_return_data(0, '请先升级迅睿系统后再安装本插件');
}
if (!dr_is_app('member')) {
return dr_return_data(0, '需要先安装官方版的<用户系统>插件');
}
return dr_return_data(1, 'ok');
+14
View File
@@ -0,0 +1,14 @@
<?php
/**
* 缓存参数配置
*
* 模型名称 => 项目目录
*
**/
return [
'weixin' => 'weixin',
];
+12
View File
@@ -0,0 +1,12 @@
<?php
return [
[
'icon' => 'fa fa-weixin',
'name' => dr_lang('转存为微信内容库'.WEIXIN_MORE_NAME),
'uri' => 'weixin/content/module_add',
'url' => 'javascript:;" onclick="dr_module_send_ajax(\''.dr_url('weixin/content/module_add', ['mid' => '{mid}']).'\')',
],
];
+23
View File
@@ -0,0 +1,23 @@
<?php
return [
/*
[
'name' => '微信客服群发'.WEIXIN_MORE_NAME, // 站点权限是插件的链接名称
'icon' => 'fa fa-weixin', // 图标
'color' => 'green', // 颜色class red green blue
'url' => 'javascript:layer.confirm(\'您确定要推送吗?\', { btn: [\'是\',\'否\'] }, function(){layer.closeAll(); dr_iframe_show(\'\', \''.SELF.'?s=weixin&c=send&m=show_add&mid={mid}&id={cid}\'); });', // 后台链接:对于点击的地址mid是模块目录,cid是内容id
'uri' => 'weixin/send/add', // 对应的uri权限判断,后面章节会介绍权限写法
'field' => '', // 统计数量的字段,填写模块内容的主表字段,只能填写int数字类型的字段
],*/
[
'name' => '微信模板消息'.WEIXIN_MORE_NAME, // 站点权限是插件的链接名称
'icon' => 'fa fa-weixin', // 图标
'color' => 'red', // 颜色class red green blue
'url' => 'javascript:layer.confirm(\'您确定要推送吗?\', { btn: [\'是\',\'否\'] }, function(){ layer.closeAll(); dr_bfb_submit(\'\',\'myform\', \''.SELF.'?s=weixin&c=sendtpl&m=show_add&mid={mid}&id={cid}\') });', // 后台链接:对于点击的地址mid是模块目录,cid是内容id
'uri' => 'weixin/sendtpl/add', // 对应的uri权限判断,后面章节会介绍权限写法
'field' => '', // 统计数量的字段,填写模块内容的主表字段,只能填写int数字类型的字段
'check' => 'is_tpl_use',
],
];
+13
View File
@@ -0,0 +1,13 @@
<?php
/**
* CSRF过滤白名单
*/
return [
'home' => [
'weixin/home/index'
],
];
+123
View File
@@ -0,0 +1,123 @@
<?php
$more = \Phpcmf\Service::L('cache')->get_auth_data('more_weixin', 1);
if (!$more) {
$more = 1;
} else {
// 防止丢失
\Phpcmf\Service::L('cache')->set_auth_data('more_weixin', $more, 1);
}
if (isset($_GET['gzh_id']) && $_GET['gzh_id']) {
$more = intval($_GET['gzh_id']);
}
$data = \Phpcmf\Service::L('cache')->get_file('app_weixin', $more); // 配置
if (!$data) {
$more = 1;
}
define('WEIXIN_MORE_ID', $more);
define('WEIXIN_MORE_NAME', $data ? '【'.$data.'】' : '');
\Phpcmf\Hooks::on('cms_init', function() {
// 微信中访问网站时,未登录时直接授权微信登录
if (IS_API
|| IS_API_HTTP
|| in_array(APP_DIR, ['weixin', 'api', 'member'])
|| in_array(\Phpcmf\Service::L('Router')->class, ['register', 'login', 'api', 'go'])) {
return;
} elseif (!IS_MEMBER && !\Phpcmf\Service::C()->uid) {
\Phpcmf\Service::C()->init_file('weixin');
$config = \Phpcmf\Service::M('Weixin', 'Weixin')->get_config('config'); // 配置
if (isset($config['autologin']) && $config['autologin']
&& strpos((string)$_SERVER['HTTP_USER_AGENT'], 'MicroMessenger')) {
// 公众号内自动登陆
if ($config['autologin'] == 1) {
dr_redirect(SITE_URL.'index.php?s=weixin&c=go&url='.urlencode(FC_NOW_URL));
} else {
// 提示绑定:静默获取openid,已绑定则直接登录,未绑定则提示
$openid = \Phpcmf\Service::L('input')->get_cookie('weixin_gzh_openid');
if (!$openid) {
dr_redirect(SITE_URL.'index.php?s=weixin&c=go&m=check&url='.urlencode(FC_NOW_URL));
} else {
$uid = 0;
$user = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->where('openid', $openid)->getRow();
$oauth = \Phpcmf\Service::M()->table('member_oauth')->where('oauth', 'wechat')->where('oid', $openid)->getRow();
if (!$user || !$user['uid']) {
if ($oauth) {
$uid = $oauth['uid'];
}
} else {
$uid = $user['uid'];
}
if ($uid) {
$member = \Phpcmf\Service::M('member')->member_info($uid);
if ($member) {
$user && \Phpcmf\Service::M()->table(weixin_wxtable('user'))->update($user['id'], ['uid' => $uid]);
$oauth && \Phpcmf\Service::M()->table('member_oauth')->update($oauth['id'], ['uid' => $uid]);
\Phpcmf\Service::M('member')->save_cookie($member, 1);
XR_C()->_msg(1, dr_lang('自动登录成功'), FC_NOW_URL);
} else {
$user && \Phpcmf\Service::M()->table(weixin_wxtable('user'))->update($user['id'], ['uid' => 0]);
$oauth && \Phpcmf\Service::M()->table('member_oauth')->update($oauth['id'], ['uid' => 0]);
$uid = 0;
XR_C()->_msg(0, dr_lang('账号不存在,解绑成功'));
}
}
if (!$uid) {
$text = $config['bang_text'] ? $config['bang_text'] : '您还没有绑定本站账号,是否立即绑定?';
define('MY_WEIXIN_BIND_URL', SITE_URL.'index.php?s=weixin&c=go&url='.urlencode(FC_NOW_URL));
define('MY_WEIXIN_BIND_TEXT', $text);
}
}
}
}
}
});
\Phpcmf\Hooks::on('cms_view_end', function() {
if (!defined('MY_WEIXIN_BIND_URL') || !MY_WEIXIN_BIND_URL) {
return;
} elseif (IS_AJAX || IS_API_HTTP || defined('SC_HTML_FILE')) {
return;
}
$cookieName = 'weixin_bind_prompt';
$today = date('Ymd', SYS_TIME);
if (\Phpcmf\Service::L('input')->get_cookie($cookieName) == $today) {
return;
}
\Phpcmf\Service::L('input')->set_cookie($cookieName, $today, 86400);
$url = MY_WEIXIN_BIND_URL;
$text = json_encode(MY_WEIXIN_BIND_TEXT, JSON_UNESCAPED_UNICODE);
$script = '<script type="text/javascript">'
.'(function(){'
.'var _k='.json_encode($cookieName).',_d='.json_encode($today).';'
.'if(document.cookie.indexOf(_k+"="+_d)>=0){return;}'
.'document.cookie=_k+"="+_d+";path=/;max-age=86400";'
.'if(typeof layer==="undefined"){return;}'
.'layer.confirm('.$text.',{icon:3,shade:0.3,title:dr_lang("提示"),btn:[dr_lang("确定"),dr_lang("取消")]},function(index){'
.'layer.close(index);window.location.href='.json_encode($url).';'
.'});'
.'})();'
.'</script>';
if (ob_get_level() > 0) {
$html = ob_get_clean();
if (stripos($html, '</body>') !== false) {
$html = preg_replace('/<\/body>/i', $script.'</body>', $html, 1);
} else {
$html .= $script;
}
ob_start();
echo $html;
} else {
echo $script;
}
});
+460
View File
@@ -0,0 +1,460 @@
<?php
$this->weixin = $this->get_cache('weixin'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : '')); // 配置
// 获取微信表名
function weixin_wxtable($name, $wxid = WEIXIN_MORE_ID) {
$prefix = $wxid > 1 ? 'more_'.$wxid.'_' : '';
if ($name != 'weixin') {
$name = 'weixin_'.$name;
}
return $prefix.$name;
}
// 获取access_token
function weixin_get_access_token($data = []) {
if (is_array($data) && $data) {
$config = $data;
} elseif ($data == 'update') {
// 重写写入
$config = \Phpcmf\Service::C()->weixin['account'];
} else {
$cache_data = \Phpcmf\Service::L('cache')->get_auth_data('weixin_access_token_'.WEIXIN_MORE_ID, 1, 2200);
if (is_array($cache_data)) {
if ($cache_data['endtime'] && $cache_data['endtime'] > SYS_TIME && $cache_data['access_token']) {
return dr_return_data(1, $cache_data['access_token']);
} elseif (!\Phpcmf\Service::C()->weixin['account']) {
return dr_return_data(0, '未配置微信接入参数');
}
}
$config = \Phpcmf\Service::C()->weixin['account'];
}
if (!$config['appid'] || !$config['appsecret']) {
return dr_return_data(0, 'appid或者appsecret没填写');
}
$result = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$config['appid'].'&secret='.$config['appsecret']);
if (!$result['code']) {
return dr_return_data(0, 'AccessToken'.$result['msg']);
} elseif (!$result['data']['access_token']) {
return dr_return_data(0, 'AccessToken为空,请重试');
}
$result['data']['endtime'] = SYS_TIME + 2360;
$rt = \Phpcmf\Service::L('cache')->set_auth_data('weixin_access_token_'.WEIXIN_MORE_ID, $result['data'], 1);
if (!$rt) {
return dr_return_data(0, 'AccessToken/cache/authcode/目录不可写,文件写入失败');
}
return dr_return_data(1, $result['data']['access_token']);
}
// 小程序获取access_token
function xcx_get_access_token($data = []) {
if (is_array($data) && $data) {
$config = $data;
} elseif ($data == 'update') {
// 重写写入
$config = \Phpcmf\Service::C()->weixin['xcx'];
} else {
$cache_data = \Phpcmf\Service::L('cache')->get_auth_data('xcx_access_token_'.WEIXIN_MORE_ID, 1, 2200);
if (is_array($cache_data)) {
if ($cache_data['endtime'] && $cache_data['endtime'] > SYS_TIME && $cache_data['access_token']) {
return dr_return_data(1, $cache_data['access_token']);
} elseif (!\Phpcmf\Service::C()->weixin['xcx']) {
return dr_return_data(0, '未配置小程序接入参数');
}
}
$config = \Phpcmf\Service::C()->weixin['xcx'];
}
if (!$config['appid'] || !$config['appsecret']) {
return dr_return_data(0, 'appid或者appsecret没填写');
}
$url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $config['appid'] . '&secret=' . $config['appsecret'] . '';
$result = wx_get_https_json_data($url);
if (!$result['code']) {
return dr_return_data(0, 'AccessToken'.$result['msg']);
} elseif (!$result['data']['access_token']) {
return dr_return_data(0, 'AccessToken为空,请重试');
}
$result['data']['endtime'] = SYS_TIME + 2360;
$rt = \Phpcmf\Service::L('cache')->set_auth_data('xcx_access_token_'.WEIXIN_MORE_ID, $result['data'], 1);
if (!$rt) {
return dr_return_data(0, 'AccessToken/cache/authcode/目录不可写,文件写入失败');
}
return dr_return_data(1, $result['data']['access_token']);
}
function ihttp_request($url, $post = '', $extra = array(), $timeout = 60) {
$urlset = parse_url($url);
if (empty($urlset['path'])) {
$urlset['path'] = '/';
}
if (!empty($urlset['query'])) {
$urlset['query'] = "?{$urlset['query']}";
}
if (empty($urlset['port'])) {
$urlset['port'] = $urlset['scheme'] == 'https' ? '443' : '80';
}
if (strexists($url, 'https://') && !extension_loaded('openssl')) {
if (!extension_loaded("openssl")) {
return dr_return_data(0, ' 请开启您PHP环境的openssl');
}
}
if (function_exists('curl_init') && function_exists('curl_exec')) {
$ch = curl_init();
if (!empty($extra['ip'])) {
$extra['Host'] = $urlset['host'];
$urlset['host'] = $extra['ip'];
unset($extra['ip']);
}
curl_setopt($ch, CURLOPT_URL, $urlset['scheme'] . '://' . $urlset['host'] . ($urlset['port'] == '80' ? '' : ':' . $urlset['port']) . $urlset['path'] . $urlset['query']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
//@curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
if ($post) {
if (is_array($post)) {
$filepost = false;
foreach ($post as $name => &$value) {
if (version_compare(phpversion(), '5.6') >= 0 && substr($value, 0, 1) == '@') {
$value = new CURLFile(ltrim($value, '@'));
if (version_compare(phpversion(), '7.4.3') == 0) {
return dr_return_data(0, ' 本功能无法在php7.4.3中运行,请升级到php7.4.3以后的版本');
}
}
if ((is_string($value) && substr($value, 0, 1) == '@') || (class_exists('CURLFile') && $value instanceof CURLFile)) {
$filepost = true;
}
}
if (!$filepost) {
$post = http_build_query($post);
}
}
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
}
if (!empty($GLOBALS['_W']['config']['setting']['proxy'])) {
$urls = parse_url($GLOBALS['_W']['config']['setting']['proxy']['host']);
if (!empty($urls['host'])) {
curl_setopt($ch, CURLOPT_PROXY, "{$urls['host']}:{$urls['port']}");
$proxytype = 'CURLPROXY_' . strtoupper($urls['scheme']);
if (!empty($urls['scheme']) && defined($proxytype)) {
curl_setopt($ch, CURLOPT_PROXYTYPE, constant($proxytype));
} else {
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
}
if (!empty($GLOBALS['_W']['config']['setting']['proxy']['auth'])) {
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['_W']['config']['setting']['proxy']['auth']);
}
}
}
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSLVERSION, 1);
if (defined('CURL_SSLVERSION_TLSv1')) {
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
}
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1');
if (!empty($extra) && is_array($extra)) {
$headers = array();
foreach ($extra as $opt => $value) {
if (strexists($opt, 'CURLOPT_')) {
curl_setopt($ch, constant($opt), $value);
} elseif (is_numeric($opt)) {
curl_setopt($ch, $opt, $value);
} else {
$headers[] = "{$opt}: {$value}";
}
}
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
}
$data = curl_exec($ch);
$status = curl_getinfo($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
curl_close($ch);
if ($errno || empty($data)) {
return dr_return_data(0, '同步出错:'.$error);
} else {
return ihttp_response_parse($data);
}
}
$method = empty($post) ? 'GET' : 'POST';
$fdata = "{$method} {$urlset['path']}{$urlset['query']} HTTP/1.1\r\n";
$fdata .= "Host: {$urlset['host']}\r\n";
if (function_exists('gzdecode')) {
$fdata .= "Accept-Encoding: gzip, deflate\r\n";
}
$fdata .= "Connection: close\r\n";
if (!empty($extra) && is_array($extra)) {
foreach ($extra as $opt => $value) {
if (!strexists($opt, 'CURLOPT_')) {
$fdata .= "{$opt}: {$value}\r\n";
}
}
}
$body = '';
if ($post) {
if (is_array($post)) {
$body = http_build_query($post);
} else {
$body = urlencode($post);
}
$fdata .= 'Content-Length: ' . strlen($body) . "\r\n\r\n{$body}";
} else {
$fdata .= "\r\n";
}
if ($urlset['scheme'] == 'https') {
$fp = fsockopen('ssl://' . $urlset['host'], $urlset['port'], $errno, $error);
} else {
$fp = fsockopen($urlset['host'], $urlset['port'], $errno, $error);
}
stream_set_blocking($fp, true);
stream_set_timeout($fp, $timeout);
if (!$fp) {
return dr_return_data(0, '同步出错:'.$error);
} else {
fwrite($fp, $fdata);
$content = '';
while (!feof($fp))
$content .= fgets($fp, 512);
fclose($fp);
return ihttp_response_parse($content, true);
}
}
function ihttp_response_parse($data, $chunked = false) {
$rlt = array();
$headermeta = explode('HTTP/', $data);
if (count($headermeta) > 2) {
$data = 'HTTP/' . array_pop($headermeta);
}
$pos = strpos($data, "\r\n\r\n");
$split1[0] = substr($data, 0, $pos);
$split1[1] = substr($data, $pos + 4, strlen($data));
$split2 = explode("\r\n", $split1[0], 2);
preg_match('/^(\S+) (\S+) (.*)$/', $split2[0], $matches);
$rlt['code'] = $matches[2];
$rlt['status'] = $matches[3];
$rlt['responseline'] = $split2[0];
$header = explode("\r\n", $split2[1]);
$isgzip = false;
$ischunk = false;
foreach ($header as $v) {
$pos = strpos($v, ':');
$key = substr($v, 0, $pos);
$value = trim(substr($v, $pos + 1));
if (is_array($rlt['headers'][$key])) {
$rlt['headers'][$key][] = $value;
} elseif (!empty($rlt['headers'][$key])) {
$temp = $rlt['headers'][$key];
unset($rlt['headers'][$key]);
$rlt['headers'][$key][] = $temp;
$rlt['headers'][$key][] = $value;
} else {
$rlt['headers'][$key] = $value;
}
if(!$isgzip && strtolower($key) == 'content-encoding' && strtolower($value) == 'gzip') {
$isgzip = true;
}
if(!$ischunk && strtolower($key) == 'transfer-encoding' && strtolower($value) == 'chunked') {
$ischunk = true;
}
}
if($chunked && $ischunk) {
$rlt['content'] = ihttp_response_parse_unchunk($split1[1]);
} else {
$rlt['content'] = $split1[1];
}
if($isgzip && function_exists('gzdecode')) {
$rlt['content'] = gzdecode($rlt['content']);
}
$rlt['meta'] = $data;
if($rlt['code'] == '100') {
return ihttp_response_parse($rlt['content']);
}
$data = json_decode($rlt['content'], true);
if (!$data) {
if($rlt['code'] != '200' && $rlt['status']) {
return dr_return_data(0, $rlt['status']);
}
return dr_return_data(0, $rlt['content'].'不是一个有效的json数据');
} elseif (isset($data['errcode']) && $data['errcode']) {
return dr_return_data(0, '错误代码('.dr_weixin_error_msg($data['errcode']).'):'.$data['errmsg']);
}
return dr_return_data(1, 'ok', $data);
}
function strexists($string, $find) {
return !(strpos($string, $find) === FALSE);
}
/**
*
* 通过code从工作平台获取openid机器access_token
* @param string $code 微信跳转回来带上的code
*
* @return openid
*/
function weixin_GetOpenidFromMp($code)
{
$url = weixin_CreateOauthUrlForOpenid($code);
//初始化curl
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//运行curl,结果以jason形式返回
$res = curl_exec($ch);
curl_close($ch);
//取出openid
$data = json_decode($res,true);
$openid = $data['openid'];
return $openid;
}
/**
*
* 构造获取code的url连接
* @param string $redirectUrl 微信服务器回跳的url,需要url编码
*
* @return 返回构造好的url
*/
function weixin_CreateOauthUrlForCode($redirectUrl)
{
$wx = \Phpcmf\Service::C()->get_cache('weixin'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : '')); // 配置
$urlObj["appid"] = $wx['account']['appid'];
$urlObj["redirect_uri"] = "$redirectUrl";
$urlObj["response_type"] = "code";
$urlObj["scope"] = "snsapi_base";
$urlObj["state"] = "STATE"."#wechat_redirect";
$bizString = weixin_ToUrlParams($urlObj);
return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
}
/**
*
* 构造获取open和access_toke的url地址
* @param string $code,微信跳转带回的code
*
* @return 请求的url
*/
function weixin_CreateOauthUrlForOpenid($code)
{
$wx = \Phpcmf\Service::C()->get_cache('weixin'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : '')); // 配置
$urlObj["appid"] = $wx['account']['appid'];
$urlObj["secret"] = $wx['account']['appsecret'];
$urlObj["code"] = $code;
$urlObj["grant_type"] = "authorization_code";
$bizString = weixin_ToUrlParams($urlObj);
return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
}
/**
*
* 拼接签名字符串
* @param array $urlObj
*
* @return 返回已经拼接好的字符串
*/
function weixin_ToUrlParams($urlObj)
{
$buff = "";
foreach ($urlObj as $k => $v)
{
if($k != "sign"){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
// 从url获取json数据
function wx_get_https_json_data($url, $ct = 0) {
if (!$url) {
return dr_return_data(0, 'url为空');
}
$response = dr_catcher_data($url);
$data = json_decode($response, true);
if (!$data) {
return dr_return_data(0, var_export($response, true).' 不是一个有效的json数据');
} elseif (isset($data['errcode']) && $data['errcode']) {
if ($data['errcode'] == '40001' && $ct == 0 && strpos($url, 'access_token=')) {
// 重新获取token
list($a, $b) = explode('access_token=', $url);
if (strpos($b, '&') !== false) {
list($b) = explode('&', $b);
}
$rt = weixin_get_access_token('update');
if ($rt['code']) {
return wx_get_https_json_data(str_replace($b, $rt['msg'], $url), 1);
}
}
return dr_return_data(0, '错误代码('.$data['errcode'].'):'.$data['errmsg']);
}
return dr_return_data(1, 'ok', $data);
}
// 从url获取json数据
function wx_post_https_json_data($url, $param = [], $ct = 0) {
$rt = dr_post_json_data($url, json_encode($param, JSON_UNESCAPED_UNICODE));
if ($rt['code']) {
if (isset($rt['data']['errcode']) && $rt['data']['errcode']) {
if ($rt['data']['errcode'] == '40001' && $ct == 0 && strpos($url, 'access_token=')) {
// 重新获取token
list($a, $b) = explode('access_token=', $url);
if (strpos($b, '&') !== false) {
list($b) = explode('&', $b);
}
$rt = weixin_get_access_token('update');
if ($rt['code']) {
return wx_post_https_json_data(str_replace($b, $rt['msg'], $url), $param, 1);
}
}
return dr_return_data(0, '错误代码('.dr_weixin_error_msg($rt['data']['errcode']).'):'.$rt['data']['errmsg']);
}
}
return $rt;
}
// 微信端的错误码转
function dr_weixin_error_msg($code) {
if ($code == '40001') {
// 清除掉token
\Phpcmf\Service::L('cache')->del_auth_data('weixin_access_token_'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : ''), 1);
}
return $code;
}
+224
View File
@@ -0,0 +1,224 @@
<?php
$rt = \Phpcmf\Service::M('table')->install_schema([
'tables' => [
'app_weixin' => [
'comment' => '多公众号表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'name' => 'varchar(200) NOT NULL COMMENT \'公众号名称\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
],
],
'weixin' => [
'comment' => '微信配置',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'Id\'',
'name' => 'varchar(100) NOT NULL COMMENT \'表名称\'',
'value' => 'text NOT NULL COMMENT \'字段配置项目\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'UNIQUE KEY `name` (`name`)',
],
],
'weixin_follow' => [
'comment' => '微信粉丝同步表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'openid' => 'varchar(255) NOT NULL COMMENT \'唯一id\'',
'status' => 'tinyint(1) NOT NULL',
'uid' => 'int(10) NOT NULL',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'KEY `uid` (`uid`)',
'KEY `status` (`status`)',
'KEY `openid` (`openid`)',
],
],
'weixin_group' => [
'comment' => '微信粉丝分组表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'tag' => 'int(10) NOT NULL COMMENT \'微信TagId\'',
'name' => 'varchar(100) NOT NULL COMMENT \'标签名称\'',
'count' => 'int(10) NOT NULL COMMENT \'粉丝人数\'',
'groupid' => 'int(10) NOT NULL COMMENT \'用户组id\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'KEY `tag` (`tag`)',
'KEY `groupid` (`groupid`)',
],
],
'weixin_user' => [
'comment' => '微信粉丝表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'uid' => 'int(10) unsigned DEFAULT NULL COMMENT \'会员id\'',
'username' => 'varchar(100) NOT NULL COMMENT \'会员名\'',
'groupids' => 'varchar(100) NOT NULL COMMENT \'标签组id值\'',
'openid' => 'varchar(50) NOT NULL COMMENT \'唯一id\'',
'nickname' => 'varchar(255) NOT NULL COMMENT \'微信昵称\'',
'sex' => 'tinyint(1) unsigned DEFAULT NULL COMMENT \'性别\'',
'city' => 'varchar(30) DEFAULT NULL COMMENT \'城市\'',
'country' => 'varchar(30) DEFAULT NULL COMMENT \'国家\'',
'province' => 'varchar(30) DEFAULT NULL COMMENT \'省\'',
'headimgurl' => 'varchar(255) DEFAULT NULL COMMENT \'头像地址\'',
'unionid' => 'varchar(255) DEFAULT NULL COMMENT \'绑定账号\'',
'remark' => 'varchar(255) DEFAULT NULL COMMENT \'对粉丝的备注\'',
'subscribe' => 'int(10) unsigned NOT NULL COMMENT \'关注时间\'',
'subscribe_time' => 'int(10) unsigned NOT NULL COMMENT \'最近时间\'',
'content' => 'text NOT NULL COMMENT \'字段\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'UNIQUE KEY `openid` (`openid`)',
'KEY `subscribe` (`subscribe`)',
'KEY `subscribe_time` (`subscribe_time`)',
],
],
'weixin_menu' => [
'comment' => '微信自定义菜单表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'pid' => 'int(10) NOT NULL COMMENT \'父id\'',
'name' => 'varchar(255) NOT NULL COMMENT \'菜单名称\'',
'type' => 'varchar(20) NOT NULL COMMENT \'菜单类型\'',
'value' => 'text NOT NULL COMMENT \'执行值\'',
'displayorder' => 'int(10) NOT NULL COMMENT \'排序值\'',
'gid' => 'int(10) NOT NULL COMMENT \'标签组id\'',
'menuid' => 'int(10) NOT NULL COMMENT \'个性菜单id\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'KEY `pid` (`pid`)',
'KEY `displayorder` (`displayorder`)',
'KEY `gid` (`gid`)',
],
],
'weixin_content' => [
'comment' => '微信素材内容表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'tid' => 'varchar(20) NOT NULL COMMENT \'素材类型\'',
'title' => 'varchar(255) NOT NULL COMMENT \'标题\'',
'content' => 'text NOT NULL COMMENT \'内容值数组\'',
'media_id' => 'varchar(255) NOT NULL COMMENT \'微信media_id\'',
'publish_id' => 'varchar(255) NOT NULL COMMENT \'publish_id\'',
'article_id' => 'varchar(255) NOT NULL COMMENT \'article_id\'',
'status' => 'tinyint(1) unsigned DEFAULT NULL COMMENT \'\'',
'nums' => 'tinyint(2) unsigned DEFAULT NULL COMMENT \'\'',
'inputtime' => 'int(10) NOT NULL COMMENT \'录入时间\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'KEY `inputtime` (`inputtime`)',
],
],
'weixin_media_id' => [
'comment' => '微信素材多媒体id表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'file' => 'varchar(255) NOT NULL COMMENT \'文件编码\'',
'media_id' => 'varchar(255) NOT NULL COMMENT \'微信media_id\'',
'url' => 'varchar(255) NOT NULL COMMENT \'对应地址\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'KEY `file` (`file`)',
],
],
'weixin_send' => [
'comment' => '微信客服消息发布表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'cid' => 'int(10) NOT NULL COMMENT \'cid\'',
'openid' => 'varchar(255) NOT NULL COMMENT \'openid\'',
'content' => 'text NOT NULL COMMENT \'内容值数组\'',
'status' => 'tinyint(1) unsigned DEFAULT NULL COMMENT \'状态1成功,2失败,0未发送\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'KEY `cid` (`cid`)',
],
],
'weixin_message' => [
'comment' => '微信消息记录表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'tid' => 'varchar(20) NOT NULL COMMENT \'消息类型\'',
'userid' => 'int(10) NOT NULL COMMENT \'用户id\'',
'openid' => 'varchar(255) NOT NULL COMMENT \'openid\'',
'nickname' => 'varchar(255) NOT NULL COMMENT \'昵称\'',
'headimgurl' => 'varchar(255) NOT NULL COMMENT \'头像\'',
'content' => 'text NOT NULL COMMENT \'消息内容\'',
'file' => 'text NOT NULL COMMENT \'xiazia\'',
'status' => 'tinyint(1) unsigned DEFAULT NULL COMMENT \'状态1更新,0未更新\'',
'inputtime' => 'int(10) NOT NULL COMMENT \'录入时间\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'KEY `openid` (`openid`)',
'KEY `userid` (`userid`)',
'KEY `nickname` (`nickname`)',
'KEY `inputtime` (`inputtime`)',
],
],
'weixin_template' => [
'comment' => '微信模板消息记录表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'title' => 'varchar(200) NOT NULL COMMENT \'主题\'',
'groupid' => 'int(10) NOT NULL COMMENT \'发送标签组\'',
'counts' => 'int(10) NOT NULL COMMENT \'发送数\'',
'content' => 'text NOT NULL COMMENT \'消息内容\'',
'template' => 'varchar(200) NOT NULL COMMENT \'模板ID\'',
'url' => 'varchar(200) NOT NULL COMMENT \'对应url\'',
'color' => 'varchar(200) NOT NULL COMMENT \'主题颜色\'',
'inputtime' => 'int(10) NOT NULL COMMENT \'录入时间\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'KEY `inputtime` (`inputtime`)',
],
],
'weixin_reply' => [
'comment' => '微信素材自动回复表',
'drop' => true,
'fields' => [
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'tid' => 'varchar(20) NOT NULL COMMENT \'素材类型\'',
'title' => 'varchar(255) NOT NULL COMMENT \'规则名称\'',
'keyword' => 'varchar(255) NOT NULL COMMENT \'关键字\'',
'content' => 'text NOT NULL COMMENT \'内容值数组\'',
'counts' => 'int(10) NOT NULL COMMENT \'命中次数\'',
'displayorder' => 'int(10) NOT NULL COMMENT \'权重值\'',
'updatetime' => 'int(10) NOT NULL COMMENT \'最近命中时间\'',
],
'indexes' => [
'PRIMARY KEY (`id`)',
'KEY `keyword` (`keyword`)',
'KEY `displayorder` (`displayorder`)',
'KEY `updatetime` (`updatetime`)',
],
],
],
'seeds' => [],
]);
if (empty($rt['code'])) {
log_message('error', 'Weixin install_schema: '.($rt['msg'] ?? ''));
}
+121
View File
@@ -0,0 +1,121 @@
<?php
/**
* 菜单配置
*/
return [
'admin' => [
'app-weixin' => [
'name' => '微信',
'icon' => 'fa fa-weixin',
'left' => [
'app-weixin-home' => [
'name' => '系统设置',
'icon' => 'fa fa-home',
'link' => [
[
'name' => '公众号',
'icon' => 'fa fa-weixin',
'uri' => 'weixin/account/index',
],
[
'name' => '小程序',
'icon' => 'fa fa-link',
'uri' => 'weixin/xcx/index',
],
[
'name' => '系统配置',
'icon' => 'fa fa-cog',
'uri' => 'weixin/config/index',
],
[
'name' => '菜单管理',
'icon' => 'fa fa-list',
'uri' => 'weixin/menu/index',
],
[
'name' => '请求日志',
'icon' => 'fa fa-shield',
'uri' => 'weixin/log/index',
],
[
'name' => '更多公众号',
'icon' => 'fa fa-users',
'uri' => 'weixin/more/index',
],
],
],
'app-weixin-content' =>[
'name' => '公众号内容',
'icon' => 'fa fa-th-large',
'link' => [
[
'name' => '内容管理',
'icon' => 'fa fa-edit',
'uri' => 'weixin/content/index',
],
[
'name' => '自动回复',
'icon' => 'fa fa-comments',
'uri' => 'weixin/reply/index',
],
]
],
'app-weixin-fans' =>[
'name' => '公众号粉丝',
'icon' => 'fa fa-user',
'link' => [
[
'name' => '粉丝管理',
'icon' => 'fa fa-user',
'uri' => 'weixin/user/index',
],
[
'name' => '用户标签组',
'icon' => 'fa fa-users',
'uri' => 'weixin/group/index',
],
]
],
'app-weixin-message' =>[
'name' => '公众号消息',
'icon' => 'fa fa-envelope',
'link' => [
[
'name' => '消息记录',
'icon' => 'fa fa-envelope',
'uri' => 'weixin/message/index',
],
[
'name' => '客服群发',
'icon' => 'fa fa-envelope-o',
'uri' => 'weixin/send/index',
],
[
'name' => '高级群发',
'icon' => 'fa fa-volume-up',
'uri' => 'weixin/sendall/index',
],
[
'name' => '模板群发',
'icon' => 'fa fa-puzzle-piece',
'uri' => 'weixin/template/index',
],
[
'name' => '内容模板群发设置',
'icon' => 'fa fa-th-large',
'uri' => 'weixin/sendtpl/index',
],
]
],
],
],
],
];
+12
View File
@@ -0,0 +1,12 @@
<?php
/*
* 自定义通知类型
* */
return [
'name' => '微信公众号',
'file' => 'weixin',
'help' => 'javascript:dr_help(481);',
'height' => '200',
'class' => 'weixin',
];
+4
View File
@@ -0,0 +1,4 @@
<?php
// 加载主程序的路由
require COREPATH.'Config/Routes.php';
+19
View File
@@ -0,0 +1,19 @@
<?php
$t = \Phpcmf\Service::M('table');
$m = \Phpcmf\Service::M();
foreach ([
'app_weixin',
'weixin',
'weixin_follow',
'weixin_group',
'weixin_user',
'weixin_menu',
'weixin_content',
'weixin_media_id',
'weixin_send',
'weixin_message',
'weixin_template',
'weixin_reply',
] as $name) {
$t->drop_table($m->dbprefix($name), true);
}
+23
View File
@@ -0,0 +1,23 @@
<?php
/**
* 更新数据结构
*/
$prefix = \Phpcmf\Service::M()->prefix;
$table = $prefix.'weixin_content';
$t = \Phpcmf\Service::M('table');
$m = \Phpcmf\Service::M();
if ($m->is_table_exists($table)) {
if (!$m->is_field_exists($table, 'nums')) {
$t->add_field($table, 'nums', 'tinyint(2)', 'DEFAULT \'0\'', '');
}
if (!$m->is_field_exists($table, 'status')) {
$t->add_field($table, 'status', 'tinyint(2)', 'DEFAULT \'0\'', '');
}
if (!$m->is_field_exists($table, 'publish_id')) {
$t->add_field($table, 'publish_id', 'varchar(255)', 'DEFAULT \'\'', '');
}
if (!$m->is_field_exists($table, 'article_id')) {
$t->add_field($table, 'article_id', 'varchar(255)', 'DEFAULT \'\'', '');
}
}
+13
View File
@@ -0,0 +1,13 @@
<?php
return [
'id' => '226',
'vip' => '',
'cms' => '4.7.3',
'version' => '5.42',
'license' => '375C71349B295FBE2DCDCA9206F20A1703',
'updatetime' => '2026-06-26 15:12:04',
'downtime' => '2026-08-08 00:54:28',
];
@@ -0,0 +1,87 @@
<?php namespace Phpcmf\Controllers\Admin;
class Account extends \Phpcmf\Common
{
public function __construct() {
parent::__construct();
if (IS_ADMIN && SITE_ID > 1) {
$this->_admin_msg(0, '请登录主站账号管理微信插件');
}
\Phpcmf\Service::V()->assign('menu', \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME. '账号接入' => [APP_DIR.'/account/index', 'fa fa-weixin'],
'help' => [808],
]
));
}
public function gz_index() {
$rt = weixin_get_access_token();
if ($rt['code']) {
$access_token = $rt['msg'];
$param = [
'expire_seconds' => 2592000,
'action_name' => 'QR_STR_SCENE',
'action_info' => array(
'scene' => array(
'scene_str' => 'login-guanzhu',
),
)
];
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=' . $access_token,
$param
);
if (!$rt['code']) {
$this->_admin_msg(0, '生成二维码失败');
}
$url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=' . $rt['data']['ticket'];
echo '<div style="text-align: center"><img src="'.$url.'"></div>';exit;
} else {
$this->_admin_msg(0, $rt['msg']);
}
}
public function index() {
$page = intval(\Phpcmf\Service::L('Input')->get('page'));
$data = \Phpcmf\Service::M('Weixin', 'Weixin')->get_config('account');
if (IS_AJAX_POST) {
$post = \Phpcmf\Service::L('Input')->post('data');
$rt = \Phpcmf\Service::M('Weixin', 'Weixin')->save_config('account', $post);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
\Phpcmf\Service::M('Weixin', 'Weixin')->cache();
$rt = weixin_get_access_token($post);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$this->_json(1, dr_lang('操作成功'));
}
$rt = weixin_get_access_token();
$access_tocken = $rt['code'] ? '': $rt['msg'];
\Phpcmf\Service::V()->assign([
'data' => $data,
'page' => $page,
'form' => dr_form_hidden(['page' => $page]),
'access_tocken' => $access_tocken,
]);
\Phpcmf\Service::V()->display('account_index.html');
}
}
@@ -0,0 +1,59 @@
<?php namespace Phpcmf\Controllers\Admin;
class Api extends \Phpcmf\Common
{
/**
* 生成安全码
*/
public function token() {
echo 'PHPCMF'.strtoupper(substr((md5(SYS_TIME)), rand(0, 10), 13));exit;
}
/**
* 生成来路随机字符
*/
public function asckey() {
$s = strtoupper(base64_encode(md5(SYS_TIME).md5(rand(0, 2015).md5(rand(0, 2015)))).md5(rand(0, 2009)));
echo substr('PHPCMF'.str_replace('=', '', $s), 0, 43);exit;
}
// 选择素材
public function content() {
// 强制将模板设置为后台
\Phpcmf\Service::V()->admin();
// 登陆判断
!$this->uid && $this->_json(0, dr_lang('会话超时,请重新登录'));
$builder = \Phpcmf\Service::M()->db->table(weixin_wxtable('content'));
// 搜索结果显示条数
$limit = (int)$_GET['limit'];
$limit = $limit ? $limit : 20;
$data = $_GET;
if ($data['search'] && isset($data['keyword']) && $data['keyword']) {
$builder->like('title', urldecode($data['keyword']));
}
$list = $builder->limit($limit)->orderBy('inputtime DESC')->get()->getResultArray();
\Phpcmf\Service::V()->assign(array(
'list' => $list,
'param' => $data,
'search' => dr_form_search_hidden(['search' => 1, 'limit' => $limit]),
'content_type' => [
'index' => '图文',
'image' => '图片',
'voice' => '语音',
'video' => '视频',
],
));
\Phpcmf\Service::V()->display('api_content.html');exit;
}
}
@@ -0,0 +1,36 @@
<?php namespace Phpcmf\Controllers\Admin;
// 已发布内容
class Article extends \Phpcmf\Common
{
public function __construct() {
parent::__construct();
\Phpcmf\Service::V()->assign('menu', \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME.'已发布内容' => [APP_DIR.'/article/index', 'fa fa-envelope-o'],
]
));
}
public function index() {
$rt = weixin_get_access_token();
if (!$rt['code']) {
$this->_admin_msg(0, $rt['msg']);
}
$access_token = $rt['msg'];
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/freepublish/batchget?access_token='.$access_token,
[
'offset' => 0,
'count' => 2,
'no_content' => 0,
]
);
var_dump($rt);
}
}
@@ -0,0 +1,53 @@
<?php namespace Phpcmf\Controllers\Admin;
class Config extends \Phpcmf\Common
{
public function __construct() {
parent::__construct();
\Phpcmf\Service::V()->assign('menu', \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME.'系统配置' => [APP_DIR.'/config/index', 'fa fa-cog'],
]
));
}
public function index() {
$page = intval(\Phpcmf\Service::L('Input')->get('page'));
$data = \Phpcmf\Service::M('Weixin', 'Weixin')->get_config('config');
if (IS_AJAX_POST) {
$post = \Phpcmf\Service::L('Input')->post('data');
$rt = \Phpcmf\Service::M('Weixin', 'Weixin')->save_config('config', $post);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$this->_json(1, dr_lang('操作成功'));
}
$module = [];
$local = dr_dir_map(APPSPATH, 1); // 搜索本地模块
foreach ($local as $dir) {
if (is_file(APPSPATH.$dir.'/Config/App.php')) {
$key = strtolower($dir);
$cfg = require APPSPATH.$dir.'/Config/App.php';
if ($cfg['type'] == 'module') {
$cfg['dirname'] = $key;
$module[$key] = $cfg;
}
}
}
\Phpcmf\Service::V()->assign([
'data' => $data,
'page' => $page,
'form' => dr_form_hidden(['page' => $page]),
'module' => $module,
]);
\Phpcmf\Service::V()->display('config_index.html');
}
}
@@ -0,0 +1,321 @@
<?php namespace Phpcmf\Controllers\Admin;
// 草稿箱
class Content extends \Phpcmf\Table
{
private $tid;
public function __construct()
{
parent::__construct();
// 支持附表存储
$this->is_data = 0;
// 表单显示名称
$this->name = dr_lang('内容库');
// 字段划分
$j = 0;
$field = [];
for ($i = 1; $i<=9; $i++) {
$field['title_'.$i] = array(
'ismain' => 0,
'displayorder' => $j,
'name' => dr_lang('标题'),
'fieldname' => 'title_'.$i,
'fieldtype' => 'Text',
'setting' => array(
'option' => array(
'width' => '100%',
),
'validate' => array(
'formattr' => ' onblur="dr_wx_show_title('.$i.');"',
)
)
);
$j++;
$field['author_'.$i] = array(
'ismain' => 0,
'displayorder' => $j,
'name' => dr_lang('作者'),
'fieldname' => 'author_'.$i,
'fieldtype' => 'Text',
'setting' => array(
'option' => array(
'width' => 200,
)
)
);
$j++;
$field['thumb_'.$i] = array(
'ismain' => 0,
'displayorder' => $j,
'name' => dr_lang('封面'),
'fieldtype' => 'File',
'fieldname' => 'thumb_'.$i,
'setting' => array(
'option' => array(
'ext' => 'jpg,png,jpeg,gif',
'size' => 20,
),
)
);
$j++;
$field['description_'.$i] = array(
'ismain' => 0,
'displayorder' => $j,
'name' => dr_lang('描述'),
'fieldname' => 'description_'.$i,
'fieldtype' => 'Textarea',
'setting' => array(
'option' => array(
'width' => '90%',
'height' => 70,
),
'validate' => array(
'xss' => 1,
),
)
);
$j++;
$field['content_'.$i] = array(
'ismain' => 0,
'displayorder' => $j,
'name' => dr_lang('内容'),
'fieldtype' => 'Ueditor',
'fieldname' => 'content_'.$i,
'setting' => array(
'option' => array(
'mode' => 1,
'height' => 300,
'width' => '100%',
'mini' => 1,
),
'validate' => [
'tips' => '内容中的图片一定不要太大,否则无法同步到微信服务器'
]
)
);
$j++;
$field['url_'.$i] = array(
'ismain' => 0,
'displayorder' => $j,
'name' => dr_lang('原文地址'),
'fieldname' => 'url_'.$i,
'fieldtype' => 'Text',
'setting' => array(
'option' => array(
'width' => '100%',
)
)
);
}
// 初始化数据表
$this->_init([
'table' => weixin_wxtable('content'),
'field' => $field,
'order_by' => 'inputtime desc',
'date_field' => 'inputtime',
]);
\Phpcmf\Service::V()->assign([
'menu' => \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME.'内容库' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/index', 'fa fa-th-list'],
'添加' => [''.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/add', 'fa fa-plus'],
'修改' => ['hide:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/edit', 'fa fa-plus'],
'清空附件media_id' => ['ajax:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/clear_del', 'fa fa-file'],
]
),
'myfieldinfo' => $field,
'zt' => [
0 => '发布成功',
1 => '发布中',
2 => '原创失败',
3 => '常规失败',
4 => '平台审核不通过',
5 => '成功后用户删除所有文章',
6 => '成功后系统封禁所有文章',
]
]);
}
public function clear_del() {
\Phpcmf\Service::M()->table(weixin_wxtable('media_id'))->clear_all();
$this->_json(1, '全部附件media_id记录被清空');
}
public function index() {
$where = (string)$_GET['keyword'] ? '`title` LIKE "%'.$_GET['keyword'].'%"' : '';
\Phpcmf\Service::M()->set_where_list($where);
list($tpl) = $this->_list();
\Phpcmf\Service::V()->display($tpl);
}
public function add() {
list($tpl) = $this->_Post();
\Phpcmf\Service::V()->display($tpl);
}
public function edit() {
list($tpl) = $this->_Post(intval(\Phpcmf\Service::L('Input')->get('id')));
\Phpcmf\Service::V()->display($tpl);
}
// 转存素材库
public function module_add() {
$mid = dr_safe_filename($_GET['mid']);
$row = \Phpcmf\Service::M('Module')->table('module')->where('dirname', $mid)->getRow();
if (!$row) {
$this->_json(0, dr_lang('此模块[%s]未安装', $mid));
}
$this->_module_init($mid);
$ids = \Phpcmf\Service::L('input')->get('ids');
if (!$ids) {
$this->_json(0, dr_lang('所选内容不存在'));
} elseif (dr_count($ids) > 9) {
$this->_json(0, dr_lang('微信素材超过9条数据'));
}
$n = 1;
$save = [
'tid' => 'index',
'title' => 'index',
'content' => [],
'media_id' => '',
'inputtime' => SYS_TIME,
];
$save['media_id'] = '';
$save['publish_id'] = '';
$save['article_id'] = '';
$save['status'] = 1;
foreach ($ids as $id) {
$data = $this->content_model->get_data($id);
if ($data) {
$save['content']['title_'.$n] = $data['title'];
$save['content']['thumb_'.$n] = $data['thumb'];
$save['content']['author_'.$n] = $data['author'];
$save['content']['content_'.$n] = $data['content'];
$save['content']['description_'.$n] = $data['description'];
$save['content']['url_'.$n] = dr_url_prefix($data['url'], $mid);
$n++;
}
}
$save['nums'] = $n;
$save['title'] = $save['content']['title_1'];
$save['content'] = dr_array2string($save['content']);
\Phpcmf\Service::M()->table(weixin_wxtable('content'))->insert($save);
$this->_json(1, '存储成功,请到微信草稿中编辑发布');
}
/**
* 获取内容
* */
protected function _Data($id = 0) {
$data = parent::_Data($id);
if (!$data) {
return [];
}
$value = dr_string2array($data['content']);
return $value;
}
// 格式化保存数据
protected function _Format_Data($id, $data, $old) {
!$data[0]['title_1'] && $this->_json(0, '第一个标题不能为空', ['field' => 'title_1']);
!$data[0]['content_1'] && $this->_json(0, '第一个内容不能为空', ['field' => 'content_1']);
$nums = 0;
for ($i = 1; $i<=9; $i++) {
if ($data[0]['title_'.$i]) {
$nums++;
} else {
break;
}
}
$save = [
'tid' => '',
'nums' => $nums,
'title' => $data[0]['title_1'],
'content' => dr_array2string($data[0]),
'inputtime' => SYS_TIME,
];
// 每次修改媒体id重置
$save['media_id'] = '';
$save['publish_id'] = '';
$save['article_id'] = '';
$save['status'] = 1;
return $save;
}
// 保存后
protected function _Save($id = 0, $data = [], $old = [], $before = null, $after = null) {
return parent::_Save($id, $data, $old, $before, function($id, $data, $old) {
$content = dr_string2array($data['content']);
for ($i = 1; $i <=9; $i++) {
if (!$content['url_'.$i]) {
$content['url_'.$i] = SITE_URL.'index.php?s=weixin&c=show&id='.$id.'&p='.$i;
}
}
\Phpcmf\Service::M()->table(weixin_wxtable('content'))->update($id, [
'content' => dr_array2string($content),
]);
});
}
//
public function del() {
$this->_Del(
\Phpcmf\Service::L('Input')->get_post_ids(),
null,
null,
\Phpcmf\Service::M()->dbprefix($this->init['table'])
);
}
//
public function sync_add() {
$ids = \Phpcmf\Service::L('Input')->get_post_ids();
if (!$ids) {
$this->_json(0, dr_lang('所选数据不存在'));
}
$rt = weixin_get_access_token();
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$access_token = $rt['msg'];
$rows = \Phpcmf\Service::M()->init($this->init)->where_in('id', $ids)->getAll();
if (!$rows) {
$this->_json(0, dr_lang('所选数据不存在'));
}
foreach ($rows as $t) {
if (!$t['article_id']) {
$rt = \Phpcmf\Service::M('Weixin', 'Weixin')->sync_content($access_token, $t);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
}
}
$this->_json(1, '提交成功,等待平台审核');
}
}
@@ -0,0 +1,117 @@
<?php namespace Phpcmf\Controllers\Admin;
// 粉丝组
class Group extends \Phpcmf\Table
{
public function __construct()
{
parent::__construct();
\Phpcmf\Service::V()->assign([
'menu' => \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME.'用户标签' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/index', 'fa fa-users'],
'添加' => ['add:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/add', 'fa fa-plus', null, '33%'],
'从服务端获取分组' => ['ajax:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/down_add', 'fa fa-refresh'],
]
),
]);
// 支持附表存储
$this->is_data = 0;
// 表单显示名称
$this->name = dr_lang('微信用户标签');
// 初始化数据表
$this->_init([
'table' => weixin_wxtable('group'),
'order_by' => 'id asc',
]);
}
public function down_add() {
$rt = \Phpcmf\Service::M('User', 'weixin')->down_group();
$rt['code'] ? $this->_json(1, '操作成功') : $this->_json(0, $rt['msg']);
}
public function index() {
$this->_list([], -1);
\Phpcmf\Service::V()->display('group_index.html');
}
public function add() {
$this->_Post();
\Phpcmf\Service::V()->display('group_add.html');exit;
}
public function edit() {
$this->_Post(intval(\Phpcmf\Service::L('Input')->get('id')));
\Phpcmf\Service::V()->display('group_add.html');exit;
}
// 删除个性菜单
public function menu_del() {
$gid = intval($_GET['gid']);
!$gid && $this->_json(0, '参数未定义');
$menu = \Phpcmf\Service::M()->table(weixin_wxtable('menu'))->where('gid', $gid)->getRow();
!$menu && $this->_json(0, '菜单不存在');
$at = weixin_get_access_token();
if (!$at['code']) {
$this->_json(0, $at['msg']);
}
$data = array('menuid'=> $menu['menuid']);
$rt = wx_post_https_json_data('https://api.weixin.qq.com/cgi-bin/menu/delconditional?access_token='.$at['msg'], $data);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
\Phpcmf\Service::M()->db->table(weixin_wxtable('menu'))->where('gid', $gid)->delete();
$this->_json(1, '操作成功');
}
// 格式化保存数据
protected function _Format_Data($id, $data, $old) {
$data['count'] = intval($old['count']);
!$data['name'] && $this->_json(0, '用户标签名称必须填写', ['field' => 'name']);
if ($id) {
// 修改标签
if ($data['name'] != $old['name'] && $old['tag']) {
$rt = \Phpcmf\Service::M('User', 'weixin')->edit_group($data['tag'], $data['name']);
!$rt['code'] && $this->_json(0, $rt['msg']);
}
unset($data['tag']);
} else {
// 创建标签
$rt = \Phpcmf\Service::M('User', 'weixin')->add_group($data['name']);
!$rt['code'] && $this->_json(0, $rt['msg']);
$data['tag'] = $rt['code'];
}
$data['groupid'] = intval($data['groupid']);
return $data;
}
// 后台删除表单内容
public function del() {
$this->_Del(
\Phpcmf\Service::L('Input')->get_post_ids(),
function ($rows) {
foreach ($rows as $t) {
$rt = \Phpcmf\Service::M('User', 'weixin')->delete_group($t['id']);
!$rt['code'] && $this->_json(0, $rt['msg']);
}
return dr_return_data(1, 'ok');
},
null,
\Phpcmf\Service::M()->dbprefix($this->init['table'])
);
}
}
@@ -0,0 +1,41 @@
<?php namespace Phpcmf\Controllers\Admin;
class Home extends \Phpcmf\Common
{
public function __construct() {
parent::__construct();
\Phpcmf\Service::V()->assign('menu', \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME.'微信公众号' => [APP_DIR.'/home/index', 'fa fa-area-chart'],
]
));
}
public function index() {
$data = [];
$fans = \Phpcmf\Service::M('Weixin', 'Weixin')->update_count_fans();
if ($fans) {
foreach ($fans as $d => $t) {
$data[] = [
'country' => substr($t['date'], 0, 4).'-'.substr($t['date'], 4, 2).'-'.substr($t['date'], 6, 2),
'year2004' => $t['new'],
'year2005' => $t['cumulate'],
];
}
}
\Phpcmf\Service::V()->assign([
'fans' => $fans,
'today' => date('Ymd'),
'yesterday' => date('Ymd', strtotime('-1 days')),
'data_tj' => json_encode($data),
'usercount' => \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts(),
'msgcount' => \Phpcmf\Service::M()->table(weixin_wxtable('message'))->where('DATEDIFF(from_unixtime(inputtime),now())=0')->counts(),
]);
\Phpcmf\Service::V()->display('weixin_index.html');
}
}
@@ -0,0 +1,36 @@
<?php namespace Phpcmf\Controllers\Admin;
class Log extends \Phpcmf\Common {
public function index() {
$file = WRITEPATH.'app/weixin.log';
if (!$file) {
$this->_admin_msg(0, '文件不存在:'.$file);
}
if (filesize($file) > 1024*1024*2) {
$this->_admin_msg(0, '此日志文件大于2MB,请使用Ftp等工具查看此文件:'.$file);
}
\Phpcmf\Service::V()->assign([
'menu' => \Phpcmf\Service::M('auth')->_admin_menu(
[
'请求日志' => ['weixin/log/index', 'fa fa-shield'],
]
),
'code' => file_get_contents($file),
'islog' => isset($this->weixin['account']['log']) && $this->weixin['account']['log'],
]);
\Phpcmf\Service::V()->display('log.html');
}
public function del() {
$file = WRITEPATH.'app/weixin.log';
unlink($file);
$this->_json(1, dr_lang('操作成功'));
}
}
@@ -0,0 +1,195 @@
<?php namespace Phpcmf\Controllers\Admin;
// 自定义菜单
class Menu extends \Phpcmf\Table
{
private $menu_type;
private $gid;
private $plugin;
public function __construct()
{
parent::__construct();
// 支持附表存储
$this->is_data = 0;
// 表单显示名称
$this->name = dr_lang('微信自定义菜单');
$this->gid = intval($_GET['gid']);
// 初始化数据表
$this->_init([
'table' => weixin_wxtable('menu'),
'where_list' => 'gid='.$this->gid,
'order_by' => 'displayorder asc,id asc',
]);
$this->menu_type = [
'view' => '网页地址',
'login' => '登录认证',
'click' => '小插件',
'miniprogram' => '小程序',
'article_view_limited' => '跳转图文',
];
$local = dr_dir_map(APPPATH.'Plugins', 1);
$this->plugin = [];
if ($local) {
foreach ($local as $dir) {
if (is_file(APPPATH.'Plugins/'.$dir.'/App.php')) {
$key = strtolower($dir);
$cfg = require APPPATH.'Plugins/'.$dir.'/App.php';
$this->plugin[$key] = [
'name' => $cfg['name'],
'value' => 'App::'.$key,
];
}
}
}
$menu = [
WEIXIN_MORE_NAME.'自定义菜单' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/index{gid='.$this->gid.'}', 'fa fa-list'],
'添加' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/add{gid='.$this->gid.'}', 'fa fa-plus', null, '33%'],
'修改' => ['hide:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/edit{gid='.$this->gid.'}', 'fa fa-edit'],
];
if (!$this->gid) {
$menu['从服务端获取菜单'] = ['ajax:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/down_add', 'fa fa-refresh'];
}
\Phpcmf\Service::V()->assign([
'gid' => $this->gid,
'menu' => \Phpcmf\Service::M('auth')->_admin_menu($menu),
'plugin' => $this->plugin,
'menu_type' => $this->menu_type,
'menu_top' => \Phpcmf\Service::M('User', APP_DIR)->top_menu(),
]);
}
public function down_add() {
$rt = \Phpcmf\Service::M('User', APP_DIR)->down_menu();
$rt['code'] ? $this->_json(1, '操作成功') : $this->_json(0, $rt['msg']);
}
public function sync_index() {
$rt = \Phpcmf\Service::M('User', APP_DIR)->sync_menu();
$rt['code'] ? $this->_json(1, '操作成功') : $this->_json(0, $rt['msg']);
}
public function displayorder_edit() {
$id = (int)\Phpcmf\Service::L('Input')->get('id');
$row = \Phpcmf\Service::M()->table(weixin_wxtable('menu'))->get($id);
if (!$row) {
$this->_json(0, dr_lang('数据#%s不存在', $id));
}
$value = (int)\Phpcmf\Service::L('Input')->get('value');
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('menu'))->save($id, 'displayorder', $value);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$this->_json(1, dr_lang('操作成功'));
}
public function index() {
list($tpl, $data) = $this->_list([], -1);
$list = [];
if ($data['list']) {
foreach ($data['list'] as $t) {
if ($t['pid'] == 0) {
$list[$t['id']] = $t;
foreach ($data['list'] as $tt) {
if ($tt['pid'] == $t['id']) {
$list[$tt['id']] = $tt;
}
}
}
}
}
\Phpcmf\Service::V()->assign('list', $list);
\Phpcmf\Service::V()->assign('is_ajax', 0);
\Phpcmf\Service::V()->display($tpl);
}
public function add() {
list($tpl) = $this->_Post();
\Phpcmf\Service::V()->assign('pid', $_GET['pid']);
$this->_get_data();
\Phpcmf\Service::V()->display($tpl);exit;
}
public function edit() {
$id = intval(\Phpcmf\Service::L('Input')->get('id'));
list($tpl, $data) = $this->_Post($id);
if (!$data) {
$this->_admin_msg(0, dr_lang('菜单#%s不存在', $id));
}
if (!$data['pid'] && !$data['type']) {
$tpl = 'menu_post_ajax.html';
}
if ($this->gid != $data['gid']) {
$this->_admin_msg(0, dr_lang('菜单#%s不属于当前组', $id));
}
$this->_get_data();
\Phpcmf\Service::V()->display($tpl);exit;
}
private function _get_data() {
\Phpcmf\Service::V()->assign([
'view_url' => [
[
'name' => '用户中心',
'value' => 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode(SITE_URL.'index.php?s=weixin&c=member').'&response_type=code&scope=snsapi_base&state=member#wechat_redirect',
],
],
'twsc' => \Phpcmf\Service::M()->table(weixin_wxtable('content'))->where('article_id<>""')->order_by('inputtime desc')->getAll(50),
]);
}
// 格式化保存数据
protected function _Format_Data($id, $data, $old) {
if (!$data['name']) {
$this->_json(0, '菜单名称必须填写', ['field' => 'name']);
}
$data['name'] = dr_emoji2html($data['name']);
$data['value'] = is_array($_POST['value_'.$data['type']]) ? dr_array2string($_POST['value_'.$data['type']]) : (string)$_POST['value_'.$data['type']];
if (!$id) {
$data['menuid'] = 0;
$data['displayorder'] = 0;
}
$data['gid'] = $this->gid;
return $data;
}
/**
* 获取内容
* $id 内容id,新增为0
* */
protected function _Data($id = 0) {
$data = parent::_Data($id);
if ($data['type'] == 'miniprogram') {
$data['value'] = dr_string2array($data['value']);
}
return $data;
}
public function del() {
$this->_Del(
\Phpcmf\Service::L('Input')->get_post_ids(),
null,
null,
\Phpcmf\Service::M()->dbprefix($this->init['table'])
);
}
}
@@ -0,0 +1,154 @@
<?php namespace Phpcmf\Controllers\Admin;
// 消息
class Message extends \Phpcmf\Table
{
public function __construct()
{
parent::__construct();
// 支持附表存储
$this->is_data = 0;
$this->tpl_prefix = 'message_';
// 表单显示名称
$this->name = dr_lang('微信消息');
$this->my_field = array(
'nickname' => array(
'ismain' => 1,
'name' => '昵称',
'isemoji' => 1,
'fieldname' => 'nickname',
),
'content' => array(
'ismain' => 1,
'name' => '内容',
'fieldname' => 'content',
),
);
// 初始化数据表
$this->_init([
'table' => weixin_wxtable('message'),
'order_by' => 'inputtime desc',
'date_field' => 'inputtime',
'field' => $this->my_field,
]);
\Phpcmf\Service::V()->assign([
'menu' => \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME. '消息管理' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/index', 'fa fa-user'],
'更新消息状态' => ['ajax:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/update_add', 'fa fa-refresh'],
]
),
'field' => $this->my_field,
]);
}
public function update_add() {
$rt = weixin_get_access_token();
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$access_token = $rt['msg'];
$error = 0;
$data = \Phpcmf\Service::M()->table(weixin_wxtable('message'))->where('status', 0)->getAll();
if ($data) {
foreach ($data as $t) {
$user = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->where('openid', $t['openid'])->getRow();
if (!$user) {
//$this->_json(0, '此用户已经取消关注,消息Id'.$t['id']);
$error++;
continue;
}
// 需要下载资源
$file = '';
$value = dr_string2array($t['content']);
if ($value['MediaId'] && in_array($t['tid'], ['image', 'voice', 'video', 'shortvideo'])) {
$file = 'http://file.api.weixin.qq.com/cgi-bin/media/get?access_token='.$access_token.
'&media_id='.$value['MediaId'];
}
\Phpcmf\Service::M()->table(weixin_wxtable('message'))->update($t['id'], [
'status' => 1,
'headimgurl' => $user['headimgurl'],
'nickname' => $user['nickname'],
'userid' => $user['id'],
'file' => $file,
]);
}
}
$this->_json(1, '更新完成,失败'.$error.'条');
}
public function index() {
list($tpl, $data) = $this->_List();
if ($data['list']) {
$list = [];
foreach ($data['list'] as $t) {
$value = dr_string2array($t['content']);
switch ($t['tid']) {
case 'text':
# 文本消息
$t['tid_name'] = '<span class="label label-success"> 文本 </span>';
$t['content'] = $value['Content'];
break;
case 'image':
# 图片消息
$t['tid_name'] = '<span class="label label-danger"> 图片 </span>';
break;
case 'voice':
# 语音消息
$t['tid_name'] = '<span class="label label-default"> 语音 </span>';
break;
case 'video':
# 视频消息
$t['tid_name'] = '<span class="label label-warning"> 视频 </span>';
break;
case 'shortvideo':
# 小视频消息
$t['tid_name'] = '<span class="label label-warning"> 小视频 </span>';
break;
case 'link':
# 链接消息
$t['tid_name'] = '<span class="label label-info"> 链接 </span>';
$t['content'] = '<a href="'.$value['Url'].'" target="_blank">'.$value['Url'].'</a>';
break;
default:
$t['tid_name'] = '未知';
break;
}
$t['status_name'] = $t['status'] ? '<span class="label label-success"> 已更新 </span>' : '<span class="label label-danger"> 未更新 </span>';
$list[] = $t;
}
}
\Phpcmf\Service::V()->assign('list', $list);
\Phpcmf\Service::V()->display($tpl);
}
public function show() {
\Phpcmf\Service::V()->assign('tid', \Phpcmf\Service::L('Input')->get('tid'));
\Phpcmf\Service::V()->assign('url', SYS_UPLOAD_URL.\Phpcmf\Service::L('Input')->get('file'));
\Phpcmf\Service::V()->display('message_show.html');exit;
}
public function del() {
$this->_Del(
\Phpcmf\Service::L('Input')->get_post_ids(),
function ($rows) {
foreach ($rows as $t) {
if ($t['file']) {
@unlink(SYS_UPLOAD_PATH.$t['file']);
}
}
return dr_return_data(1, 'ok');
},
null,
\Phpcmf\Service::M()->dbprefix($this->init['table'])
);
}
}
@@ -0,0 +1,146 @@
<?php namespace Phpcmf\Controllers\Admin;
class More extends \Phpcmf\Table
{
public function __construct() {
parent::__construct();
if (IS_ADMIN && SITE_ID > 1) {
$this->_admin_msg(0, '请登录主站账号管理微信插件');
}
\Phpcmf\Service::V()->assign('menu', \Phpcmf\Service::M('auth')->_admin_menu(
[
'多公众号管理' => [APP_DIR.'/more/index', 'fa fa-user'],
'添加' => ['add:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/add', 'fa fa-plus', null, '200px'],
]
));
// 支持附表存储
$this->is_data = 0;
// 表单显示名称
$this->name = dr_lang('多公众号');
// 初始化数据表
$this->_init([
'table' => 'app_weixin',
'order_by' => 'id asc',
]);
}
public function index() {
$this->_list([], -1);
\Phpcmf\Service::V()->display('more_list.html');
}
public function add() {
$this->_Post();
\Phpcmf\Service::V()->display('more_post.html');exit;
}
public function edit() {
$this->_Post(intval(\Phpcmf\Service::L('Input')->get('id')));
\Phpcmf\Service::V()->display('more_post.html');exit;
}
public function go_index() {
$id = intval(\Phpcmf\Service::L('Input')->get('id'));
$data = \Phpcmf\Service::M()->table('app_weixin')->get($id);
if (!$data) {
$this->_msg(0, '公众号不存在');
}
\Phpcmf\Service::L('cache')->set_auth_data('more_weixin', $id, 1);
$this->_msg(1, '切换到公众号:'.$data['name'], dr_url('weixin/account/index'));
}
protected function _Save($id = 0, $data = [], $old = [], $func = null, $func2 = null) {
return parent::_Save($id, $data, $old, function($id, $data, $old){
// 保存之前执行的函数,并返回新的数据
return dr_return_data(1, null, $data);
}, function ($id, $data, $old) {
// 保存之后执行的动作
if (!$old) {
// 生成新表
$this->_create_table($id);
}
});
}
private function _create_table($id) {
$sql = file_get_contents(APPPATH.'Config/Install.sql');
$sql = str_replace('{dbprefix}', \Phpcmf\Service::M()->dbprefix('more_'.$id.'_'), $sql);
$sql_data = explode(';SQL_FINECMS_EOL', trim(str_replace(array(PHP_EOL, chr(13), chr(10)), 'SQL_FINECMS_EOL', $sql)));
foreach($sql_data as $query){
if (!$query) {
continue;
}
$ret = '';
$queries = explode('SQL_FINECMS_EOL', trim($query));
foreach($queries as $query) {
$ret.= $query[0] == '#' || $query[0].$query[1] == '--' ? '' : $query;
}
if (!$ret) {
continue;
}
if (!\Phpcmf\Service::M()->db->simpleQuery(dr_format_create_sql($ret))) {
$rt = \Phpcmf\Service::M()->db->error();
return $ret.': '.$rt['message'];
}
}
return 0;
}
private function _delete_table($id) {
$sql = file_get_contents(APPPATH.'Config/Install.sql');
$sql = str_replace('{dbprefix}', \Phpcmf\Service::M()->dbprefix('more_'.$id.'_'), $sql);
$sql_data = explode(';SQL_FINECMS_EOL', trim(str_replace(array(PHP_EOL, chr(13), chr(10)), 'SQL_FINECMS_EOL', $sql)));
foreach($sql_data as $query){
if (!$query) {
continue;
}
$ret = '';
$queries = explode('SQL_FINECMS_EOL', trim($query));
foreach($queries as $query) {
$ret.= $query[0] == '#' || $query[0].$query[1] == '--' ? '' : $query;
}
if (!$ret) {
continue;
} elseif (strpos($ret, 'DROP TABLE') === false) {
continue;
}
if (!\Phpcmf\Service::M()->db->simpleQuery(($ret))) {
$rt = \Phpcmf\Service::M()->db->error();
return $ret.': '.$rt['message'];
}
}
return 0;
}
// 后台删除表单内容
public function del() {
$this->_Del(
\Phpcmf\Service::L('Input')->get_post_ids(),
function ($rows) {
foreach ($rows as $t) {
if ($t['id'] == 1) {
$this->_json(0, '默认公众号不能删除');
}
$this->_delete_table($t['id']);
}
return dr_return_data(1, 'ok');
},
null,
\Phpcmf\Service::M()->dbprefix($this->init['table'])
);
}
}
@@ -0,0 +1,118 @@
<?php namespace Phpcmf\Controllers\Admin;
// 微信自动回复内容
class Reply extends \Phpcmf\Table
{
public function __construct()
{
parent::__construct();
// 支持附表存储
$this->is_data = 0;
// 表单显示名称
$this->name = dr_lang('微信回复内容');
// 初始化数据表
$this->_init([
'table' => weixin_wxtable('reply'),
'order_by' => '`displayorder` desc,`id` desc',
'date_field' => 'updatetime',
]);
\Phpcmf\Service::V()->assign([
'menu' => \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME.'自动回复' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/index', 'fa fa-comments'],
'添加' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/add', 'fa fa-plus'],
'修改' => ['hide:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/edit', 'fa fa-plus'],
]
),
]);
}
public function index() {
$where = (string)$_GET['keyword'] ? '`keyword` LIKE "%'.$_GET['keyword'].'%"' : '';
$where && \Phpcmf\Service::M()->set_where_list($where);
list($tpl) = $this->_list();
\Phpcmf\Service::V()->display($tpl);
}
public function add() {
list($tpl) = $this->_Post();
\Phpcmf\Service::V()->display($tpl);
}
public function edit() {
list($tpl) = $this->_Post(intval(\Phpcmf\Service::L('Input')->get('id')));
\Phpcmf\Service::V()->display($tpl);
}
public function displayorder_edit() {
$id = (int)\Phpcmf\Service::L('Input')->get('id');
$row = \Phpcmf\Service::M()->table(weixin_wxtable('reply'))->get($id);
if (!$row) {
$this->_json(0, dr_lang('数据#%s不存在', $id));
}
$value = (int)\Phpcmf\Service::L('Input')->get('value');
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('reply'))->save($id, 'displayorder', $value);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
\Phpcmf\Service::M('weixin', 'weixin')->cache();
$this->_json(1, dr_lang('操作成功'));
}
/**
* 获取内容
* */
protected function _Data($id = 0) {
$data = parent::_Data($id);
if (!$data) {
return [];
}
return $data;
}
// 格式化保存数据
protected function _Format_Data($id, $data, $old) {
$data['content'] = (string)$_POST['value'][$data['tid']];
$data['displayorder'] = (int)$data['displayorder'];
if (!$id) {
$data['counts'] = 0;
$data['updatetime'] = 0;
}
return $data;
}
/**
* 保存内容
* $id 内容id,新增为0
* $data 提交内容数组,留空为自动获取
* $func 格式化提交的数据
* */
protected function _Save($id = 0, $data = [], $old = [], $func = null, $func2 = null) {
return parent::_Save($id, $data, $old,
null,
function ($id, $data, $old) {
// 保存之后
\Phpcmf\Service::M('weixin', 'weixin')->cache();
}
);
}
// 删除时
public function del() {
$this->_Del(\Phpcmf\Service::L('Input')->get_post_ids(), null, function($data){
\Phpcmf\Service::M('weixin', 'weixin')->cache();
});
}
}
@@ -0,0 +1,137 @@
<?php namespace Phpcmf\Controllers\Admin;
// 微信客服群发
class Send extends \Phpcmf\Common
{
public function __construct() {
parent::__construct();
\Phpcmf\Service::V()->assign('menu', \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME. '客服群发' => [APP_DIR.'/send/index', 'fa fa-envelope-o'],
]
));
}
// 来自cms的群发
public function show_add() {
$id = (int)\Phpcmf\Service::L('Input')->get('id');
$mid = dr_safe_filename(\Phpcmf\Service::L('Input')->get('mid'));
if (!$id || !$mid) {
$this->_html_msg(0, '参数不能为空');
}
$data = \Phpcmf\Service::M()->table_site($mid)->get($id);
if (!$data) {
$this->_html_msg(0, '内容不存在');
}
$data['tid'] = 'index';
$rt = \Phpcmf\Service::M('Weixin', 'Weixin')->send_for_content(0, $data);
!$rt['code'] && $this->_html_msg(0, $rt['msg']);
$this->_html_msg(1, '发送命令提交成功,即将自动发布', dr_url('weixin/send/add', ['id' => $rt['code']]));
}
public function add() {
$id = (int)\Phpcmf\Service::L('Input')->get('id');
$send_table = weixin_wxtable('send');
$data = \Phpcmf\Service::M()->table($send_table)->where('cid', $id)->where('status', 0)->getAll(20);
if (!$data) {
$msg = '发送结果:成功'. \Phpcmf\Service::M()->table($send_table)->where('cid', $id)->where('status', 1)->counts().'个,失败'. \Phpcmf\Service::M()->table($send_table)->where('cid', $id)->where('status', 2)->counts().'个';
\Phpcmf\Service::M()->db->table($send_table)->where('cid', $id)->delete();
$this->_admin_msg(1, $msg);
}
$rt = weixin_get_access_token();
if (!$rt['code']) {
$this->_admin_msg(0, $rt['msg']);
}
$access_token = $rt['msg'];
foreach ($data as $t) {
$param = dr_string2array($t['content']);
$param['touser'] = $t['openid'];
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='.$access_token,
$param
);
if (!$rt['code']) {
\Phpcmf\Service::M()->table($send_table)->update($t['id'], [
'status' => 2,
]);
} else {
// 发送成功
\Phpcmf\Service::M()->table($send_table)->update($t['id'], [
'status' => 1,
]);
}
}
$this->_admin_msg(2, '正在发送中...', FC_NOW_URL, 0);
}
public function index() {
if ($_GET['ac'] == 'send' && IS_AJAX_POST) {
// 发送群发
$data = \Phpcmf\Service::L('Input')->post('data');
$data['type'] = (int)$data['type'];
!$data['content'][$data['type']] && $this->_json(0, '没有选择内容');
if ($data['type']) {
$content = \Phpcmf\Service::M()->table(weixin_wxtable('content'))->get($data['content'][$data['type']]);
!$content && $this->_json(0, '素材内容不存在');
//!$content['media_id'] && $this->_json(0, '素材内容未同步');
$rt = \Phpcmf\Service::M('Weixin', 'Weixin')->send_for_content($data['groupid'], $content);
} else {
$rt = \Phpcmf\Service::M('Weixin', 'Weixin')->send_for_text($data['groupid'], $data['content'][0]);
}
!$rt['code'] && $this->_json(0, $rt['msg']);
$this->_json(1, '发送命令提交成功,即将自动发布', ['url' =>\Phpcmf\Service::L('Router')->url('weixin/send/add', ['id' => $rt['code']])]);
exit;
}
$db = \Phpcmf\Service::M()->table(weixin_wxtable('content'))->where('article_id<>""');
if (IS_POST) {
$param = \Phpcmf\Service::L('Input')->post('search');
$param['keyword'] && $db->where('`title` LIKE "%'.$param['keyword'].'%"');
}
$list = $db->order_by('inputtime desc')->getAll(30);
$uuid = 0;
$group = \Phpcmf\Service::M('User', APP_DIR)->get_group_data();
if (isset($_GET['uid']) && $_GET['uid']) {
$user = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->get($_GET['uid']);
$uuid = $user['openid'];
if ($user && $uuid) {
$group[$uuid] = [
'id' => $uuid,
'tag' => $uuid,
'name' => '指定粉丝',
'count' => dr_html2emoji($user['nickname']),
];
}
}
\Phpcmf\Service::V()->assign([
'form' => dr_form_hidden(),
'list' => $list,
'uuid' => $uuid,
'param' => $param,
'group' => $group,
'ucount' => \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts(),
'content_type' => [
//'index' => '图文',
//'image' => '图片',
//'//voice' => '语音',
//'video' => '视频',
],
]);
\Phpcmf\Service::V()->display('send_index.html');
}
}
@@ -0,0 +1,59 @@
<?php namespace Phpcmf\Controllers\Admin;
// 微信群发
class Sendall extends \Phpcmf\Table
{
public function __construct() {
parent::__construct();
\Phpcmf\Service::V()->assign('menu', \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME. '高级群发' => [APP_DIR.'/sendall/index', 'fa fa-volume-up'],
]
));
}
public function index() {
if ($_GET['ac'] == 'send' && IS_AJAX_POST) {
// 发送群发
$data = \Phpcmf\Service::L('Input')->post('data');
!$data['content'] && $this->_json(0, '没有选择素材内容');
$content = \Phpcmf\Service::M()->table(weixin_wxtable('content'))->get($data['content']);
!$content && $this->_json(0, '素材内容不存在');
!$content['article_id'] && $this->_json(0, '素材内容未同步');
$rt = \Phpcmf\Service::M('Weixin', 'Weixin')->sendall($data['groupid'], $content);
!$rt['code'] && $this->_json(0, $rt['msg']);
$this->_json(1, '发送提交成功');
exit;
}
$db = \Phpcmf\Service::M()->table(weixin_wxtable('content'))->where('article_id<>""');
if (IS_POST) {
$param = \Phpcmf\Service::L('Input')->post('search');
$param['tid'] && $db->where('tid', $param['tid']);
$param['keyword'] && $db->where('`title` LIKE "%'.$param['keyword'].'%"');
}
$list = $db->order_by('inputtime desc')->getAll(30);
\Phpcmf\Service::V()->assign([
'form' => dr_form_hidden(),
'list' => $list,
'param' => $param,
'group' => \Phpcmf\Service::M('User', APP_DIR)->get_group_data(),
'ucount' => \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts(),
'content_type' => [
//'index' => '图文',
//'image' => '图片',
//'voice' => '语音',
// 'video' => '视频',
],
]);
\Phpcmf\Service::V()->display('sendall_index.html');
}
}
@@ -0,0 +1,119 @@
<?php namespace Phpcmf\Controllers\Admin;
// 优速贡献代码
class Sendtpl extends \Phpcmf\App
{
// 来自cms的群发
public function show_add() {
$id = (int)\Phpcmf\Service::L('Input')->get('id');
$mid = dr_safe_filename(\Phpcmf\Service::L('Input')->get('mid'));
if (!$id || !$mid) {
$this->_json(0, '参数不能为空');
}
$this->_module_init($mid);
$data = $this->content_model->get_data($id);
if (!$data) {
$this->_json(0, '内容不存在');
}
$file = WRITEPATH.'config/weixin_sendtpl.php';
$config = [];
if (is_file($file)) {
$config = require $file;
}
if (!isset($config[$mid])) {
$this->_json(0, '微信插件-内容模板群发设置-没有设置本模块参数');
} elseif (!isset($config[$mid]['use']) || !$config[$mid]['use']) {
$this->_json(0, '微信插件-内容模板群发设置-没有开启本模块');
} elseif (!isset($config[$mid]['id']) || !$config[$mid]['id']) {
$this->_json(0, '微信插件-内容模板群发设置-没有设置本模块参数');
} elseif (!isset($config[$mid]['content']) || !$config[$mid]['content']) {
$this->_json(0, '微信插件-内容模板群发设置-没有设置本模块参数');
}
$cache = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->getAll();
if (!$cache) {
$this->_json(0, dr_lang('没有可用粉丝'));
}
// 生成模板
$template = [];
foreach ($config[$mid]['content'] as $t) {
if ($t['name']) {
$value = $t['value'];
$tpl = $this->replace($data, $value);
$template[$t['name']] = [
'value' => $tpl ? $tpl : $value,
'color' => $t['color'],
];
}
}
if (!$template) {
$this->_json(0, dr_lang('模板内容解析后不存在'));
}
$data['template'] = $config[$mid]['id'];
$data['color'] = $config[$mid]['color'];
$data['url'] = dr_url_prefix($data['url'], $mid);
// 存储文件
\Phpcmf\Service::L('cache')->set_auth_data('app-weixin-template-send', [
'data' => $data,
'template' => $template,
'users' => dr_save_bfb_data($cache)
]);
$this->_json(1, 'ok', ['url' => dr_url('weixin/template/show_index', ['counts'=> count($cache)])]);
}
// 查看列表
public function index() {
$file = WRITEPATH.'config/weixin_sendtpl.php';
$module = \Phpcmf\Service::L('cache')->get('module-'.SITE_ID.'-content');
if (IS_POST) {
$post = \Phpcmf\Service::L('input')->post('data');
\Phpcmf\Service::L('Config')->file($file, '微信模板群发', 32)->to_require($post);
$this->_json(1, '操作成功');
}
$one = reset($module);
$page = \Phpcmf\Service::L('input')->get('page');
if (!$page) {
$page = $one['dirname'];
}
\Phpcmf\Service::V()->assign([
'page' => $page,
'data' => is_file($file) ? require $file : [],
'form' => dr_form_hidden(),
'menu' => \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME.'模块内容群发' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/index', 'fa fa-edit'],
'help' => [1127],
]),
'module' => $module,
]);
\Phpcmf\Service::V()->display('sendtpl.html');
}
// 替换全部
private function replace($data, $value) {
$rep = new \php5replace($data);
$value = preg_replace_callback('#{([A-Z_]+)}#U', array($rep, 'php55_replace_var'), $value);
$value = preg_replace_callback('#{([a-z_0-9]+)}#U', array($rep, 'php55_replace_data'), $value);
$value = preg_replace_callback('#{\$([a-z_0-9]+)}#U', array($rep, 'php55_replace_data'), $value);
$value = preg_replace_callback('#{([a-z_0-9]+)\((.*)\)}#Ui', array($rep, 'php55_replace_function'), $value);
return $value;
}
}
@@ -0,0 +1,347 @@
<?php namespace Phpcmf\Controllers\Admin;
class Template extends \Phpcmf\Table
{
public function __construct()
{
parent::__construct();
// 表单显示名称
$this->name = dr_lang('模板消息');
// 模板前缀(避免混淆)
$this->tpl_prefix = 'template_';
// 用于表储存的字段,后台可修改的表字段
$field = array(
'title' => array(
'name' => dr_lang('主题'),
'fieldname' => 'title', // 这是字段名称必须和主键相同
),
'template' => array(
'name' => dr_lang('模板ID'),
'fieldname' => 'template', // 这是字段名称必须和主键相同
),
'url' => array(
'name' => dr_lang('消息URL'),
'fieldname' => 'url', // 这是字段名称必须和主键相同
),
);
// 初始化数据表
$this->_init([
'table' => weixin_wxtable('template'),
'field' => $field, // 可查询的字段
'order_by' => 'inputtime desc', // 列表排序
'date_field' => 'inputtime', // 按时间段搜索字段
]);
// 把公共变量传入模板
\Phpcmf\Service::V()->assign([
// 搜索字段
'field' => $field,
// 后台的菜单
'menu' => \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME. $this->name => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/index', 'fa fa-edit'],
'创建' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/add', 'fa fa-plus'],
'修改' => ['hide:'.APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/edit', 'fa fa-edit'],
]),
'group' => \Phpcmf\Service::M('User', APP_DIR)->get_group_data(),
'ucount' => \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts(),
]);
}
// 来自cms的群发
public function show_add() {
$id = (int)\Phpcmf\Service::L('Input')->get('id');
$mid = dr_safe_filename(\Phpcmf\Service::L('Input')->get('mid'));
if (!$id || !$mid) {
$this->_json(0, '参数不能为空');
}
$data = \Phpcmf\Service::M()->table_site($mid)->get($id);
if (!$data) {
$this->_json(0, '内容不存在');
}
$cache = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->getAll();
if (!$cache) {
$this->_json(0, dr_lang('没有可用粉丝'));
}
$tpl = [];
// 生成模板
$template = [];
foreach ($tpl['content'] as $t) {
if ($t['name']) {
$template[$t['name']] = [
'value' => $t['value'],
'color' => $t['color'],
];
}
}
if (!$template) {
$this->_json(0, dr_lang('模板内容解析后不存在'));
}
// 存储文件
\Phpcmf\Service::L('cache')->set_auth_data('app-weixin-template-send', [
'data' => $data,
'template' => $template,
'users' => dr_save_bfb_data($cache)
], 3600);
$this->_json(1, 'ok', ['url' => dr_url('weixin/template/show_index', ['counts'=> count($cache)])]);
}
// 查看列表
public function index() {
list($tpl) = $this->_List();
\Phpcmf\Service::V()->display($tpl);
}
// 添加内容
public function add() {
list($tpl) =$this->_Post(0);
\Phpcmf\Service::V()->display($tpl);
}
// 修改内容
public function edit() {
$id = intval(\Phpcmf\Service::L('Input')->get('id'));
list($tpl) = $this->_Post($id);
\Phpcmf\Service::V()->display($tpl);
}
// 删除内容
public function del() {
$this->_Del(
\Phpcmf\Service::L('Input')->get_post_ids(),
null,
null,
\Phpcmf\Service::M()->dbprefix($this->init['table'])
);
}
// 内容处理
public function todo_add() {
$id = \Phpcmf\Service::L('input')->get('id');
$data = \Phpcmf\Service::M()->table($this->init['table'])->get($id);
if (!$data) {
$this->_json(0, dr_lang('模板内容不存在'));
} elseif (!$data['content']) {
$this->_json(0, dr_lang('内容参数不存在'));
} elseif (!$data['template']) {
$this->_json(0, dr_lang('模板ID不存在'));
}
$data['content'] = dr_string2array($data['content']);
if ($data['groupid'] < 0) {
$gid = abs($data['groupid']);
$where = 'uid in (select uid from '.\Phpcmf\Service::M()->dbprefix('member_group_index').' where gid='.$gid.')';
$cache = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->where($where)->getAll();
} elseif ($data['groupid'] > 0) {
$cache = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->where('groupids LIKE "%\"'.\Phpcmf\Service::M()->db->escapeString($data['groupid'], true).'\"%"')->getAll();
} else {
$cache = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->getAll();
}
if (!$cache) {
$this->_json(0, dr_lang('没有可用粉丝'));
}
// 生成模板
$template = [];
foreach ($data['content'] as $t) {
if ($t['name']) {
$template[$t['name']] = [
'value' => $t['value'],
'color' => $t['color'],
];
}
}
if (!$template) {
$this->_json(0, dr_lang('模板内容解析后不存在'));
}
// 存储文件
\Phpcmf\Service::L('cache')->set_auth_data('app-weixin-template-send', [
'data' => $data,
'template' => $template,
'users' => $this->_save_bfb_data($cache),
]);
$this->_json(1, 'ok', ['url' => dr_url('weixin/template/show_index', ['counts'=> count($cache)])]);
}
function _save_bfb_data($data) {
$cache = [];
$count = dr_count($data);
$num = ceil($count/10);
if ($count > $num) {
$pagesize = ceil($count/$num);
for ($i = 1; $i <= $num; $i ++) {
$cache[$i] = array_slice($data, ($i - 1) * $pagesize, $pagesize);
}
} else {
for ($i = 1; $i <= $count; $i ++) {
$cache[$i] = array_slice($data, ($i - 1), 1);
}
}
return $cache;
}
// 内容处理
public function show_index() {
\Phpcmf\Service::V()->assign([
'menu' => '',
'hidebtn' => 1,
'todo_url' => dr_url('weixin/template/send_add'),
'count_url' => dr_url('weixin/template/show_count_index'),
]);
\Phpcmf\Service::V()->display('bfb.html');exit;
}
// 内容数量统计
public function show_count_index() {
$data = \Phpcmf\Service::L('cache')->get_auth_data('app-weixin-template-send');
!dr_count($data) && $this->_json(0, dr_lang('无可用数据,缓存已失效'));
$this->_json(count($data['users']), 'ok');
}
public function send_add() {
$page = max(1, intval($_GET['pp']));
$cache = \Phpcmf\Service::L('cache')->get_auth_data('app-weixin-template-send');
!$cache && $this->_json(0, dr_lang('缓存不存在'));
$data = $cache['users'][$page];
$cts = count($cache['users']);
if ($data) {
$html = '';
foreach ($data as $user) {
$rt = $this->_send_template($user['openid'], $cache['data']['template'], $cache['template'], $cache['data']['url'], $cache['data']['color']);
if (!$rt['code']) {
$ok = "<span class='error'>".$rt['msg']."</span>";
$class = ' p_error';
} else {
$ok = "<span class='ok'>".dr_lang('发送成功')."</span>";
\Phpcmf\Service::M()->db->table($this->init['table'])
->where('id', intval($cache['data']['id']))
->increment('counts', 1);
}
$html.= '<p class="'.$class.'"><label class="rleft">'.dr_html2emoji($user['nickname']).'</label><label class="rright">'.$ok.'</label></p>';
}
$this->_json($page + 1, $html, [
'msg' => '正在执行第'.$page.'页/共'.$cts.'页',
'bfb' => round($page/$cts * 100, 2),
]);
}
// 完成
\Phpcmf\Service::L('cache')->del_auth_data('app-weixin-template-send');
$this->_json($cts, 'ok');
}
/**
* 获取微信 access token
*/
public function _weixin_template_access_token() {
$cache_data = \Phpcmf\Service::L('cache')->init('file')->get('access_token');
if (isset($cache_data['time']) && $cache_data['access_token']) {
$access_token = $cache_data['access_token'];
} else {
$weixin = \Phpcmf\Service::C()->get_cache('weixin');
$result = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$weixin['account']['appid'].'&secret='.$weixin['account']['appsecret']);
if (!$result['code']) {
return dr_return_data(0, 'AccessToken'.$result['msg']);
}
\Phpcmf\Service::L('cache')->init('file')->save('access_token', $result['data'], 3600);
$access_token = $result['data']['access_token'];
}
return dr_return_data(1, 'ok', ['access_token' => $access_token]);
}
private function _send_template($oid, $id, $data, $url = '', $color = '') {
$rt = $this->_weixin_template_access_token();
if (!$rt['code']) {
return dr_return_data(0, $rt['msg']);
}
$p = [
'touser' => $oid,
'template_id' => $id,
'url' => $url,
'topcolor' => $color,
'data' => $data,
];
$rt = wx_post_https_json_data('https://api.weixin.qq.com/cgi-bin/message/template/send?access_token='.$rt['data']['access_token'], $p);
return $rt;
}
// 复制
public function copy_edit() {
$id = intval(\Phpcmf\Service::L('input')->get('id'));
$data = \Phpcmf\Service::M()->db->table(weixin_wxtable('template'))->where('id', $id)->get()->getRowArray();
if (!$data) {
$this->_json(0, dr_lang('数据#%s不存在', $id));
}
unset($data['id']);
$data['title'].= '_copy';
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('template'))->insert($data);
if (!$rt['code']) {
$this->_json(0, dr_lang($rt['msg']));
}
$this->_json(1, dr_lang('复制成功'));
}
/**
* 获取内容
* $id 内容id,新增为0
* */
protected function _Data($id = 0) {
$data = parent::_Data($id);
if (!$data) {
return [];
}
$data['content'] = dr_string2array($data['content']);
return $data;
}
// 格式化保存数据
protected function _Format_Data($id, $data, $old) {
$data[1] = \Phpcmf\Service::L('input')->post('data');
$data[1]['content'] = dr_array2string($data[1]['content']);
if (!$id) {
// 当提交新数据时,把当前时间插入进去
$data[1]['counts'] = 0;
$data[1]['inputtime'] = SYS_TIME;
}
return $data;
}
}
@@ -0,0 +1,275 @@
<?php namespace Phpcmf\Controllers\Admin;
// 粉丝
class User extends \Phpcmf\Table
{
public function __construct()
{
parent::__construct();
// 支持附表存储
$this->is_data = 0;
$this->tpl_prefix = 'user_';
// 表单显示名称
$this->name = dr_lang('微信用户');
$this->my_field = array(
'nickname' => array(
'ismain' => 1,
'name' => '昵称',
'isemoji' => 1,
'fieldname' => 'nickname',
),
'username' => array(
'ismain' => 1,
'name' => '账号',
'fieldname' => 'username',
),
'openid' => array(
'ismain' => 1,
'name' => 'openid(OID)',
'fieldname' => 'openid',
),
);
// 初始化数据表
$this->_init([
'table' => weixin_wxtable('user'),
'order_by' => 'subscribe_time desc,uid asc',
'date_field' => 'subscribe_time',
'field' => $this->my_field,
]);
\Phpcmf\Service::V()->assign([
'menu' => \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME.'粉丝管理' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/index', 'fa fa-user'],
'从服务端获取粉丝' => [APP_DIR.'/'.\Phpcmf\Service::L('Router')->class.'/down_add', 'fa fa-plus'],
]
),
'field' => $this->my_field,
'group' => \Phpcmf\Service::M('User', APP_DIR)->get_group_data(),
]);
}
public function down_add() {
$rt = weixin_get_access_token();
if (!$rt['code']) {
$this->_admin_msg(0, $rt['msg']);
}
$access_token = $rt['msg'];
$action = \Phpcmf\Service::L('Input')->get('action');
if (!$action) {
$url = 'https://api.weixin.qq.com/cgi-bin/user/get?access_token='.$access_token.'&next_openid='.\Phpcmf\Service::L('Input')->get('next_openid');
$rt = wx_get_https_json_data($url);
if (!$rt['code']) {
$this->_admin_msg(0, $rt['msg']);
} elseif (!isset($rt['data']['count']) || $rt['data']['count'] == 0) {
// 拉取完毕 全部设置为0状态
\Phpcmf\Service::M()->db->table(weixin_wxtable('follow'))->update(array(
'status' => 0,
));
\Phpcmf\Service::M()->table(weixin_wxtable('user'))->clear_all();
$this->_admin_msg(1, '同步用户数据中,请勿关闭',\Phpcmf\Service::L('Router')->url('weixin/user/down_add', array('action'=>'user')), 0);
}
// 查询并入库
$res = \Phpcmf\Service::M()->db->table(weixin_wxtable('follow'))->whereIn('openid', $rt['data']['data']['openid'])->get()->getResultArray();
if (count($res) != $rt['data'] ['count']) {
// 更新的数量不一致,可能有增加的用户openid
$openids = array();
if ($res) {
foreach ($res as $t) {
$openids[] = $t['openid'];
}
}
$diff = array_diff ( $rt['data'] ['data'] ['openid'], $openids );
if (! empty ( $diff )) {
foreach ( $diff as $id ) {
$save = array();
$save ['openid'] = $id;
$save ['uid'] = 0;
$save ['status'] = 0;
\Phpcmf\Service::M()->db->table(weixin_wxtable('follow'))->insert($save);
}
}
}
$this->_admin_msg(1, '同步用户OpenID中,请勿关闭',\Phpcmf\Service::L('Router')->url('weixin/user/down_add', array('next_openid'=>$rt['data']['next_openid'])), 0);
} elseif ($action == 'user') {
// 开始更新会员资料
$list = \Phpcmf\Service::M()->db->table(weixin_wxtable('follow'))->where('status', 0)->orderBy('id desc')->limit(50)->get()->getResultArray();
if (empty ($list)) {
$this->_admin_msg(1, '同步用户完成',\Phpcmf\Service::L('Router')->url('weixin/user/index') , 0);
}
$param = $openids = $uids = array();
foreach ( $list as $vo ) {
$param['user_list'][] = array (
'openid' => $vo ['openid'],
'lang' => 'zh-CN'
);
$openids[] = $vo ['openid'];
$uids [$vo ['openid']] = $vo ['uid'];
}
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=' . $access_token,
$param
);
if (!$rt['code']) {
$this->_admin_msg(0, $rt['msg']);
}
$ok = 0;
$update = array();
foreach ($rt['data']['user_info_list'] as $u ) {
if ($u['subscribe'] == 0) {
continue;
}
$rt = \Phpcmf\Service::M('User', APP_DIR)->insert_user($u);
// 更新关注表状态
if ($rt) {
$ok++;
\Phpcmf\Service::M()->db->table(weixin_wxtable('follow'))->where('openid', $u['openid'])->update(array(
'status' => 1,
'uid' => $rt['id'],
));
}
$update[] = $u['openid'];
}
// 判断没获取到的
foreach ($list as $t) {
if (!dr_in_array($t['openid'], $update)) {
\Phpcmf\Service::M()->db->table(weixin_wxtable('follow'))->where('openid', $t['openid'])->update(array(
'status' => 1,
'uid' => 0,
));
}
}
$this->_admin_msg(1, '每次同步50个,本次成功'.$ok.'个,请勿关闭',\Phpcmf\Service::L('Router')->url('weixin/user/down_add', array('action'=>'user')), 0);
}
}
public function index() {
$groupid = (int)\Phpcmf\Service::L('Input')->request('groupid');
$groupid && \Phpcmf\Service::M()->set_where_list('`groupids` LIKE "%'.str_replace('\\', '\\\\\\', json_encode($groupid)).'%"');
list($tpl) = $this->_List(['groupid' => $groupid]);
\Phpcmf\Service::V()->display($tpl);
}
// 分组设置
public function move_edit() {
$ids = \Phpcmf\Service::L('Input')->get_post_ids();
!$ids && $this->_json(0, dr_lang('所选数据不存在'));
$rows = \Phpcmf\Service::M()->init($this->init)->where_in('id', $ids)->getAll();
!$rows && $this->_json(0, dr_lang('所选数据不存在'));
$rt = weixin_get_access_token();
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$access_token = $rt['msg'];
$groupid = (int)\Phpcmf\Service::L('Input')->post('groupid');
if (!$groupid) {
$this->_json(0, '未选择标签组');
}
$openid = [];
foreach ($rows as $t) {
$openid[] = $t['openid'];
$groupids = dr_string2array($t['groupids']);
if (!dr_in_array($groupid, $groupids)) {
$groupids[] = (string)$groupid;
}
// 更改本地库
\Phpcmf\Service::M()->db->table(weixin_wxtable('user'))->where('id', $t['id'])->update(array(
'groupids' => dr_array2string($groupids),
));
}
$param = [
'openid_list' => $openid,
'tagid' => $groupid,
];
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=' . $access_token,
$param
);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$this->_json(1, dr_lang('操作成功'));
}
// 分组取消
public function move_del() {
$ids = \Phpcmf\Service::L('Input')->get_post_ids();
!$ids && $this->_json(0, dr_lang('所选数据不存在'));
$rows = \Phpcmf\Service::M()->init($this->init)->where_in('id', $ids)->getAll();
!$rows && $this->_json(0, dr_lang('所选数据不存在'));
$rt = weixin_get_access_token();
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$access_token = $rt['msg'];
$groupid = (int)\Phpcmf\Service::L('Input')->post('groupid');
if (!$groupid) {
$this->_json(0, '未选择标签组');
}
$openid = [];
foreach ($rows as $t) {
$openid[] = $t['openid'];
$groupids = dr_string2array($t['groupids']);
if ($groupids && dr_in_array($groupid, $groupids)) {
foreach ($groupids as $i => $v) {
if ($v == $groupid) {
unset($groupids[$i]);
}
}
// 更改本地库
\Phpcmf\Service::M()->db->table(weixin_wxtable('user'))->where('id', $t['id'])->update(array(
'groupids' => dr_array2string($groupids),
));
}
}
$param = [
'openid_list' => $openid,
'tagid' => $groupid,
];
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/tags/members/batchuntagging?access_token=' . $access_token,
$param
);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$this->_json(1, dr_lang('操作成功'));
}
//
public function del() {
$this->_Del(
\Phpcmf\Service::L('Input')->get_post_ids(),
null,
null,
\Phpcmf\Service::M()->dbprefix($this->init['table'])
);
}
}
@@ -0,0 +1,36 @@
<?php namespace Phpcmf\Controllers\Admin;
class Xcx extends \Phpcmf\Common
{
public function index() {
$page = intval(\Phpcmf\Service::L('Input')->get('page'));
$data = \Phpcmf\Service::M('Weixin', 'Weixin')->get_config('xcx');
if (IS_AJAX_POST) {
$post = \Phpcmf\Service::L('Input')->post('data');
$rt = \Phpcmf\Service::M('Weixin', 'Weixin')->save_config('xcx', $post);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
\Phpcmf\Service::M('Weixin', 'Weixin')->cache();
$this->_json(1, dr_lang('操作成功'));
}
\Phpcmf\Service::V()->assign([
'data' => $data,
'page' => $page,
'form' => dr_form_hidden(['page' => $page]),
'menu' => \Phpcmf\Service::M('auth')->_admin_menu(
[
WEIXIN_MORE_NAME. '小程序' => [APP_DIR.'/xcx/index', 'fa fa-cog'],
'help' => [416],
]
),
]);
\Phpcmf\Service::V()->display('xcx_index.html');
}
}
+16
View File
@@ -0,0 +1,16 @@
<?php namespace Phpcmf\Controllers;
class Api extends \Phpcmf\Common {
// 从微信菜单中进入授权
public function xcx_access_token() {
$rts = xcx_get_access_token();
if (!$rts['code']) {
$this->_json(0, $rts['msg']);
}
$this->_json(1, $rts['msg']);
}
}
+41
View File
@@ -0,0 +1,41 @@
<?php namespace Phpcmf\Controllers;
// 登录跳转
class Go extends \Phpcmf\Common {
// 从微信菜单中进入授权
// 公众号内自动登陆
public function index() {
$url = (!$this->is_mobile ? SITE_URL : SITE_MURL).'index.php?s=weixin&c=member&m=login';
if ($_GET['url']) {
$burl = urlencode($_GET['url']);
} else {
$burl = urlencode((!$this->is_mobile ? SITE_URL : SITE_MURL).'index.php?s=member');
}
dr_redirect('https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode($url).'&response_type=code&scope=snsapi_userinfo&state='.($burl).'#wechat_redirect');
}
// 静默授权获取openidsnsapi_base
public function check() {
$code = \Phpcmf\Service::L('input')->get('code');
$burl = $_GET['url'] ? $_GET['url'] : FC_NOW_URL;
if ($code) {
$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$this->weixin['account']['appid'].'&secret='.$this->weixin['account']['appsecret'].'&code='.$code.'&grant_type=authorization_code';
$rt = wx_get_https_json_data($url);
if (!$rt['code']) {
$this->_msg(0, $rt['msg']);
} elseif ($rt['data']['openid']) {
\Phpcmf\Service::L('input')->set_cookie('weixin_gzh_openid', $rt['data']['openid'], 86400 * 30);
}
dr_redirect($burl);
}
$redirect_uri = (!$this->is_mobile ? SITE_URL : SITE_MURL).'index.php?s=weixin&c=go&m=check&url='.urlencode($burl);
dr_redirect('https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode($redirect_uri).'&response_type=code&scope=snsapi_base&state=check#wechat_redirect');
}
}
+652
View File
@@ -0,0 +1,652 @@
<?php namespace Phpcmf\Controllers;
class Home extends \Phpcmf\Common {
private $token;
private $data;
private $access_token;
public function index() {
if (!isset($this->weixin['account']['appid']) || !$this->weixin['account']['appid']) {
exit('插件AppId未配置(如果后台已经配置,请更新缓存后,才会生效)');
} elseif (!isset($this->weixin['account']['token']) || !$this->weixin['account']['token']) {
exit('插件Token未配置(如果后台已经配置,请更新缓存后,才会生效)');
} elseif ($this->checkSignature()) {
// 判读是不是只是验证
$echostr = \Phpcmf\Service::L('Input')->get('echostr', true);
if ($echostr) {
echo $echostr;exit;
} else {
// 实际处理用户消息
$content = file_get_contents('php://input');
if (isset($this->weixin['account']['log']) && $this->weixin['account']['log']) {
file_put_contents(WRITEPATH.'app/weixin.log', dr_date(SYS_TIME, 'Y-m-d H:i:s').' - '.$content.PHP_EOL.'==================================='.PHP_EOL, FILE_APPEND);
}
//file_put_contents(APPPATH."wx.txt", var_export($content, true));
if ($content) {
// 解析微信传过来的 XML 内容 转化为数组
$this->data = dr_object2array(simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA));
if (!$this->data['EventKey']) {
$this->data['EventKey'] = '';
}
$this->token = $this->data['ToUserName'];
$rt = weixin_get_access_token();
$rt['code'] && $this->access_token = $rt['msg'];
// 微信消息钩子
\Phpcmf\Hooks::trigger('weixin_msg', $this);
// 存储和分析请求
switch ($this->data['MsgType']) {
case 'text':
# 文本消息
// 初始化用户 将其加入到粉丝组里面
$this->_init_user();
\Phpcmf\Service::M('Weixin', 'Weixin')->save_message($this->data);
//
// 搜索自定义回复
$kws = $this->get_cache('weixin-kws'.(WEIXIN_MORE_ID > 1 ? '_more_'.WEIXIN_MORE_ID : ''));
if ($kws) {
foreach ($kws as $kw => $id) {
if (strpos($this->data['Content'], (string)$kw) !== false) {
$data = \Phpcmf\Service::M()->table(weixin_wxtable('reply'))->get($id);
if ($data) {
// 记录
\Phpcmf\Service::M()->table(weixin_wxtable('reply'))->update($data['id'], [
'counts' => $data['counts'] + 1,
'updatetime' => SYS_TIME,
]);
if ($data['tid']) {
// 回复素材
return $this->_to_weixin_content($data['content']);
} else {
// 回复文本
return $this->_to_weixin_text($data['content']);
}
break;
}
}
}
}
// 用于自定义开发回复
if (is_file(APPPATH.'Plugins/AutoReply/Run.php')) {
require APPPATH.'Plugins/AutoReply/Run.php';
}
// 搜索模块内容回复
if ($this->weixin['config']['ss']) {
// 搜索模块内容回复
if ($this->weixin['config']['ss_dir']) {
// 搜索模块内容
foreach ($this->weixin['config']['ss_dir'] as $dirname) {
foreach ($this->site as $siteid) {
$table = dr_module_table_prefix($dirname, $siteid);
// 判断是否存在表
if (!\Phpcmf\Service::M()->is_table_exists($table)) {
continue;
}
// 查询 关键 词
$kw = dr_safe_replace($this->data['Content']);
$data = \Phpcmf\Service::M()->db->table($table)->where('`title` LIKE "%'.$kw.'%"')->orderBy('id desc')->limit(1)->get()->getResultArray();
#log_message('error', ''.\Phpcmf\Service::M()->get_sql_query());
if ($data) {
// 查询成功,回复他们
$cdata = [
'tid' => 'index',
'content' => [],
];
foreach ($data as $ii => $t) {
$i = 10 + $ii;
$cdata['content'][$i] = [
'title_'.$i => $t['title'],
'author_'.$i => $t['author'],
'thumb_'.$i => $t['thumb'] ? dr_get_file($t['thumb']) : SITE_LOGO,
'description_'.$i => $t['description'],
'url_'.$i => dr_url_prefix($t['url']),
];
if ($t['thumb'] && !isset($cdata['content'][1])) {
$cdata['content'][1] = [
'title_1' => $t['title'],
'author_1' => $t['author'],
'thumb_1' => dr_get_file($t['thumb']),
'description_1' => $t['description'],
'url_1' => dr_url_prefix($t['url']),
];
unset($cdata['content'][$i]);
}
}
ksort($cdata['content']);
// 回复内容
return $this->_to_weixin_content_data($cdata);
}
}
}
}
// 没有找到回复内容
if ($this->weixin['config']['ss_type']) {
// 回复素材
return $this->_to_weixin_content($this->weixin['config']['ss_value_1']);
} else {
// 回复文本
return $this->_to_weixin_text($this->weixin['config']['ss_value_0']);
}
}
break;
case 'image':
# 图片消息
case 'voice':
# 语音消息
case 'video':
# 视频消息
case 'shortvideo':
# 小视频消息
case 'link':
# 链接消息
// 初始化用户 将其加入到粉丝组里面
$this->_init_user();
\Phpcmf\Service::M('Weixin', 'Weixin')->save_message($this->data);
break;
case 'location':
# 地理位置消息
break;
case 'event':
# 事件推送
switch ($this->data['Event']) {
case 'PUBLISHJOBFINISH':
// 发布内容推送
\Phpcmf\Service::M()->table(weixin_wxtable('content'))
->where('publish_id', $this->data['PublishEventInfo']['publish_id'])->update(0, [
'status' => $this->data['PublishEventInfo']['publish_status'],
'article_id' => $this->data['PublishEventInfo']['article_id'],
]);
break;
case 'subscribe':
// 关注时
// 统计数据
/*
$fans = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->where('date', date('Ymd'))->getRow();
if (!$fans) {
// 今日新关注
$usercount = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts();
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->insert([
'new' => 1,
'cancel' => 0,
'cumulate' => $usercount,
'date' => date('Ymd'),
]);
} else {
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->update($fans['id'], [
'new' => $fans['new'] + 1,
'cumulate' => $fans['cumulate'] + 1,
]);
}*/
if (strpos($this->data['EventKey'], 'qrscene_bang-') === 0) {
// 表示通过扫描二维码关注微信公众号
$this->_gz_bang_user();
} else {
// 初始化用户 将其加入到粉丝组里面
$user = $this->_init_user();
$this->_gz_login_user();
// 回复关注信息
if ($this->weixin['config']['gz']) {
if ($this->weixin['config']['gz_type']) {
// 回复素材
if ($this->weixin['config']['gz_value_1']) {
$this->_to_weixin_content($this->weixin['config']['gz_value_1']);
}
} else {
// 回复文本
if ($this->weixin['config']['gz_value_0']) {
$this->_to_weixin_text($this->_gz_msg($this->weixin['config']['gz_value_0'], $user));
}
}
}
}
break;
case 'unsubscribe':
// 取消关注时
/*
$fans = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->where('date', date('Ymd'))->getRow();
if (!$fans) {
// 今日新取消关注
$usercount = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->counts();
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->insert([
'new' => 0,
'cancel' => 1,
'cumulate' => $usercount,
'date' => date('Ymd'),
]);
} else {
$rt = \Phpcmf\Service::M()->table(weixin_wxtable('count_fans'))->update($fans['id'], [
'cancel' => $fans['new'] + 1,
'cumulate' => max(0, $fans['cumulate'] - 1),
]);
}*/
// 删除各种记录
\Phpcmf\Service::M()->db->table(weixin_wxtable('user'))->where('openid', $this->data['FromUserName'])->delete();
\Phpcmf\Service::M()->db->table(weixin_wxtable('follow'))->where('openid', $this->data['FromUserName'])->delete();
\Phpcmf\Service::M()->db->table(weixin_wxtable('message'))->where('openid', $this->data['FromUserName'])->delete();
\Phpcmf\Service::M()->db->table('member_oauth')->where('oauth', 'wechat')->where('oid', $this->data['FromUserName'])->delete();
break;
default:
if (strpos($this->data['EventKey'], 'App::') === 0) {
// 表示执行插件控制器
$file = APPPATH.'Plugins/'.ucfirst(substr($this->data['EventKey'], 5)).'/Run.php';
if (!is_file($file)) {
log_message('error', '微信小插件运行程序不存在:'.$file);
} else {
require $file;
}
// 初始化用户 将其加入到粉丝组里面
$this->_init_user();
} elseif (strpos($this->data['EventKey'], 'bang-') === 0 || strpos($this->data['EventKey'], 'qrscene_bang-') === 0) {
// 表示通过扫描二维码关注微信公众号
$this->_gz_bang_user();
} elseif (strpos($this->data['EventKey'], 'login-') === 0 || strpos($this->data['EventKey'], 'qrscene_login-') === 0) {
// 表示通过扫描二维码关注微信公众号
$this->_gz_login_user();
}
break;
}
break;
default:
# code...
// 初始化用户 将其加入到粉丝组里面
$this->_init_user();
break;
}
}
}
}
exit;
}
// 表示通过扫描二维码关注微信公众号
private function _gz_bang_user() {
list($s, $uid) = explode('-', $this->data['EventKey']);
$member = $uid ? dr_member_info($uid) : [];
if ($member) {
// 绑定账号
$rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$this->data['FromUserName']);
if (!$rt['code']) {
return;
} elseif (!$rt['data']['openid']) {
return;
}
\Phpcmf\Service::M('member')->insert_oauth($uid, 'login', [
'oid' => $rt['data']['openid'],
'oauth' => 'wechat',
'avatar' => (string)$rt['data']['headimgurl'],
'unionid' => (string)$rt['data']['unionid'],
'nickname' => dr_emoji2html($rt['data']['nickname']?$rt['data']['nickname']:'微信用户'),
'expire_at' => SYS_TIME,
'access_token' => 0,
'refresh_token' => 0,
], '');
\Phpcmf\Service::M()->db->table(weixin_wxtable('user'))->where('openid', $this->data['FromUserName'])->update([
'uid' => (int)$member['uid'],
'username' => (string)$member['username'],
]);
if ( $this->weixin['config']['gz']) {
if ($this->weixin['config']['gz_type']) {
// 回复素材
$this->_to_weixin_content($this->weixin['config']['gz_value_1']);
} else {
// 回复文本
$this->_to_weixin_text($this->_gz_msg($this->weixin['config']['gz_value_0'], $member));
}
}
}
}
// 表示通过扫描二维码关注微信公众号
private function _gz_login_user() {
list($s, $ep) = explode('-', $this->data['EventKey']);
if ($ep) {
// 登录或注册账号
$rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$this->data['FromUserName']);
if (!$rt['code']) {
return;
}
$user = \Phpcmf\Service::M()->table('member_oauth')->where('oid', $rt['data']['openid'])->where('oauth', 'wechat')->getRow();
if (!$user && isset($rt['data']['unionid']) && $rt['data']['unionid']) {
$user = \Phpcmf\Service::M()->table('member_oauth')->where('unionid', $rt['data']['unionid'])->getRow();
}
if ($user['uid']) {
// 已经关注,就登录
\Phpcmf\Service::M()->table('member_oauth')->update($user['id'], [
'refresh_token' => 'login-'.$ep,
]);
if ($this->weixin['config']['gz_login']) {
$user = dr_member_info($user['uid']);
$this->_to_weixin_text(str_replace(['{user}', '{time}', '{name}'], [$user['username'], dr_date(SYS_TIME), $user['name']], $this->weixin['config']['gz_login']));
} else {
$this->_to_weixin_text('通过扫描二维码在PC登录成功');
}
return;
}
if ($this->member_cache['oauth']['login']) {
// 直接注册
$oauth = [
'oid' => $rt['data']['openid'],
'oauth' => 'wechat',
'avatar' => $rt['data']['headimgurl'],
'unionid' => (string)$rt['data']['unionid'],
'nickname' => dr_emoji2html($rt['data']['nickname']?$rt['data']['nickname']:'微信用户'),
'expire_at' => SYS_TIME,
'access_token' => 0,
'refresh_token' => 'login-'.$ep,
];
$rt2 = \Phpcmf\Service::M('member')->insert_oauth(0, 'register', $oauth, '');
if (!$rt2['code']) {
$this->_to_weixin_text($rt2['msg']);
}
$oauth['id'] = $rt2['code'];
$groupid = (int)$this->member_cache['register']['groupid'];
if (!$groupid) {
$this->_to_weixin_text('系统没有设置默认注册的用户组');
}
$rt = \Phpcmf\Service::M('member')->register_oauth($groupid, $oauth);
if ($rt['code']) {
// 登录成功
if ($this->weixin['config']['gz_reg']) {
$user = $rt['data']['member'];
$this->_to_weixin_text(str_replace(['{user}', '{time}', '{name}'], [$user['username'], dr_date(SYS_TIME), $user['name']], $this->weixin['config']['gz_reg']));
} else {
$this->_to_weixin_text('通过扫描二维码在PC注册成功,随机账号为:'.$rt['data']['member']['username']);
}
} else {
$this->_to_weixin_text($rt['msg']);
}
} else {
// 绑定账号
$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode(SITE_URL.'index.php?s=weixin&c=member&ep=login-'.$ep).'&response_type=code&scope=snsapi_base&state=member#wechat_redirect';
$txt = $this->weixin['config']['bang_text'] ? $this->weixin['config']['bang_text'] : '您还没有绑定本站账号,点我立即绑定账号';
$this->_to_weixin_text('<a href="'.$url.'">'.$txt.'</a>');
}
}
}
// 替换返回值
private function _gz_msg($tpl, $user) {
if (!isset($user['username']) || !$user['username']) {
$user['username'] = $user['nickname'];
}
return str_replace('{username}', $user['username'], (string)$tpl);
}
// 初始化用户情况
private function _init_user() {
$rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$this->data['FromUserName']);
if (!$rt['code']) {
return;
}
$user = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->where('openid', $this->data['FromUserName'])->getRow();
if (!$user) {
// 入库粉丝表
$user = \Phpcmf\Service::M('User', APP_DIR)->insert_user($rt['data']);
} else {
// 更新
$user = \Phpcmf\Service::M('User', APP_DIR)->update_user($user, $rt['data']);;
}
// 判断当用户没有绑定会员的情况时
if (!$user['uid']) {
// 判断是否绑定过公众号
$bang = \Phpcmf\Service::M()->table('member_oauth')->where('oauth', 'wechat')->where('oid', $this->data['FromUserName'])->getRow();
if (!$bang && isset($user['unionid']) && $user['unionid']) {
$bang = \Phpcmf\Service::M()->table('member_oauth')->where('unionid', $user['unionid'])->getRow();
}
if ($bang && $bang['uid']) {
$member = dr_member_info($bang['uid']);
\Phpcmf\Service::M()->table(weixin_wxtable('user'))->update($user['id'], [
'uid' => (int)$bang['uid'],
'username' => (string)$member['username'],
]);
} else {
if ($this->weixin['config']['bang']) {
// 提醒用户绑定会员
$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode(SITE_URL.'index.php?s=weixin&c=member').'&response_type=code&scope=snsapi_base&state=member#wechat_redirect';
$txt = $this->weixin['config']['bang_text'] ? $this->weixin['config']['bang_text'] : '您还没有绑定本站账号,点我立即绑定账号';
$this->_to_weixin_text('<a href="'.$url.'">'.$txt.'</a>');
}
return $user;
}
}
// 存储cookie
$this->uid = $user['uid'];
$this->member = \Phpcmf\Service::M('member')->get_member($this->uid);
\Phpcmf\Service::M('member')->save_cookie($this->member);
return $this->member;
}
// 验证微信请求
private function checkSignature() {
$nonce = (string)$_GET["nonce"];
$signature = (string)$_GET["signature"];
$timestamp = (string)$_GET["timestamp"];
$token = $this->weixin['account']['token'];
$tmpArr = [$token, $timestamp, $nonce];
sort($tmpArr, SORT_STRING);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if ($tmpStr == $signature){
return true;
} else{
return false;
}
}
// ================================================
// 回复文本
public function _to_weixin_text($text) {
if (!$text) {
return;
}
echo '<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA['.$text.']]></Content>
</xml>';exit;
}
// 回复素材
public function _to_weixin_content($id) {
$id = (int)substr($id, 5);
if (!$id) {
return;
}
// 查询内容
$data = \Phpcmf\Service::M()->table(weixin_wxtable('content'))->get($id);
if (!$data) {
return;
}
$value = dr_string2array($data['content']);
$data['content'] = [];
if ($value) {
for ($i = 1; $i<=9; $i++) {
if (!$value['thumb_'.$i] || !$value['title_'.$i]) {
break;
}
$data['content'][$i] = [
"title_".$i => $value['title_'.$i],
"thumb_".$i => dr_get_file($value['thumb_'.$i]),
"description_".$i => $value['description_'.$i],
"url_".$i => html_entity_decode(dr_url_prefix($value['url_'.$i]))
];
}
}
#file_put_contents(WRITEPATH."weixin/wx.txt", var_export($data, true));
return $this->_to_weixin_content_data($data);
}
// 开始回复
public function _to_weixin_content_data($cdata) {
if (!$cdata['tid']) {
$cdata['tid'] = 'index';
}
switch ($cdata['tid']) {
case 'index':
// 回复图文
$count = 0;
$text = '';
foreach ($cdata['content'] as $i => $t) {
if ($t['title_'.$i]) {
$count ++;
$text.= '<item>
<Title><![CDATA['.$t['title_'.$i].']]></Title>
<Description><![CDATA['.$t['description_'.$i].']]></Description>
<PicUrl><![CDATA['.$t['thumb_'.$i].']]></PicUrl>
<Url><![CDATA['.$t['url_'.$i].']]></Url>
</item>';
}
}
if (!$count) {
$this->_to_weixin_text('没有找到相关内容');
return;
}
exit('
<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>'.$count.'</ArticleCount>
<Articles>
'.$text.'
</Articles>
</xml>
');
break;
case 'image':
if (!$cdata['media_id']) {
$this->_to_weixin_text('没有找到相关内容');
return;
}
exit('<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA['.$cdata['media_id'].']]></MediaId>
</Image>
</xml>');
break;
case 'voice':
if (!$cdata['media_id']) {
$this->_to_weixin_text('没有找到相关内容');
return;
}
exit('<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[voice]]></MsgType>
<Image>
<MediaId><![CDATA['.$cdata['media_id'].']]></MediaId>
</Image>
</xml>');
break;
case 'video':
if (!$cdata['media_id']) {
$this->_to_weixin_text('没有找到相关内容');
return;
}
exit('<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[video]]></MsgType>
<Image>
<MediaId><![CDATA['.$cdata['media_id'].']]></MediaId>
</Image>
</xml>');
break;
case 'link':
exit('<xml>
<ToUserName><![CDATA['.$this->data['FromUserName'].']]></ToUserName>
<FromUserName><![CDATA['.$this->data['ToUserName'].']]></FromUserName>
<CreateTime>'.(SYS_TIME+2).'</CreateTime>
<MsgType><![CDATA[link]]></MsgType>
<Title><![CDATA['.$cdata['title'].']]></Title>
<Description><![CDATA['.$cdata['description'].']]></Description>
<Url><![CDATA['.$cdata['url'].']]></Url>
</xml>');
break;
}
$this->_to_weixin_text('没有找到相关内容');
}
/* 组装xml数据 */
private function _data2xml($xml, $data, $item = 'item') {
foreach ( $data as $key => $value ) {
is_numeric ( $key ) && ($key = $item);
if (is_array ( $value ) || is_object ( $value )) {
$child = $xml->addChild ( $key );
$this->_data2xml ( $child, $value, $item );
} else {
if (is_numeric ( $value )) {
$child = $xml->addChild ( $key, $value );
} else {
$child = $xml->addChild ( $key );
$node = dom_import_simplexml ( $child );
$node->appendChild ( $node->ownerDocument->createCDATASection ( $value ) );
}
}
}
}
}
+408
View File
@@ -0,0 +1,408 @@
<?php namespace Phpcmf\Controllers;
// 绑定账号
class Member extends \Phpcmf\Common {
private $access_token;
// 从微信菜单中进入授权
public function index() {
$code = \Phpcmf\Service::L('input')->get('code');
$state = \Phpcmf\Service::L('input')->get('state');
$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$this->weixin['account']['appid'].'&secret='.$this->weixin['account']['appsecret'].'&code='.$code.'&state='.$state.'&grant_type=authorization_code';
$rt = wx_get_https_json_data($url);
if (!$rt['code']) {
$this->_msg(0, $rt['msg']);
}
$user = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->where('openid', $rt['data']['openid'])->getRow();
if (!$user) {
$rts = weixin_get_access_token();
$rts['code'] && $this->access_token = $rts['msg'];
$rts = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->access_token.'&openid='.$rt['data']['openid']);
if (!$rts['code']) {
$this->_msg(0, $rts['msg']);
} elseif (!$rts['data']['nickname']) {
//$this->_msg(0, '未获取到微信用户昵称');
}
$user = \Phpcmf\Service::M('User', APP_DIR)->insert_user($rts['data']);
}
$oid = $rt['data']['openid'];
$user['uid'] = (int)$user['uid'];
$rt = \Phpcmf\Service::M('member')->insert_oauth($user['uid'], 'login', [
'oid' => $oid,
'oauth' => 'wechat',
'avatar' => $user['headimgurl'],
'unionid' => (string)$user['unionid'],
'nickname' => dr_emoji2html($user['nickname']?$user['nickname']:'微信用户'),
'expire_at' => SYS_TIME,
'access_token' => 0,
'refresh_token' => 0,
], $state);
if (!$rt['code']) {
$this->_msg(0, $rt['msg']);
exit;
} else {
if ($user['uid']) {
// 验证是否存在
$member = \Phpcmf\Service::M('member')->member_info($user['uid']);
if (!$member) {
\Phpcmf\Service::M()->db->table('weixin_user')->where('uid', $user['uid'])->delete();
}
}
dr_redirect($rt['msg']);
}
exit;
}
// 小程序读取手机号
public function xcx_phone()
{
if (IS_POST) {
if (!$_POST['js_code']) {
$this->_json(0, 'js_code数据获取失败');
}
$rts = xcx_get_access_token();
if (!$rts['code']) {
$this->_json(0, $rts['msg']);
}
$url = 'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=' . $rts['msg'];
$rt = wx_post_https_json_data(($url), [
'code' => $_POST['js_code']
]);
$token = $rt['data'];
if (!$token) {
$this->_json(0, '手机号获取失败');
} elseif (isset($token['errcode']) && $token['errcode']) {
$this->_json(0, '手机号错误代码(' . $token['errcode'] . '):' . $token['errmsg'] . ' appid=' . $this->weixin['xcx']['appid'] . '&secret=' . $this->weixin['xcx']['appsecret'] . '');
}
$this->_json(1, 'ok', $token['phone_info']['phoneNumber']);
}
}
// 小程序登录
public function xcx() {
if (IS_POST) {
$json = json_decode($_POST['json'], true);
if (!$json) {
$this->_json(0, 'POST数据解析失败');
} elseif (!$_POST['js_code']) {
$this->_json(0, 'js_code数据获取失败');
}
$url = 'https://api.weixin.qq.com/sns/jscode2session?appid='.$this->weixin['xcx']['appid'].'&secret='.$this->weixin['xcx']['appsecret'].'&js_code='.$_POST['js_code'].'&grant_type=authorization_code';
$token = json_decode(dr_catcher_data($url), true);
if (!$token) {
$this->_json(0, 'jscode2session获取失败');
} elseif (isset($token['errcode']) && $token['errcode']) {
$this->_json(0, 'jscode2session错误代码('.$token['errcode'].'):'.$token['errmsg'].' appid='.$this->weixin['xcx']['appid'].'&secret='.$this->weixin['xcx']['appsecret'].'');
} elseif (!$token['openid']) {
$this->_json(0, 'jscode2session:openid获取失败');
}
$rt = \Phpcmf\Service::M('member')->insert_oauth(0, 'login', [
'oid' => $token['openid'],
'oauth' => 'wxxcx',
'avatar' => $json['avatarUrl'],
'unionid' => (string)$token['unionid'],
//'nickname' => dr_emoji2html($json['nickName']),
'nickname' => dr_emoji2html($user['nickName']?$user['nickName']:'微信用户'),
'expire_at' => SYS_TIME,
'access_token' => $token['session_key'],
'refresh_token' => '',
]);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$oauth = \Phpcmf\Service::M()->table('member_oauth')->get($rt['code']);
if (!$oauth) {
$this->_json(0, '服务端储存用户失败');
} elseif ($oauth['uid']) {
$rt = \Phpcmf\Service::M('member')->login_uid($oauth, $oauth['uid']);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$this->_json(1, 'login', $rt['data']);
}
if ($this->weixin['xcx']['login']) {
// 直接登录
$rt = \Phpcmf\Service::M('member')->register_oauth(0, $oauth);
if ($rt['code']) {
// 登录成功
$this->_json(1, 'login', $rt['data']);
} else {
$this->_json(0, $rt['msg']);
}
} else {
// 提示注册
$oauth['nickname'] = dr_html2emoji($oauth['nickname']?$oauth['nickname']:'微信用户');
$this->_json(1, 'register', $oauth);
}
} else {
$this->_json(0, '非POST提交');
}
exit;
}
// 小程序绑定账号
public function xcx_bang() {
if (IS_POST) {
$oid = (int)\Phpcmf\Service::L('Input')->post('oid');
$post = \Phpcmf\Service::L('Input')->post('data', true);
if (!$post) {
$this->_json(0, 'POST数据解析失败');
} elseif (!$oid) {
$this->_json(0, '小程序OpenId为空');
}
$oauth = \Phpcmf\Service::M()->table('member_oauth')->get($oid);
if (!$oauth) {
$this->_json(0, '服务端用户不存在');
} elseif ($oauth['uid']) {
$rt = \Phpcmf\Service::M('member')->login_uid($oauth, $oauth['uid']);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$this->_json(1, 'ok', $rt['data']);
}
// 登录绑定
if (empty($post['username']) || empty($post['password'])) {
$this->_json(0, dr_lang('账号或密码必须填写'));
} else {
$rt = \Phpcmf\Service::M('member')->login($post['username'], $post['password']);
if ($rt['code']) {
// 登录成功
\Phpcmf\Service::M()->db->table('member_oauth')->where('id', $oid)->update(['uid' => $rt['data']['member']['id']]);
$this->_json(1, 'ok', $rt['data']);
} else {
$this->_json(0, $rt['msg']);
}
}
} else {
$this->_json(0, '非POST提交');
}
}
// 小程序注册账号
public function xcx_reg() {
if (IS_POST) {
$oid = (int)\Phpcmf\Service::L('Input')->post('oid');
$post = \Phpcmf\Service::L('Input')->post('data', true);
if (!$post) {
$this->_json(0, 'POST数据解析失败');
} elseif (!$oid) {
$this->_json(0, '小程序OpenId为空');
}
$oauth = \Phpcmf\Service::M()->table('member_oauth')->get($oid);
if (!$oauth) {
$this->_json(0, '服务端用户不存在');
} elseif ($oauth['uid']) {
$rt = \Phpcmf\Service::M('member')->login_uid($oauth, $oauth['uid']);
if (!$rt['code']) {
$this->_json(0, $rt['msg']);
}
$this->_json(1, 'ok', $rt['data']);
}
// 注册
if (empty($post['password'])) {
$this->_json(0, dr_lang('密码必须填写'), ['field' => 'password']);
} elseif ($post['password'] != $post['password2']) {
$this->_json(0, dr_lang('确认密码不一致'), ['field' => 'password2']);
} else {
$rt = \Phpcmf\Service::M('member')->register_oauth_bang($oauth, 0, [
'username' => (string)$post['username'],
'phone' => (string)$post['phone'],
'email' => (string)$post['email'],
'password' => dr_safe_password($post['password']),
'name' => dr_safe_replace($post['name']),
]);
if ($rt['code']) {
// 注册绑定成功
$this->_json(1, 'ok', $rt['data']);
} else {
$this->_json(0, $rt['msg'], ['field' => $rt['data']['field']]);
}
}
} else {
$this->_json(0, '非POST提交');
}
}
// 公众号浏览url弹出登录
//
// 公众号内自动登陆
public function login() {
$code = \Phpcmf\Service::L('input')->get('code');
$state = \Phpcmf\Service::L('input')->get('state');
$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$this->weixin['account']['appid'].'&secret='.$this->weixin['account']['appsecret'].'&code='.$code.'&state='.$state.'&grant_type=authorization_code';
$rt = wx_get_https_json_data($url);
if (!$rt['code']) {
$this->_msg(0, $rt['msg']);
}
// 刷新
$rs = wx_get_https_json_data('https://api.weixin.qq.com/sns/oauth2/refresh_token?appid='.$this->weixin['account']['appid'].'&grant_type=refresh_token&refresh_token='.$rt['data']['refresh_token']);
if (!$rs['code']) {
$this->_msg(0, $rs['msg']);
}
$rts = wx_get_https_json_data('https://api.weixin.qq.com/sns/userinfo?access_token='.$rs['data']['access_token'].'&openid='.$rt['data']['openid'].'&lang=zh_CN');
if (!$rts['code']) {
$this->_msg(0, $rts['msg']);
} elseif (!$rts['data']['nickname']) {
//$this->_msg(0, '未获取到微信用户昵称');
}
$user = \Phpcmf\Service::M()->table(weixin_wxtable('user'))->where('openid', $rt['data']['openid'])->getRow();
if (!$user) {
$user = \Phpcmf\Service::M('User', APP_DIR)->insert_user($rts['data']);
$user['uid'] = 0;
} else {
$user = \Phpcmf\Service::M('User', APP_DIR)->update_user($user, $rts['data']);
}
// $rt = \Phpcmf\Service::M('member')->register_oauth($groupid, $oauth);
$oid = $rt['data']['openid'];
$rt = \Phpcmf\Service::M('member')->insert_oauth($user['uid'], 'login', [
'oid' => $oid,
'oauth' => 'wechat',
'avatar' => $user['headimgurl'],
'unionid' => (string)$user['unionid'],
'nickname' => dr_emoji2html($user['nickname']),
'expire_at' => SYS_TIME,
'access_token' => 0,
'refresh_token' => 0,
], $state);
if (!$rt['code']) {
$this->_msg(0, $rt['msg']);
exit;
} else {
if ($user['uid'] && $state) {
// 存储cookie
$member = \Phpcmf\Service::M('member')->member_info($user['uid']);
if (!$member) {
\Phpcmf\Service::M()->db->table('weixin_user')->where('uid', $user['uid'])->delete();
dr_redirect($rt['msg']);
exit;
}
\Phpcmf\Service::M('member')->save_cookie($member, 1);
$goto_url = urldecode($state);
if (strpos($goto_url, 'is_admin_call')) {
// 存储后台回话
\Phpcmf\Service::M('auth')->save_login_auth('wechat', $user['uid']);
$goto_url.= '&uid='.$user['uid'];
} elseif (strpos($state, DOMAIN_NAME) === false) {
// 域名不同的情况下
$rt = \Phpcmf\Service::M('member')->sso($member, 1);
$sso = '';
foreach ($rt as $url) {
$sso.= '<script src="'.$url.'"></script>';
}
$this->_msg(1, dr_lang('%s,欢迎回来', dr_html2emoji($user['nickname'])).$sso, $goto_url, 0);exit;
}
dr_redirect($goto_url);
} else {
dr_redirect($rt['msg']);
}
}
}
// 微信公众号绑定
public function wxbang() {
if (!$this->uid) {
$ep = dr_safe_replace(\Phpcmf\Service::L('input')->get('ep'));
$rt = \Phpcmf\Service::M()->table('member_oauth')->where('refresh_token', $ep)->where('uid>0')->where('oauth', 'wechat')->getRow();
if ($rt) {
// 为他登录
// 存储cookie
$this->uid = $rt['uid'];
$this->member = \Phpcmf\Service::M('member')->get_member($this->uid);
$sso = \Phpcmf\Service::M('member')->login_oauth('wechat', $this->member);
// 存储后台回话
if (isset($_GET['is_admin_call'])) {
\Phpcmf\Service::M('auth')->save_login_auth('wechat', $this->uid);
$this->_json(1, 'ok', [
'url' => urldecode($_GET['is_admin_call']).'&uid='.$this->uid,
'sso' => $sso,
]);
} else {
$this->_json(1, 'ok', [
'sso' => $sso,
]);
}
}
} else {
$rt = \Phpcmf\Service::M()->table('member_oauth')->where('uid', $this->uid)->where('oauth', 'wechat')->getRow();
}
if (!$rt) {
$this->_json(0, '');
} else {
// 绑定成功更新头像
list($cache_path) = dr_avatar_path();
$path = $cache_path.dr_avatar_dir($this->uid);
$file = $path.$this->uid.'.jpg';
if (!is_file($file)) {
// 没有头像下载头像
$img = dr_catcher_data($rt['avatar']);
if (strlen($img) > 20) {
if (!is_dir($path)) {
dr_mkdirs($path);
}
file_put_contents($file, $img);
}
}
// 存储后台回话
if (isset($_GET['is_admin_call'])) {
\Phpcmf\Service::M('auth')->save_login_auth('wechat', $this->uid);
$this->_json($rt['access_token'] ? 0 : 1, 'ok', [
'url' => urldecode($_GET['is_admin_call']).'&uid='.$this->uid,
'sso' => \Phpcmf\Service::M('member')->sso($this->member, 1),
]);
} else {
$this->_json($rt['access_token'] ? 0 : 1, 'ok', $rt);
}
}
}
// 公众号浏览url弹出登录 url
public function login_url() {
$url = (!$this->is_mobile ? SITE_URL : SITE_MURL).'index.php?s=weixin&c=member&m=login';
if ($_GET['back'] && strpos($_GET['back'], 'c=member&m=login') === false) {
$burl = $_GET['back'];
} else {
$burl = (!$this->is_mobile ? SITE_URL : SITE_MURL).'index.php?s=member';
}
dr_redirect('https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode($url).'&response_type=code&scope=snsapi_userinfo&state='.urlencode($burl).'#wechat_redirect');
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php namespace Phpcmf\Controllers;
// 素材内容显示
class Show extends \Phpcmf\Common {
public function index() {
$id = (int)\Phpcmf\Service::L('Input')->get('id');
$p = (int)\Phpcmf\Service::L('Input')->get('p');
$data = \Phpcmf\Service::M()->table(weixin_wxtable('content'))->get($id);
if (!$data) {
$this->_msg(0, '微信素材内容不存在');
} elseif ($data['tid'] != 'index') {
$this->_msg(0, '素材内容不正确');
}
$content = dr_string2array($data['content']);
if (!$content['title_'.$p] || !$content['content_'.$p]) {
$this->_msg(0, '素材内容不完整');
}
$share = \Phpcmf\Service::L('jssdk', 'weixin');
\Phpcmf\Service::V()->assign([
'title' => $content['title_'.$p],
'thumb' => $content['thumb_'.$p],
'author' => $content['author_'.$p],
'content' => htmlspecialchars_decode($content['content_'.$p]),
'inputtime' => dr_date($data['inputtime']),
'_inputtime' => $data['inputtime'],
'description' => $content['description_'.$p],
'signPackage' => $share->GetSignPackage(),
]);
\Phpcmf\Service::V()->display('show.html');exit;
}
}
File diff suppressed because one or more lines are too long
+124
View File
@@ -0,0 +1,124 @@
<?php namespace Phpcmf\Library;
class Jssdk {
private $weixin;
private $appId;
private $appSecret;
public function __construct() {
$this->weixin = \Phpcmf\Service::C()->get_cache('weixin'); // 配置
$this->appId = $this->weixin['account']['appid'];
$this->appSecret = $this->weixin['account']['appsecret'];
}
public function getSignPackage() {
$jsapiTicket = $this->getJsApiTicket();
// 注意 URL 一定要动态获取,不能 hardcode.
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
$url = $protocol.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$timestamp = time();
$nonceStr = $this->createNonceStr();
// 这里参数的顺序要按照 key 值 ASCII 码升序排序
$string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
$signature = sha1($string);
$signPackage = array(
"appId" => $this->appId,
"nonceStr" => $nonceStr,
"timestamp" => $timestamp,
"url" => $url,
"signature" => $signature,
"rawString" => $string
);
return $signPackage;
}
private 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;
}
private function getJsApiTicket() {
// jsapi_ticket 应该全局存储与更新,以下代码以写入到文件中做示例
$data = json_decode($this->get_php_file("jsapi_ticket.php"));
if (!$data || $data->expire_time < SYS_TIME) {
$accessToken = $this->getAccessToken();
// 如果是企业号用以下 URL 获取 ticket
// $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
$res = json_decode($this->httpGet($url));
$ticket = $res->ticket;
if ($ticket) {
$data = [
'expire_time' => SYS_TIME + 7000,
'jsapi_ticket' => $ticket
];
$this->set_php_file("jsapi_ticket.php", json_encode($data));
}
} else {
$ticket = $data->jsapi_ticket;
}
return $ticket;
}
private function getAccessToken() {
// access_token 应该全局存储与更新,以下代码以写入到文件中做示例
$data = json_decode($this->get_php_file("access_token.php"));
if (!$data || $data->expire_time < SYS_TIME) {
// 如果是企业号用以下URL获取access_token
// $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret";
$res = json_decode($this->httpGet($url));
$access_token = $res->access_token;
if ($access_token) {
$data = [
'expire_time' => SYS_TIME + 7000,
'access_token' => $access_token
];
$this->set_php_file("access_token.php", json_encode($data));
}
} else {
$access_token = $data->access_token;
}
return $access_token;
}
private function httpGet($url) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_TIMEOUT, 500);
// 为保证第三方服务器与微信服务器之间数据传输的安全性,所有微信接口采用https方式调用,必须使用下面2行代码打开ssl安全校验。
// 如果在部署过程中代码在此处验证失败,请到 http://curl.haxx.se/ca/cacert.pem 下载新的证书判别文件。
if (substr($url, 0, 8) == "https://") {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, true); // 从证书中检查SSL加密算法是否存在
}
curl_setopt($curl, CURLOPT_URL, $url);
$res = curl_exec($curl);
curl_close($curl);
return $res;
}
private function get_php_file($filename) {
return trim(substr(file_get_contents(WRITEPATH.'temp/'.$filename), 15));
}
private function set_php_file($filename, $content) {
$fp = fopen(WRITEPATH.'temp/'.$filename, "w");
fwrite($fp, "<?php exit();?>" . $content);
fclose($fp);
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php namespace Phpcmf\Model\Weixin;
// 权限验证
class Auth extends \Phpcmf\Model
{
// 判断底部链接的显示权限
public function is_bottom_auth($mid) {
if (SITE_ID == 1) {
return 1;
}
// 这里的程序体,有权限返回1,没权限返回0
return 0;
}
// 判断右侧链接的显示权限
public function is_link_auth($mid) {
// $mid 是当前模块的目录名称
// 这里的程序体,显示返回1,不显示返回0
return 1;
}
public function is_tpl_use($mid, $data) {
$config = \Phpcmf\Service::R(WRITEPATH.'config/weixin_sendtpl.php');
if (!isset($config[$mid])) {
return 0;
} elseif (!isset($config[$mid]['use']) || !$config[$mid]['use']) {
return 0;
}
return 1;
}
}
+516
View File
@@ -0,0 +1,516 @@
<?php namespace Phpcmf\Model;
class User extends \Phpcmf\Model
{
public $openid;
// 获取微信表名
public function wxtable($name) {
return weixin_wxtable($name);
}
// 绑定二维码
public function qrcode_bang($member) {
$rt = weixin_get_access_token();
if ($rt['code']) {
$access_token = $rt['msg'];
$param = [
'expire_seconds' => 2592000,
'action_name' => 'QR_STR_SCENE',
'action_info' => array(
'scene' => array(
'scene_str' => $member ? 'bang-'.(int)$member['id'] : 'login-'.md5(SYS_TIME.(string)$_SERVER['HTTP_USER_AGENT']),
),
)
];
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=' . $access_token,
$param
);
if (!$rt['code']) {
return dr_return_data(0, 'qrcode '.$rt['msg']);
}
// 更新状态
if ($member) {
\Phpcmf\Service::M()->db->table('member_oauth')->where('uid', $member['id'])->where('oauth', 'wechat')->update([
'access_token' => 1,
]);
}
$url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=' . $rt['data']['ticket'];
return dr_return_data(1, $url, $param);
} else {
return dr_return_data(0, 'access_token '.$rt['msg']);
}
}
// 获取本地用户组信息
public function get_group_data() {
$data = $this->db->table(weixin_wxtable('group'))->orderBy('id asc')->get()->getResultArray();
if (!$data) {
return [];
}
$rt = [];
foreach ($data as $t) {
$rt[$t['tag']] = $t;
}
return $rt;
}
// 服务器获取用户组
public function down_group() {
$rt = weixin_get_access_token();
if (!$rt['code']) {
return $rt;
}
$rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/tags/get?access_token='.$rt['msg']);
if (!$rt['code']) {
return $rt;
}
if ($rt['data']['tags']) {
\Phpcmf\Service::M()->table(weixin_wxtable('group'))->clear_all();
foreach ($rt['data']['tags'] as $t) {
$this->db->table(weixin_wxtable('group'))->insert([
'tag' => $t['id'],
'name' => $t['name'],
'count' => $t['count'],
'groupid' => 0,
]);
}
return dr_return_data(1, 'ok');
} else {
return dr_return_data(0, '公众号上没有任何粉丝组');
}
}
// 获取同步规则值
private function _get_menu_data($t) {
$data = array(
'type' => $t['type'],
'name' => dr_html2emoji($t['name']),
);
//$root_url = \Phpcmf\Service::C()->site_info[1]['SITE_MURL'] ? \Phpcmf\Service::C()->site_info[1]['SITE_MURL'] : ROOT_URL;
$root_url = ROOT_URL;
switch ($t['type']) {
case 'view':
$data['url'] = $t['value'];
break;
case 'login':
$data['url'] = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.\Phpcmf\Service::C()->weixin['account']['appid'].'&redirect_uri='.urlencode($root_url.'index.php?s=weixin&c=member').'&response_type=code&scope=snsapi_base&state='.urlencode($t['value']).'#wechat_redirect';
$data['type'] = 'view';
break;
case 'article_view_limited':
$data['article_id'] = $t['value'];
break;
case 'miniprogram':
$value = dr_string2array($t['value']);
$data['appid'] = $value['appid'];
$data['pagepath'] = $value['path'];
$data['url'] = $value['url'];
break;
default:
$data['key'] = $t['value'];
break;
}
return $data;
}
// 服务器同步更新菜单
public function sync_menu() {
$at = weixin_get_access_token();
if (!$at['code']) {
return $at;
}
// 全局菜单
$data = $this->db->table(weixin_wxtable('menu'))->where('gid', 0)->where('pid', 0)->orderBy('displayorder asc')->get()->getResultArray();
if ($data) {
$json = array();
foreach ($data as $i => $t) {
$list = $this->db->table(weixin_wxtable('menu'))->where('pid', (int)$t['id'])->orderBy('displayorder asc')->get()->getResultArray();
if ($list) {
$val = array();
foreach ($list as $c) {
$val[] = $this->_get_menu_data($c);
}
$json[] = array(
'name' => dr_html2emoji($t['name']),
'sub_button' => $val
);
} else {
$json[] = $this->_get_menu_data($t);
}
}
$data = array('button'=>$json);
$rt = wx_post_https_json_data('https://api.weixin.qq.com/cgi-bin/menu/create?access_token='.$at['msg'], $data);
if (!$rt['code']) {
$rt['msg'] = '全局菜单:'.$rt['msg'];
return $rt;
}
} else {
return dr_return_data(0, '你还没有创建菜单');
}
// 个性菜单
$group = $this->db->table(weixin_wxtable('group'))->orderBy('id asc')->get()->getResultArray();
if ($group) {
foreach ($group as $g) {
$gid = $g['tag'];
$data = $this->db->table(weixin_wxtable('menu'))->where('gid', $gid)->where('pid', 0)->orderBy('displayorder asc')->get()->getResultArray();
if ($data) {
$json = array();
foreach ($data as $i => $t) {
$list = $this->db->table(weixin_wxtable('menu'))->where('pid', (int)$t['id'])->orderBy('displayorder asc')->get()->getResultArray();
if ($list) {
$val = array();
foreach ($list as $c) {
$val[] = $this->_get_menu_data($c);
}
$json[] = array(
'name' => dr_html2emoji($t['name']),
'sub_button' => $val
);
} else {
$json[] = $this->_get_menu_data($t);
}
}
$data = array(
'button'=>$json,
'matchrule' => [
'tag_id' => $gid,
]
);
$rt = wx_post_https_json_data('https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token='.$at['msg'], $data);
if (!$rt['code']) {
$rt['msg'] = '个性菜单['.$g['name'].']'.$rt['msg'];
return $rt;
}
$this->db->table(weixin_wxtable('menu'))->where('gid', $gid)->update(['menuid' => (int)$rt['data']['menuid']]);
}
}
}
return dr_return_data(1, 'ok');
//https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN
}
// 服务器获取菜单
public function down_menu() {
$rt = weixin_get_access_token();
if (!$rt['code']) {
return $rt;
}
$rt = wx_get_https_json_data('https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token='.$rt['msg']);
if (!$rt['code']) {
return $rt;
} elseif (!$rt['data']['is_menu_open']) {
return dr_return_data(0, '公众号上菜单没有开启');
} elseif ($rt['data']['selfmenu_info']) {
\Phpcmf\Service::M()->table(weixin_wxtable('menu'))->clear_all();
foreach ($rt['data']['selfmenu_info']['button'] as $top) {
if ($top['sub_button']) {
$this->db->table(weixin_wxtable('menu'))->insert([
'gid' => 0,
'pid' => 0,
'name' => dr_emoji2html($top['name']),
'type' => '',
'value' => '',
'displayorder' => 0,
]);
$pid = $this->db->insertID();
// 子菜单
foreach ($top['sub_button']['list'] as $menu) {
$this->db->table(weixin_wxtable('menu'))->insert([
'gid' => 0,
'pid' => $pid,
'name' => dr_emoji2html($menu['name']),
'type' => $menu['type'],
'value' => (string)($menu['url'] ? $menu['url'] : $menu['key']),
'displayorder' => 0,
]);
}
} else {
// 本身菜单
$this->db->table(weixin_wxtable('menu'))->insert([
'gid' => 0,
'pid' => 0,
'name' => dr_emoji2html($top['name']),
'type' => $top['type'],
'value' => (string)($top['url'] ? $top['url'] : $top['key']),
'displayorder' => 0,
]);
}
}
}
return dr_return_data(1, 'ok');
}
// 顶级菜单
public function top_menu() {
return $this->db->table(weixin_wxtable('menu'))->where('pid', 0)->orderBy('displayorder asc')->get()->getResultArray();
}
// 修改标签
public function edit_group($id, $name) {
$rt = weixin_get_access_token();
if (!$rt['code']) {
return $rt;
}
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/tags/update?access_token='.$rt['msg'],
[
'tag' => [
'id' => $id,
'name' => $name,
]
]
);
if (!$rt['code']) {
return $rt;
}
return dr_return_data(1, 'ok');
}
// 添加标签
public function add_group($name) {
$rt = weixin_get_access_token();
if (!$rt['code']) {
return $rt;
}
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/tags/create?access_token='.$rt['msg'],
[
'tag' => [
'name' => $name,
]
]
);
if (!$rt['code']) {
return $rt;
}
return dr_return_data($rt['data']['tag']['id'], 'ok');
}
// 删除标签
public function delete_group($id) {
$rt = weixin_get_access_token();
if (!$rt['code']) {
return $rt;
}
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/tags/delete?access_token='.$rt['msg'],
[
'tag' => [
'id' => $id,
]
]
);
if (!$rt['code']) {
return $rt;
}
return dr_return_data(1, 'ok');
}
// 更新本地账户表
public function insert_user($data) {
$save = [
'uid' => 0,
'username' => '',
'openid' => $data['openid'],
'nickname' => dr_emoji2html($data['nickname']?$data['nickname']:'微信用户'),
'sex' => $data['sex'],
'city' => $data['city'],
'province' => $data['province'],
'country' => $data['country'],
'headimgurl' => (string)$data['headimgurl'],
'subscribe' => (int)$data['subscribe_time'],
'subscribe_time' => SYS_TIME,
'unionid' => (string)$data['unionid'],
'remark' => dr_emoji2html($data['remark']),
'groupids' => $this->_get_groupids($data['tagid_list']),
'content' => dr_array2string($data),
];
$oauth = $this->db->table('member_oauth')->where('oid', $data['openid'])->get()->getRowArray();
if ($oauth) {
$save['uid'] = $oauth['uid'];
$save['username'] = \Phpcmf\Service::M('member')->username($save['uid']);
}
$row = $this->db->table(weixin_wxtable('user'))->where('openid', $data['openid'])->get()->getRowArray();
if ($row) {
$rt = $this->table(weixin_wxtable('user'))->update($row['id'], $save);
if ($rt['code']) {
$save['id'] = $row['id'];
return $save;
}
} else {
$rt = $this->table(weixin_wxtable('user'))->insert($save);
if ($rt['code']) {
$save['id'] = $rt['code'];
return $save;
}
}
return [];
}
// 更新本地账户表
public function update_user($user, $data, $time = SYS_TIME) {
$save = [
'openid' => $data['openid'],
'nickname' => dr_emoji2html($data['nickname']?$data['nickname']:'微信用户'),
'sex' => $data['sex'],
'city' => $data['city'],
'province' => $data['province'],
'country' => $data['country'],
'headimgurl' => $data['headimgurl'],
'subscribe' => (int)$data['subscribe_time'],
'subscribe_time' => $time,
'unionid' => (string)$data['unionid'],
'remark' => dr_emoji2html($data['remark']),
'groupids' => $this->_get_groupids($data['tagid_list']),
'content' => dr_array2string($data),
];
$this->table(weixin_wxtable('user'))->update($user['id'], $save);
return dr_array22array($user, $save);
}
// 更新组
public function add_member_group($uid, $groupid) {
$group = $this->db->table(weixin_wxtable('group'))->where('groupid', $groupid)->get()->getRowArray();
if (!$group) {
return;
}
$gid = $group['tag'];
$user = $this->db->table(weixin_wxtable('user'))->where('uid', $uid)->get()->getRowArray();
if ($user && $gid) {
$tags = dr_string2array($user['groupids']);
if (!dr_in_array($gid, $tags)) {
$tags[] = (string)$gid;
$this->table(weixin_wxtable('user'))->update($user['id'], [
'groupids' => $this->_get_groupids($tags),
]);
// 增加标签
$rt = weixin_get_access_token();
if ($rt['code']) {
$access_token = $rt['msg'];
$param = [
'openid_list' => [$user['openid']],
'tagid' => $gid,
];
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=' . $access_token,
$param
);
if (!$rt['code']) {
log_message('error', '联动变更微信组标签:'.$rt['msg']);
}
} else {
log_message('error', '联动变更微信组标签:'.$rt['msg']);
}
}
}
}
// 删除组
public function delete_member_group($uid, $groupid) {
$group = $this->db->table(weixin_wxtable('group'))->where('groupid', $groupid)->get()->getRowArray();
if (!$group) {
return;
}
$gid = $group['tag'];
$user = $this->db->table(weixin_wxtable('user'))->where('uid', $uid)->get()->getRowArray();
if ($user && $gid) {
$tags = dr_string2array($user['groupids']);
if (dr_in_array($gid, $tags)) {
$tags[] = (string)$gid;
foreach ($tags as $i => $v) {
if ($v == $gid) {
unset($tags[$i]);
}
}
$this->table(weixin_wxtable('user'))->update($user['id'], [
'groupids' => $this->_get_groupids($tags),
]);
// 删除标签
$rt = weixin_get_access_token();
if ($rt['code']) {
$access_token = $rt['msg'];
$param = [
'openid_list' => [$user['openid']],
'tagid' => $gid,
];
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/tags/members/batchuntagging?access_token=' . $access_token,
$param
);
if (!$rt['code']) {
log_message('error', '联动变更微信组标签:'.$rt['msg']);
}
} else {
log_message('error', '联动变更微信组标签:'.$rt['msg']);
}
}
}
}
// 格式化
private function _get_groupids($arr) {
if ($arr) {
foreach ($arr as $i => $t) {
$arr[$i] = (string)$t;
}
}
return dr_array2string($arr);
}
}
+701
View File
@@ -0,0 +1,701 @@
<?php namespace Phpcmf\Model\Weixin;
class Weixin extends \Phpcmf\Model
{
// 发送通知
public function send_notice($value, $siteid, $error) {
$content = [];
if (isset($value['config']['weixin']['tpl_content']) && is_array($value['config']['weixin']['tpl_content'])) {
$content = $value['config']['weixin']['tpl_content'];
if (!$content) {
$error[] = $debug = '自定义通知内容参数tpl_content不存在';
CI_DEBUG && log_message('debug', '通知任务('.$value['name'].')微信执行失败:'.$debug);
}
} else {
$rt = \Phpcmf\Service::L('notice')->_get_tpl_content($siteid, $value['name'], 'weixin', $value['data']);
if (!$rt['code']) {
$error[] = $rt['msg'];
CI_DEBUG && log_message('debug', '通知任务('.$value['name'].')执行失败:'.$rt['msg']);
} else {
$xml = \Phpcmf\Service::L('notice')->_xml_array($rt['msg']);
if (!$xml || !isset($xml['xml']) || !$xml['xml']) {
$error[] = $debug = 'xml解析失败,检查文件格式是否正确:'.$value['name'].'.html';
CI_DEBUG && log_message('debug', '通知任务('.$value['name'].')微信执行失败:'.$debug.'<br>'.$rt['msg']);
} else {
$content = $xml['xml'];
}
}
}
if ($content) {
$rt = \Phpcmf\Service::M('member')->weixin_template($value['data']['uid'], $content['id'], $content['param'], $content['url']);
if (!$rt['code']) {
$error[] = $debug = '微信消息执行错误:'.$rt['msg'];
CI_DEBUG && log_message('debug', '通知任务('.$value['name'].')微信执行失败:'.$debug);
} else {
// 成功
unset($value['config']['weixin']);
}
}
return [$error, $value];
}
// 获取微信表名
public function wxtable($name) {
return weixin_wxtable($name);
}
// 获取配置信息
public function get_config($name) {
$data = $this->db->table(weixin_wxtable('weixin'))->where('name', $name)->get()->getRowArray();
if ($data) {
$data = dr_string2array($data['value']);
return $data;
} else {
$this->db->table(weixin_wxtable('weixin'))->insert([
'name' => $name,
'value' => '',
]);
return [];
}
}
// 存储配置信息
public function save_config($name, $post) {
$rt = $this->db->table(weixin_wxtable('weixin'))->replace([
'name' => $name,
'value' => dr_array2string($post),
]);
if ($rt->connID->error) {
return dr_return_data(0, $this->table.': '.$rt->connID->error);
}
return dr_return_data(1);
}
// 上传图文消息内的图片获取URL
public function get_file_media_id($access_token, $type, $filename) {
// 查询本地库
$rt = $this->table(weixin_wxtable('media_id'))->where('file', md5($filename))->getRow();
if ($rt) {
return dr_return_data(1, 'ok', $rt);
}
$id = dr_get_file($filename, true);
if (!$id) {
return dr_return_data(0, '文件不存在');
}
$file = WRITEPATH.'temp/sync_'.md5($id).'.'.substr(strrchr($id, '.'), 1);;
$c = dr_catcher_data($id);
if (!$c) {
return dr_return_data(0, '无法获取文件内容:'.$id);
}
$rt = file_put_contents($file, $c);
if (!$rt) {
return dr_return_data(0, '本地文件写入失败:'.$id);
} elseif (!is_file($file)) {
return dr_return_data(0, '本地文件不存在');
}
$rt = ihttp_request(
'https://api.weixin.qq.com/cgi-bin/material/add_material?access_token='.$access_token,
[
'type' => 'image',
'media' => '@' . $file
]
);
if ($rt['code']) {
// 更新到媒体表
$save = [
'file' => md5($filename),
'url' => $rt['data']['url'],
'media_id' => $rt['data']['media_id'],
];
$this->table(weixin_wxtable('media_id'))->insert($save);
}
return $rt;
}
// 同步素材到服务器
public function sync_content($access_token, $t, $return = 0) {
if (!$t['media_id'] || $return) {
// 图文素材
$url = 'https://api.weixin.qq.com/cgi-bin/draft/add?access_token='.$access_token;
$param = [
'articles' => [
]
];
$value = dr_string2array($t['content']);
for ($i = 1; $i<=9; $i++) {
if (!$value['title_'.$i]) {
break;
}
if (!$value['thumb_'.$i]) {
return dr_return_data(0, '素材['.$t['title'].'] 第'.$i.'个内容缺少封面图片');
}
$cache = [];
$content = htmlspecialchars_decode($value['content_'.$i]);
if (preg_match_all("/(src)=([\"|']?)([^ \"'>]+\.(gif|jpg|jpeg|png))\\2/i", $content, $imgs)) {
foreach ($imgs[3] as $image) {
if (!isset($cache[$image])) {
$tmp = WRITEPATH.'temp/sync_'.md5($image).'.'.substr(strrchr($image, '.'), 1);;
if (strpos($image, '/') === 0 && is_file(WEBPATH.$image)) {
$file = file_get_contents(WEBPATH.$image);
} else {
$file = dr_catcher_data($image);
}
if ($file && file_put_contents($tmp, $file)) {
$cache[$image] = 1;
$rt = ihttp_request(
'https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token='.$access_token,
[
'media' => '@' . $tmp
]
);
// 更新到内容
$rt['code'] && $content = str_replace($image, $rt['data']['url'], $content);
}
}
}
}
$rt = $this->get_file_media_id($access_token, 'thumb', $value['thumb_'.$i]);
if (!$rt['code']) {
$rt['msg'] = $value['thumb_'.$i].' - 附件上传失败:'.$rt['msg'];
return $rt;
}
$thumb_id = $rt['data']['media_id'];
$param['articles'][] = [
"title" => $value['title_'.$i],
"thumb_media_id" => $thumb_id,
"author" => $value['author_'.$i],
"digest" => dr_strcut($value['description_'.$i], 50),
"content" => $content,
"show_cover_pic" => 1,
"content_source_url" => html_entity_decode($value['url_'.$i])
];
}
if (!count($param['articles'])) {
return dr_return_data(0, '素材['.$t['title'].'] 资源信息为空无法同步');
}
$rt = wx_post_https_json_data($url, $param);
if (!$rt['code']) {
return $rt;
}
$media_id = $rt['data']['media_id'];
if ($return) {
return dr_return_data(1, $media_id);
}
} else {
$media_id = $t['media_id'];
}
if (!$t['publish_id']) {
// 发布内容
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/freepublish/submit?access_token='.$access_token,
[
'media_id' => $media_id
]
);
if (!$rt['code']) {
$this->table(weixin_wxtable('content'))->update($t['id'], [
'media_id' => $media_id
]);
return $rt;
}
// 存储
$this->table(weixin_wxtable('content'))->update($t['id'], [
'media_id' => $media_id,
'publish_id' => $rt['data']['publish_id'],
]);
} else {
// 查询结果
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/freepublish/get?access_token='.$access_token,
[
'publish_id' => $t['publish_id']
]
);
if (!$rt['code']) {
return $rt;
}
$this->table(weixin_wxtable('content'))->update($t['id'], [
'status' => $rt['data']['publish_status'],
'article_id' => $rt['data']['article_id']
]);
}
return dr_return_data(1, 'ok');
}
// 高级群发
public function sendall($groupid, $data)
{
$rt = weixin_get_access_token();
if (!$rt['code']) {
return $rt;
}
// 将内容转成为草稿箱
$rs = $this->sync_content($rt['msg'], $data, 1);
if (!$rs['code']) {
return $rs;
}
$param = [
'msgtype' => 'mpnews',
'mpnews' => [
'media_id' => $rs['msg']
],
];
if ($groupid) {
$param['filter'] = [
'is_to_all' => false,
'tag_id' => $groupid,
];
} else {
$param['filter'] = [
'is_to_all' => true,
];
}
$rt = wx_post_https_json_data(
'https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token='.$rt['msg'],
$param
);
if (!$rt['code']) {
return $rt;
}
return dr_return_data(1, 'ok');
}
// 客服群发 文本内容
public function send_for_text($groupid, $data)
{
$param = [
'msgtype' => 'text',
'text' => [
'content' => $data
],
];
if ($groupid) {
if (strlen($groupid) > 5) {
// 指定粉丝
$user = [
[
'openid' => $groupid,
]
];
} else {
// 粉丝组
$user = $this->table(weixin_wxtable('user'))->where('subscribe>0 and subscribe_time > '.(SYS_TIME - 3600*48))->where('`groupids` like "%\"'.$groupid.'\"%"')->getAll();
}
} else {
// 全部粉丝
$user = $this->table(weixin_wxtable('user'))->where('subscribe>0 and subscribe_time > '.(SYS_TIME - 3600*48))->getAll();
}
if (!$user) {
return dr_return_data(0, '48小时内互动的粉丝不存在');
}
return $this->_save_send_data($user, $param);
}
// 客服群发 内容模块
public function send_for_module($dir, $ids) {
$data = $this->table_site($dir)->where_in('id', $ids)->getAll(9);
if (!$data) {
return dr_return_data(0, '模块内容不存在');
}
$param = [
'msgtype' => 'news',
'news' => [
'articles' => []
],
];
foreach ($data as $t) {
$param['news']['articles'][] = [
"title" => $t['title'],
"description" => $t['description'],
"picurl" => dr_get_file($t['thumb'], true),
"url" => dr_url_prefix($t['url'], $dir)
];
}
$user = $this->table(weixin_wxtable('user'))->where('subscribe>0 and subscribe_time > '.(SYS_TIME - 3600*48))->getAll();
if (!$user) {
return dr_return_data(0, '粉丝信息不存在');
}
return $this->_save_send_data($user, $param);
}
// 客服群发 内容素材
public function send_for_content($groupid, $data)
{
$param = [
'msgtype' => 'mpnewsarticle',
'mpnewsarticle' => [
'article_id' => $data['article_id']
],
];
if ($groupid) {
if (strlen($groupid) > 5) {
// 指定粉丝
$user = [
[
'openid' => $groupid,
]
];
} else {
// 粉丝组
$user = $this->table(weixin_wxtable('user'))->where('groupid', $groupid)->where('subscribe>0 and subscribe_time > '.(SYS_TIME - 3600*48))->getAll();
}
} else {
// 全部粉丝
$user = $this->table(weixin_wxtable('user'))->where('subscribe>0 and subscribe_time > '.(SYS_TIME - 3600*48))->getAll();
}
if (!$user) {
return dr_return_data(0, '48小时内互动的粉丝不存在');
} elseif (!$param) {
return dr_return_data(0, '未知的tid类别信息:'.$data['tid']);
}
return $this->_save_send_data($user, $param);
}
// 存储客服消息发送记录表
private function _save_send_data($user, $param) {
$id = (int)substr(SYS_TIME - rand(0, 9999), 0, 10);
foreach ($user as $t) {
$rt = $this->table(weixin_wxtable('send'))->insert([
'cid' => $id,
'openid' => $t['openid'],
'status' => 0,
'content' => dr_array2string($param)
]);
if (!$rt['code']) {
return $rt;
}
}
return dr_return_data($id, 'ok');
}
// 存储客户端消息
public function save_message($data)
{
$rt = $this->table(weixin_wxtable('message'))->insert([
'tid' => $data['MsgType'],
'openid' => $data['FromUserName'],
'nickname' => '',
'headimgurl' => '',
'status' => 0,
'content' => dr_array2string($data),
'inputtime' => $data['CreateTime'],
]);
if (!$rt['code']) {
log_message('error', '微信消息存储失败:'.$rt['msg']);
}
}
// 更新统计数据
public function update_count_fans() {
return $this->table(weixin_wxtable('count_fans'))->order_by('id desc')->getAll(10, 'date');
$seven_days = array(
date('Ymd', strtotime('-1 days')),
date('Ymd', strtotime('-2 days')),
date('Ymd', strtotime('-3 days')),
date('Ymd', strtotime('-4 days')),
date('Ymd', strtotime('-5 days')),
date('Ymd', strtotime('-6 days')),
date('Ymd', strtotime('-7 days')),
);
// 本周数据
$week_stat_fans = $this->table(weixin_wxtable('count_fans'))->where_in('date', $seven_days)->getAll(0, 'date');
$stat_update_yes = false;
foreach ($seven_days as $sevens) {
if (empty($week_stat_fans[$sevens]) || $week_stat_fans[$sevens]['cumulate'] <=0) {
$stat_update_yes = true;
break;
}
}
if (empty($stat_update_yes)) {
return $week_stat_fans;
}
$rt = weixin_get_access_token();
if ($rt['code']) {
$access_token = $rt['msg'];
$url = 'https://api.weixin.qq.com/datacube/getusersummary?access_token='.$access_token;
$rt = wx_post_https_json_data($url, [
"begin_date" => date('Y-m-d', strtotime('-7 days')),
"end_date" => date('Y-m-d', strtotime('-1 days')),
]);
if ($rt['code']) {
$summary = $rt['data'];
}
$url = 'https://api.weixin.qq.com/datacube/getusercumulate?access_token='.$access_token;
$rt = wx_post_https_json_data($url, [
"begin_date" => date('Y-m-d', strtotime('-7 days')),
"end_date" => date('Y-m-d', strtotime('-1 days')),
]);
if ($rt['code']) {
$cumulate = $rt['data'];
}
$result = [];
if (!empty($summary['list'])) {
foreach ($summary['list'] as $row) {
$key = str_replace('-', '', $row['ref_date']);
$result[$key]['new'] = intval($result[$key]['new']) + $row['new_user'];
$result[$key]['cancel'] = intval($result[$key]['cancel']) + $row['cancel_user'];
}
}
if (!empty($cumulate['list'])) {
foreach ($cumulate['list'] as $row) {
$key = str_replace('-', '', $row['ref_date']);
$result[$key]['cumulate'] = $row['cumulate_user'];
}
}
foreach ($result as $i => $t) {
$this->table(weixin_wxtable('count_fans'))->replace([
'new' => (int)$t['new'],
'cancel' => (int)$t['cancel'],
'cumulate' => (int)$t['cumulate'],
'date' => $i,
]);
}
return $result;
}
return $week_stat_fans;
}
/**
* 发送微信通知模板
*
* $uid 会员id
* $id 微信模板id
* $data 通知内容
* $url 详细地址
* $color top颜色
*/
public function send_template($uid, $id, $data, $url = '', $color = '') {
$rt = weixin_get_access_token();
if (!$rt['code']) {
return dr_return_data(0, $rt['msg']);
}
if (is_array($uid)) {
$error = [];
foreach ($uid as $u) {
$oauth = $this->db->table('member_oauth')->where('uid', $u)->where('oauth', 'wechat')->get()->getRowArray();
if (!$oauth) {
$error[] = 'uid'.$u.')未绑定账号';
continue;
}
$rs = wx_post_https_json_data('https://api.weixin.qq.com/cgi-bin/message/template/send?access_token='.$rt['msg'], [
'touser' => $oauth['oid'],
'template_id' => $id,
'url' => $url,
'topcolor' => $color,
'data' => $data,
]);
if (!$rs['code']) {
$error[] = $rs['msg'];
}
}
if (dr_count($error) == dr_count($uid)) {
return dr_return_data(0, implode('', $error));
} else {
return dr_return_data(1, '发送成功');
}
} else {
$oauth = $this->db->table('member_oauth')->where('uid', $uid)->where('oauth', 'wechat')->get()->getRowArray();
if (!$oauth) {
return dr_return_data(0, 'uid'.$uid.')未绑定账号');
}
return wx_post_https_json_data('https://api.weixin.qq.com/cgi-bin/message/template/send?access_token='.$rt['msg'], [
'touser' => $oauth['oid'],
'template_id' => $id,
'url' => $url,
'topcolor' => $color,
'data' => $data,
]);
}
}
/**
* 发送微信订阅通知
*
* $uid 会员id
* $id 所需下发的订阅模板id
* $data 通知内容
* $url 详细地址
*/
public function send_biz($uid, $id, $data, $url = '') {
$oauth = $this->db->table('member_oauth')->where('uid', $uid)->where('oauth', 'wechat')->get()->getRowArray();
if (!$oauth) {
return dr_return_data(0, 'uid'.$uid.')未绑定账号');
}
$rt = weixin_get_access_token();
if (!$rt['code']) {
return dr_return_data(0, $rt['msg']);
}
return wx_post_https_json_data('https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token='.$rt['msg'], [
'touser' => $oauth['oid'],
'template_id' => $id,
'page' => $url,
'data' => $data,
]);
}
// 缓存
public function cache($siteid = SITE_ID)
{
$table = \Phpcmf\Service::M()->dbprefix('app_weixin');
if (!\Phpcmf\Service::M()->is_table_exists($table)) {
\Phpcmf\Service::M('table')->create_table(
$table,
[
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'name' => 'varchar(200) NOT NULL COMMENT \'公众号名称\'',
],
[
'PRIMARY KEY (`id`)',
],
'多公众号表'
);
}
$mr = \Phpcmf\Service::M()->table('app_weixin')->get(1);
if (!$mr) {
\Phpcmf\Service::M()->table('app_weixin')->replace([
'id' => 1,
'name' => '默认公众号'
]);
}
$alls = $this->table('app_weixin')->getAll();
$more_cache = [];
foreach ($alls as $more) {
$more_cache[$more['id']] = $more['name'];
/////////////////////////
$data = $this->table(weixin_wxtable('weixin', $more['id']))->getAll();
$cache = [];
if ($data) {
foreach ($data as $t) {
$value = dr_string2array($t['value']);
$cache[$t['name']] = $value;
}
}
$kws = [];
$data = $this->table(weixin_wxtable('reply', $more['id']))->getAll();
if ($data) {
foreach ($data as $t) {
$arr = explode(',', $t['keyword']);
if ($arr) {
foreach ($arr as $kw) {
$kws[$kw] = $t['id'];
}
}
}
uksort($kws, function ($a, $b) {
return strlen($b) - strlen($a);
});
}
\Phpcmf\Service::L('cache')->set_file('weixin-kws'.($more['id'] > 1 ? '_more_'.$more['id'] : ''), $kws);
$table = $this->dbprefix(weixin_wxtable('template', $more['id']));
if (!\Phpcmf\Service::M()->is_table_exists($table)) {
\Phpcmf\Service::M('table')->create_table(
$table,
[
'id' => 'int(10) NOT NULL AUTO_INCREMENT COMMENT \'id\'',
'title' => 'varchar(200) NOT NULL COMMENT \'主题\'',
'groupid' => 'int(10) NOT NULL COMMENT \'发送标签组\'',
'counts' => 'int(10) NOT NULL COMMENT \'发送数\'',
'content' => 'text NOT NULL COMMENT \'消息内容\'',
'template' => 'varchar(200) NOT NULL COMMENT \'模板ID\'',
'url' => 'varchar(200) NOT NULL COMMENT \'url\'',
'color' => 'varchar(200) NOT NULL COMMENT \'主题颜色\'',
'inputtime' => 'int(10) NOT NULL COMMENT \'录入时间\'',
],
[
'PRIMARY KEY (`id`)',
'KEY `inputtime` (`inputtime`)',
],
'微信模板消息记录表'
);
}
$table = $this->dbprefix(weixin_wxtable('user', $more['id']));
\Phpcmf\Service::M()->query('UPDATE `'.$table.'` SET `subscribe`=`subscribe_time` where `subscribe`=1');
$table = $this->dbprefix(weixin_wxtable('content', $more['id']));
$t = \Phpcmf\Service::M('table');
$m = \Phpcmf\Service::M();
if (!$m->is_field_exists($table, 'nums')) {
$t->add_field($table, 'nums', 'tinyint(2)', 'DEFAULT \'0\'', '');
}
if (!$m->is_field_exists($table, 'status')) {
$t->add_field($table, 'status', 'tinyint(2)', 'DEFAULT \'0\'', '');
}
if (!$m->is_field_exists($table, 'publish_id')) {
$t->add_field($table, 'publish_id', 'varchar(255)', 'DEFAULT \'\'', '');
}
if (!$m->is_field_exists($table, 'article_id')) {
$t->add_field($table, 'article_id', 'varchar(255)', 'DEFAULT \'\'', '');
}
\Phpcmf\Service::L('cache')->set_file('weixin'.($more['id'] > 1 ? '_more_'.$more['id'] : ''), $cache);
/// ////////////////////////
}
\Phpcmf\Service::L('cache')->set_file('app_weixin', count($more_cache) == 1 ? '' : $more_cache);
return;
}
}
+11
View File
@@ -0,0 +1,11 @@
<?php
/**
* 微信会员登录插件
*/
return [
'type' => 'url',
'name' => '微信会员登录',
];
@@ -0,0 +1,4 @@
<?php
/**
* 后台配置控制器
*/
+8
View File
@@ -0,0 +1,8 @@
<?php
/**
* 前端运行控制器
*/
$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->weixin['account']['appid'].'&redirect_uri='.urlencode(ROOT_URL.'index.php?s=weixin&c=member').'&response_type=code&scope=snsapi_base&state=member#wechat_redirect';
$txt = '小插件提醒:单击进入用户中心';
$this->_to_weixin_text('<a href="'.$url.'">'.$txt.'</a>');
+126
View File
@@ -0,0 +1,126 @@
{template "header.html"}
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="portlet bordered light myfbody">
<div class="portlet-title tabbable-line">
<ul class="nav nav-tabs" style="float:left;">
<li class="{if $page==0}active{/if}">
<a href="#tab_0" data-toggle="tab" onclick="$('#dr_page').val('0')"> <i class="fa fa-cog"></i> {dr_lang('账号设置')} </a>
</li>
</ul>
</div>
<div class="portlet-body">
<div class="tab-content">
<div class="tab-pane {if $page==0}active{/if}" id="tab_0">
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">请求日志</label>
<div class="col-md-9">
<input type="checkbox" name="data[log]" value="1" {if $data['log']}checked{/if} data-on-text="{dr_lang('已开启')}" data-off-text="{dr_lang('已关闭')}" data-on-color="success" data-off-color="danger" class="make-switch" data-size="small">
<span class="help-block">{dr_lang('记录微信端请求本站的日志,建议在开发阶段开启,正式上线后关闭')}</span>
</div>
</div>
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">AppId</label>
<div class="col-md-9">
<input class="form-control input-xlarge" type="text" name="data[appid]" value="{$data['appid']}" >
</div>
</div>
</div>
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">AppSecret</label>
<div class="col-md-9">
<input class="form-control input-xlarge" type="text" name="data[appsecret]" value="{$data['appsecret']}" >
</div>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Token</label>
<div class="col-md-9">
<div class="input-group input-xlarge">
<input type="text" class="form-control" name="data[token]" id="sys_token" value="{$data['token']}" >
<span class="input-group-btn">
<button class="btn green" type="button" onclick="dr_to_token()">生成</button>
</span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">EncodingAESKey</label>
<div class="col-md-6">
<div class="input-group ">
<input type="text" class="form-control" name="data[aeskey]" id="sys_asckey" value="{$data['aeskey']}" >
<span class="input-group-btn">
<button class="btn green" type="button" onclick="dr_to_aeskey()">生成</button>
</span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">服务器地址</label>
<div class="col-md-6">
<p class="form-control-static"> {ROOT_URL}index.php?s=weixin{if WEIXIN_MORE_ID>1}&gzh_id={WEIXIN_MORE_ID}{/if} </p>
</div>
</div>
{if $access_tocken}
<div class="form-group">
<label class="col-md-2 control-label">接入错误信息</label>
<div class="col-md-6">
<p class="form-control-static" style="color: red;"> {$access_tocken} </p>
</div>
</div>
{/if}
</div>
</div>
<div class="tab-pane {if $page==1}active{/if}" id="tab_1">
<div class="form-body">
</div>
</div>
</div>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<label> <button type="button" onclick="dr_ajax_submit('{dr_now_url()}&page='+$('#dr_page').val(), 'myform', '2000')" class="btn green"> <i class="fa fa-save"></i> {dr_lang('保存')}</button>
</label>
<label> <a href="javascript:;" onclick="dr_iframe_show('{dr_lang('查看关注二维码')}','{dr_url('weixin/account/gz_index')}')" class="btn red"> <i class="fa fa-code"></i> {dr_lang('查看关注二维码')}</a>
</label>
</div>
</div>
</form>
<script type="text/javascript">
function dr_to_token() {
$.get("{dr_url(APP_DIR.'/api/token')}", function(data){
$("#sys_token").val(data);
});
}
function dr_to_aeskey() {
$.get("{dr_url(APP_DIR.'/api/asckey')}", function(data){
$("#sys_asckey").val(data);
});
}
</script>
{template "footer.html"}
+43
View File
@@ -0,0 +1,43 @@
{template "header.html"}
<div class="row table-search-tool" style="margin-top: -20px;">
<form action="{SELF}" method="get">
{$search}
<div class="col-xs-12">
<label><input type="text" class="form-control" placeholder="" value="{$param['keyword']}" name="keyword" /></label>
<label><button type="submit" class="btn blue btn-sm onloading" name="submit" > <i class="fa fa-search"></i> {dr_lang('搜索')}</button></label>
</div>
</form>
</div>
<form class="form-horizontal" role="form" id="myform">
{dr_form_hidden()}
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
<th class="myselect">
</th>
<th>内容</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
<td class="myselect" style="padding-left:10px !important">
<label class="mt-radio mt-radio-outline">
<input type="radio" class="cid" name="id" value="CID::{$t.id}">
<span></span>
</label>
</td>
<td>{$t.title}</td>
</tr>
{/loop}
</tbody>
</table>
</div>
</form>
{template "footer.html"}
+111
View File
@@ -0,0 +1,111 @@
{template "header.html"}
<div class="text-center">
<button type="button" id="dr_check_button" onclick="dr_checking();" class="btn blue"> <i class="fa fa-refresh"></i> {dr_lang('立即开始')}</button>
</div>
<div id="dr_check_result" class="margin-top-30" style="display: none">
</div>
<div id="dr_check_div" class="well margin-top-30" style="display: none">
<div class="scroller" style="height:300px" data-rail-visible="1" id="dr_check_html">
</div>
</div>
<div id="dr_check_ing" style="display: none">
<div class="progress progress-striped">
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
</div>
</div>
</div>
<script>
$(function () {
dr_checking();
});
function dr_checking() {
$.ajax({
type: "GET",
dataType: "json",
url: "{$count_url}",
success: function (json) {
if (json.code == 0) {
$('#dr_check_div').show();
$('#dr_check_html').html('<font color="red">'+json.msg+'</font>');
} else {
$('#dr_check_html').html("");
$('#dr_check_result').html($('#dr_check_ing').html());
$('#dr_check_div').show();
$('#dr_check_result').show();
$('#dr_check_button').html('{dr_lang("正在初始化")}');
$('#dr_check_button').attr('disabled', true);
dr_ajax2ajax(1);
}
},
error: function(HttpRequest, ajaxOptions, thrownError) {
dr_ajax_alert_error(HttpRequest, this, thrownError);
}
});
}
function dr_ajax2ajax(page) {
$.ajax({
type: "GET",
dataType: "json",
url: "{$todo_url}&pp="+page,
success: function (json) {
$('#dr_check_html').append(json.msg);
document.getElementById('dr_check_html').scrollTop = document.getElementById('dr_check_html').scrollHeight;
$('#dr_check_result .progress-bar-success').attr('style', 'width:'+json.data.bfb+'%');
if (json.code == 0) {
$('#dr_check_button').attr('disabled', true);
$('#dr_check_button').html('<i class="fa fa-times-circle"></i> {dr_lang("出现错误")}');
} else {
if (json.msg == 'ok') {
$('#dr_check_button').attr('disabled', true);
$('#dr_check_button').html('<i class="fa fa-check-circle"></i> {dr_lang("发送完毕")}');
} else {
$('#dr_check_button').html('<i class="fa fa-refresh"></i> '+json.data.msg+'');
dr_ajax2ajax(json.code);
}
}
},
error: function(HttpRequest, ajaxOptions, thrownError) {
dr_ajax_alert_error(HttpRequest, this, thrownError);
}
});
}
</script>
<style>
#dr_check_html .p_error {
color: red;
}
#dr_check_html p {
margin: 10px 0;
clear: both;
}
#dr_check_html .rleft {
float: left;
}
#dr_check_html .rright .ok {
color: green;
}
#dr_check_html .rright .error {
color: red;
}
#dr_check_html .rright {
float: right;
}
</style>
{template "footer.html"}
+276
View File
@@ -0,0 +1,276 @@
{template "header.html"}
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="portlet bordered light myfbody">
<div class="portlet-title tabbable-line">
<ul class="nav nav-tabs" style="float:left;">
<li class="{if $page==0}active{/if}">
<a href="#tab_0" data-toggle="tab" onclick="$('#dr_page').val('0')"> <i class="fa fa-cog"></i> {dr_lang('系统配置')} </a>
</li>
<li class="{if $page==1}active{/if}">
<a href="#tab_1" data-toggle="tab" onclick="$('#dr_page').val('1')"> <i class="fa fa-commenting"></i> {dr_lang('关注回复')} </a>
</li>
<li class="{if $page==2}active{/if}">
<a href="#tab_2" data-toggle="tab" onclick="$('#dr_page').val('2')"> <i class="fa fa-search"></i> {dr_lang('内容搜索')} </a>
</li>
<li class="{if $page==3}active{/if}">
<a href="#tab_3" data-toggle="tab" onclick="$('#dr_page').val('3')"> <i class="fa fa-user"></i> {dr_lang('关注绑定回复')} </a>
</li>
</ul>
</div>
<div class="portlet-body">
<div class="tab-content">
<div class="tab-pane {if $page==3}active{/if}" id="tab_3">
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">关注绑定</label>
<div class="col-md-9">
<p class="form-control-static"> 指扫描二维码关注公众号时提醒绑定会员账号或者系统自动生成会员账号 </p>
<p> 二维码在模板中调用函数: <?php echo htmlspecialchars('<a href="{'.'Router::oauth_url(\'wechat\', \'login\')}"> <img src="{'.'THEME_PATH}assets/oauth/wechat.png"> </a>');?></p>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">扫码登录成功</label>
<div class="col-md-9">
<textarea class="form-control" rows="3" name="data[gz_login]">{$data.gz_login}</textarea>
<span class="help-block">当用户扫码关注公众号并登录成功后的提示文字,可用通配符:{user}表示账号、{time}表示时间、{name}表示姓名,只有这3个通配符</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">扫码注册成功</label>
<div class="col-md-9">
<textarea class="form-control" rows="3" name="data[gz_reg]">{$data.gz_reg}</textarea>
<span class="help-block">当用户扫关注公众号并自动注册成功后的提示文字,可用通配符:{user}表示账号、{time}表示时间、{name}表示姓名,只有这3个通配符</span>
</div>
</div>
</div>
</div>
<div class="tab-pane {if $page==0}active{/if}" id="tab_0">
<div class="form-body">
<div class="form-group hide">
<label class="col-md-2 control-label">站点共享</label>
<div class="col-md-9">
<input type="checkbox" name="data[share]" value="1" {if $data['share']}checked{/if} data-on-text="{dr_lang('已开启')}" data-off-text="{dr_lang('已关闭')}" data-on-color="success" data-off-color="danger" class="make-switch" data-size="small">
<span class="help-block">{dr_lang('开启共享之后本站公众号数据将默认为主站数据')}</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">公众号内自动登录</label>
<div class="col-md-9">
<div class="mt-radio-inline">
<label class="mt-radio mt-radio-outline"><input type="radio" name="data[autologin]" value="0" {if !$data.autologin}checked=""{/if}> 关闭 <span></span></label>
<label class="mt-radio mt-radio-outline"><input type="radio" name="data[autologin]" value="1" {if $data.autologin ==1}checked=""{/if}> 自动登陆并绑定账号 <span></span></label>
<label class="mt-radio mt-radio-outline"><input type="radio" name="data[autologin]" value="2" {if $data.autologin ==2}checked=""{/if}> 提示用户是否绑定账号 <span></span></label>
</div>
<span class="help-block">{dr_lang('在公众号内访问网站时自动登录本微信所绑定的用户')}</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">强制绑定账号</label>
<div class="col-md-9">
<input type="checkbox" name="data[bang]" value="1" {if $data['bang']}checked{/if} data-on-text="{dr_lang('已开启')}" data-off-text="{dr_lang('已关闭')}" data-on-color="success" data-off-color="danger" class="make-switch" data-size="small">
<span class="help-block">{dr_lang('开启之后将会提醒他绑定账号账号才能进行自动回复功能')}</span>
</div>
</div>
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">强制绑定时提醒内容</label>
<div class="col-md-9">
<textarea class="form-control" rows="5" name="data[bang_text]">{$data.bang_text}</textarea>
<span class="help-block">{dr_lang('强制绑定账号的提醒文字,输入纯文本,不支持标签符号')}</span>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane {if $page==1}active{/if}" id="tab_1">
<div class="form-body">
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">关注时回复</label>
<div class="col-md-9">
<input type="checkbox" name="data[gz]" value="1" {if $data['gz']}checked{/if} data-on-text="{dr_lang('已开启')}" data-off-text="{dr_lang('已关闭')}" data-on-color="success" data-off-color="danger" class="make-switch" data-size="small">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">回复类型</label>
<div class="col-md-9">
<div class=" mt-radio-inline">
<label class="mt-radio mt-radio-outline"> 文本
<input type="radio" onclick="dr_content_type(0)" value="0" {if !$data.gz_type}checked{/if} name="data[gz_type]">
<span></span>
</label>
<label class="mt-radio mt-radio-outline"> 素材
<input type="radio" onclick="dr_content_type(1)" value="1" {if $data.gz_type}checked{/if} name="data[gz_type]">
<span></span>
</label>
</div>
<span class="help-block">设置用户添加公众帐号好友时,发送的欢迎信息</span>
</div>
</div>
</div>
<div class="form-body mytype" id="dr_type_0" style="display: none">
<div class="form-group">
<label class="col-md-2 control-label">文本内容</label>
<div class="col-md-9">
<textarea class="form-control" rows="5" name="data[gz_value_0]">{$data.gz_value_0}</textarea>
</div>
</div>
</div>
<div class="form-body mytype" id="dr_type_1" style="display: none">
<div class="form-group">
<label class="col-md-2 control-label">素材选择</label>
<div class="col-md-9">
<div class="input-group input-xlarge">
<input type="text" class="form-control" name="data[gz_value_1]" id="gz_value_1" value="{$data['gz_value_1']}" >
<span class="input-group-btn">
<button class="btn green" type="button" onclick="dr_get_weixin_content('gz_value_1')">选择素材</button>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane {if $page==2}active{/if}" id="tab_2">
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">搜索时回复</label>
<div class="col-md-9">
<input type="checkbox" name="data[ss]" value="1" {if $data['ss']}checked{/if} data-on-text="{dr_lang('已开启')}" data-off-text="{dr_lang('已关闭')}" data-on-color="success" data-off-color="danger" class="make-switch" data-size="small">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">搜索模块</label>
<div class="col-md-9">
<div class="mt-checkbox-list">
{loop $module $t}
<label class="mt-checkbox mt-checkbox-outline">
<input type="checkbox" name="data[ss_dir][]" value="{$t.dirname}" {if dr_in_array($t.dirname, $data.ss_dir)} checked{/if}> {$t.name}
<span></span>
</label>
{/loop}
</div>
</div>
</div>
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">回复类型</label>
<div class="col-md-9">
<div class=" mt-radio-inline">
<label class="mt-radio mt-radio-outline"> 文本
<input type="radio" onclick="dr_content_type2(0)" value="0" {if !$data.ss_type}checked{/if} name="data[ss_type]">
<span></span>
</label>
<label class="mt-radio mt-radio-outline"> 素材
<input type="radio" onclick="dr_content_type2(1)" value="1" {if $data.ss_type}checked{/if} name="data[ss_type]">
<span></span>
</label>
</div>
<span class="help-block">当系统没有搜索到任何内容时,不知道该如何回复粉丝的消息时,默认发送的内容</span>
</div>
</div>
</div>
<div class="form-body mytypess" id="dr_typess_0" style="display: none">
<div class="form-group">
<label class="col-md-2 control-label">文本内容</label>
<div class="col-md-9">
<textarea class="form-control" rows="5" name="data[ss_value_0]">{$data.ss_value_0}</textarea>
</div>
</div>
</div>
<div class="form-body mytypess" id="dr_typess_1" style="display: none">
<div class="form-group">
<label class="col-md-2 control-label">素材选择</label>
<div class="col-md-9">
<div class="input-group input-xlarge">
<input type="text" class="form-control" name="data[ss_value_1]" id="ss_value_1" value="{$data['ss_value_1']}" >
<span class="input-group-btn">
<button class="btn green" type="button" onclick="dr_get_weixin_content('ss_value_1')">选择素材</button>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<button type="button" onclick="dr_ajax_submit('{dr_now_url()}&page='+$('#dr_page').val(), 'myform', '2000')" class="btn green"> <i class="fa fa-save"></i> {dr_lang('保存')}</button>
</div>
</div>
</form>
<script type="text/javascript">
$(function(){
dr_content_type('{intval($data.gz_type)}');
dr_content_type2('{intval($data.ss_type)}');
});
function dr_content_type(i) {
$('.mytype').hide();
$('#dr_type_'+i).show();
}
function dr_content_type2(i) {
$('.mytypess').hide();
$('#dr_typess_'+i).show();
}
function dr_get_weixin_content(id) {
layer.open({
type: 2,
title: '选择素材',
fix:true,
scrollbar: false,
shadeClose: true,
shade: 0,
area: ['70%', '70%'],
btn: [lang['ok'], lang['esc']],
yes: function(index, layero){
var body = layer.getChildFrame('body', index);
$(body).find('.form-group').removeClass('has-error');
var form2 = $(body).find('#myform').serializeArray();
for ( var p in form2 ){ // 方法
if (form2[p].name == 'id') {
$('#'+id).val(form2[p].value);
}
}
//$('#'+id).val(form.cid);
layer.closeAll();
},
content: '{dr_url('weixin/api/content')}&is_ajax=1'
});
}
</script>
{template "footer.html"}
+98
View File
@@ -0,0 +1,98 @@
{template "header.html"}
{template "api_list_date_search.html"}
<div class="right-card-box">
<div class="row table-search-tool">
<form action="{SELF}" method="get">
{dr_form_search_hidden()}
<div class="col-md-12 col-sm-12">
<label><input type="text" class="form-control" placeholder="" value="{$param['keyword']}" name="keyword" /></label>
</div>
<div class="col-md-12 col-sm-12">
<label>
<div class="input-group input-medium date-picker input-daterange" data-date="" data-date-format="yyyy-mm-dd">
<input type="text" class="form-control" value="{$param.date_form}" name="date_form">
<span class="input-group-addon"> {dr_lang('到')} </span>
<input type="text" class="form-control" value="{$param.date_to}" name="date_to">
</div>
</label>
</div>
<div class="col-md-12 col-sm-12">
<label><button type="submit" class="btn blue btn-sm onloading" name="submit" > <i class="fa fa-search"></i> {dr_lang('搜索')}</button></label>
</div>
</form>
</div>
<form class="form-horizontal" role="form" id="myform">
{dr_form_hidden()}
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
<th class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
</th>
<th class="{dr_sorting('title')}" name="title">{dr_lang('标题')}</th>
<th width="80" style="text-align:center" class="{dr_sorting('media_id')}" name="media_id">{dr_lang('状态')}</th>
<th width="80" style="text-align:center" class="{dr_sorting('nums')}" name="nums">{dr_lang('数量')}</th>
<th width="150" class="{dr_sorting('inputtime')}" name="inputtime">{dr_lang('发布时间')}</th>
<th>{dr_lang('操作')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
<td class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="checkboxes" name="ids[]" value="{$t.id}" />
<span></span>
</label>
</td>
<td>{$t.title}</td>
<td style="text-align:center">
{if !$t.media_id}
<span class="label label-sm label-danger"> {dr_lang('未同步')} </span>
{else}
<span class="label label-sm label-success"> {$zt[$t.status]} </span>
{/if}</td>
<td style="text-align:center">
{$t.nums}</td>
<td>{dr_date($t.inputtime, '', 'red')}</td>
<td>
{if $ci->_is_admin_auth('edit')}
<label><a href="{dr_url($uriprefix.'/edit', ['id'=>$t.id, 'tid'=>$tid])}" class="btn btn-xs green"> <i class="fa fa-edit"></i> {dr_lang('修改')}</a></label>
{/if}
{if $t.article_url}<label><a target="_blank" href="{$t.article_url}" class="btn btn-xs dark"> <i class="fa fa-search"></i> {dr_lang('预览')}</a></label>{/if}
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
<div class="row fc-list-footer table-checkable ">
<div class="col-md-5 fc-list-select">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
<button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/del')}', '{dr_lang('你确定要删除它们吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('删除')}</button>
<button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/sync_add')}', '{dr_lang('你确定要同步它们吗?')}', 1)" class="btn green btn-sm"> <i class="fa fa-refresh"></i> {dr_lang('一键同步')}</button>
</div>
<div class="col-md-7 fc-list-page">
{$mypages}
</div>
</div>
</form>
{template "footer.html"}
+192
View File
@@ -0,0 +1,192 @@
{template "header.html"}
<div class="note note-danger">
<p>图文的封面图、标题必须填写</p>
</div>
<script>
$(function () {
dr_wx_content(1);
$('.wx-p-box-title').click(function () {
var cid = $(this).attr('cid');
$('.wx-p-box-title').removeClass('on');
$(this).addClass('on');
dr_wx_content(cid);
});
$('.wx-content-field').click(function () {
var cid = $('#dr_wx_cid').val();
var img = $('#fileupload_thumb_'+cid+'_files').find('img').attr('src');
$('#wx-box-thumb-'+cid).html('<img src="'+img+'">');
});
});
function dr_wx_content(cid) {
$('#dr_wx_cid').val(cid);
$('.wx-content-field .form-group').hide();
$('#dr_row_title_'+cid).show();
$('#dr_row_author_'+cid).show();
$('#dr_row_thumb_'+cid).show();
$('#dr_row_description_'+cid).show();
$('#dr_row_content_'+cid).show();
$('#dr_row_url_'+cid).show();
}
function dr_wx_show_title(cid) {
$('#wx-box-title-'+cid).html($('#dr_title_'+cid).val());
}
</script>
<style>
.wx-p-box .wx-p-box-title {
border: 1px solid #e7ecf1;
padding: 5px;
}
.wx-p-box .wx-p-box-title .color-view {
height: 100px;
}
.wx-p-box .wx-p-box-title .color-demo {
margin-bottom: 0;
}
.wx-p-box .on {
padding: 9px 9px;
border: 2px solid #43b548;
}
.wx-p-box-otitle {
float: left;
width: 120px;
height: 55px;
}
.color-demo .color-view img, .wx-img-prev img {
max-width: 100%;
max-height: 100%;
}
.color-demo .color-view {
padding:0;
text-align: center;
overflow: hidden;
width: 100%;
height: 100%;
}
.wx-img-prev {
width: 60px; height: 60px;overflow: hidden;padding: 0 !important;
}
.media {
margin-top: 15px
}
.media:first-child {
margin-top: 0
}
.media,.media-body {
zoom: 1;
overflow: hidden
}
.media-object.img-thumbnail {
max-width: none
}
.media-right,.media>.pull-right {
padding-left: 10px
}
.media-left,.media>.pull-left {
padding-right: 10px
}
.media-body,.media-left,.media-right {
display: table-cell;
vertical-align: top
}
.media-middle {
vertical-align: middle
}
.media-bottom {
vertical-align: bottom
}
.media-heading {
margin-top: 0;
margin-bottom: 5px
}
.media-list {
padding-left: 0;
list-style: none
}
</style>
<input id="dr_wx_cid" type="hidden" value="1">
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="row myfbody">
<div class="col-md-3">
<div class="portlet light bordered">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject font-green sbold ">{dr_lang('图文列表')}</span>
</div>
</div>
<div class="portlet-body wx-p-box">
<div class="wx-p-box-title on" cid="1">
<div class="color-demo">
<div id="wx-box-thumb-1" class="color-view bg-default bg-font-default bold uppercase">
{if $thumb_1}<img src="{dr_get_file($thumb_1)}">{/if}
</div>
<div id="wx-box-title-1" class="color-info bg-blue-ebonyclay bg-font-grey-cascade c-font-14 sbold"> {if $title_1}{$title_1}{else}这里输入标题{/if} </div>
</div>
</div>
<?php for($i=2;$i<=9;$i++) {
eval('$thumb= $thumb_'.$i.';');
eval('$title= $title_'.$i.';');
?>
<div class="wx-p-box-title media" cid="{$i}">
<div id="wx-box-thumb-{$i}" class="pull-right bg-default wx-img-prev">
{if $thumb}<img src="{dr_get_file($thumb)}">{/if}
</div>
<div class="media-body wx-p-box-otitle" id="wx-box-title-{$i}">{if $title}{$title}{else}这里输入标题{/if}</div>
</div>
<?php } ?>
</div>
</div>
</div>
<div class="col-md-9">
<div class="portlet light bordered">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject font-green sbold ">{dr_lang('当前内容')}</span>
</div>
<div class="actions">
<div class="btn-group">
<a class="btn" href="{$reply_url}"> <i class="fa fa-mail-reply"></i> {dr_lang('返回列表')}</a>
</div>
</div>
</div>
<div class="portlet-body form">
<div class="form-body wx-content-field">
{$myfield}
</div>
</div>
</div>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<button type="button" onclick="dr_ajax_submit('{dr_now_url()}', 'myform', '2000')" class="btn green"> <i class="fa fa-save"></i> {dr_lang('保存内容')}</button>
<button type="button" onclick="dr_ajax_submit('{dr_now_url()}', 'myform', '2000', '{$reply_url}&tid={$tid}')" class="btn yellow"> <i class="fa fa-mail-reply-all"></i> {dr_lang('保存并返回')}</button>
</div>
</div>
</form>
{template "footer.html"}
+34
View File
@@ -0,0 +1,34 @@
{template "header.html"}
<form class="form-horizontal" method="post" role="form" id="myform">
{$form}
<div class="form-body">
<div class="form-group" id="dr_row_name">
<label class="col-xs-3 control-label ajax_name">{dr_lang('标签名称')}</label>
<div class="col-xs-8">
<label>
<input type="text" class="form-control" id="dr_name" name="data[name]" value="{$name}">
</label>
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label ajax_name">{dr_lang('绑定用户组')}</label>
<div class="col-xs-8">
<label>
<select name="data[groupid]" class="form-control">
<option value="0"> -- </option>
{loop $ci->member_cache['group'] $t}
<option value="{$t.id}" {if $groupid==$t.id}selected{/if}>{$t.name}</option>
{/loop}
</select>
</label>
<span class="help-block"> {dr_lang('给微信粉丝分配用户组,用于绑定本站会员的微信粉丝')} </span>
</div>
</div>
</div>
</form>
{template "footer.html"}
+75
View File
@@ -0,0 +1,75 @@
{template "header.html"}
<div class="note note-danger">
<p>{dr_lang('微信标签组用户可设置个性化菜单')}</p>
</div>
<div class="right-card-box">
<form class="form-horizontal" role="form" id="myform">
{dr_form_hidden()}
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
{if $ci->_is_admin_auth('del')}
<th class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
</th>
{/if}
<th width="80" class="{dr_sorting('tag')}" name="tag">Tag</th>
<th width="200" class="{dr_sorting('name')}" name="name">{dr_lang('标签')}</th>
<th style="text-align:center" width="200" class="{dr_sorting('groupid')}" name="groupid">{dr_lang('用户组')}</th>
<th style="text-align:center" width="80">{dr_lang('粉丝数')}</th>
<th>{dr_lang('操作')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
{if $ci->_is_admin_auth('del')}
<td class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="checkboxes" name="ids[]" value="{$t.id}" />
<span></span>
</label>
</td>
{/if}
<td>{$t.tag}</td>
<td>{$t.name}</td>
<td style="text-align:center"> {if !$t.groupid} -- {else} {$ci->member_cache['group'][$t.groupid]['name']} {/if} </td>
<td style="text-align:center"> {$t.count} </td>
<td>
{if $ci->_is_admin_auth('edit')}
<label><a href="javascript:dr_iframe('edit', '{dr_url($uriprefix.'/edit', ['id'=>$t.id])}', '', '33%');" class="btn btn-xs green"> <i class="fa fa-edit"></i> {dr_lang('修改')}</a></label>
<label><a href="javascript:dr_iframe_show('{$t.name}', '{dr_url('weixin/menu/index', ['gid'=>$t.tag])}', '', '');" class="btn btn-xs blue"> <i class="fa fa-list"></i> {dr_lang('设置个性化菜单')}</a></label>
{/if}
{if $ci->_is_admin_auth('del')}
<label><a href="javascript:;" onclick="dr_ajax_option('{dr_url($uriprefix.'/menu_del', ['gid'=>$t.tag])}', '{dr_lang('你确定要删除它吗?')}', 1)" class="btn btn-xs red"> <i class="fa fa-trash"></i> {dr_lang('删除个性化菜单')}</a></label>
{/if}
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
<div class="row fc-list-footer table-checkable ">
<div class="col-md-5 fc-list-select">
{if $ci->_is_admin_auth('del')}
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
<button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/del')}', '{dr_lang('你确定要删除它们吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('删除')}</button>
{/if}
</div>
<div class="col-md-7 fc-list-page">
{$mypages}
</div>
</div>
</form>
{template "footer.html"}
+46
View File
@@ -0,0 +1,46 @@
{template "header.html"}
<link href="{THEME_PATH}assets/global/plugins/codemirror/lib/codemirror.css" rel="stylesheet" type="text/css" />
<link href="{THEME_PATH}assets/global/plugins/codemirror/theme/neat.css" rel="stylesheet" type="text/css" />
<script src="{THEME_PATH}assets/global/plugins/codemirror/lib/codemirror.js" type="text/javascript"></script>
<script src="{THEME_PATH}assets/global/plugins/codemirror/mode/javascript/javascript.js" type="text/javascript"></script>
<script type="text/javascript">
jQuery(document).ready(function() {
var myTextArea = document.getElementById('file_code');
var myCodeMirror = CodeMirror.fromTextArea(myTextArea, {
lineNumbers: true,
matchBrackets: true,
styleActiveLine: true,
theme: "neat",
mode: 'javascript'
});
});
</script>
<div class="note note-danger">
<p>
{if $islog}<a style="color: red" href="{dr_url('weixin/account/index')}">
当前已开启请求日志记录功能,建议上线后关闭此项,会生成大量日志内容,增加服务器负担
{else}<a style="color: blue" href="{dr_url('weixin/account/index')}">
当前没有开启请求日志记录功能,开发阶段建议开启日志可以分析微信是否与服务器通信
{/if} </a>
</p>
<p style="margin-top: 10px;">
<label><button type="button" onclick="dr_ajax_option('{dr_url('weixin/log/del')}', '{dr_lang('你确定要清空记录吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('清空')}</button></label>
</p>
</div>
<div class="right-card-box">
<div class="form-group">
<textarea id="file_code" name="code">{$code}</textarea>
</div>
{template "footer.html"}
+69
View File
@@ -0,0 +1,69 @@
<html><head>
<title>关注微信公众号</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://res.wx.qq.com/connect/zh_CN/htmledition/style/impowerApp45a337.css">
<link href="https://res.wx.qq.com/connect/zh_CN/htmledition/images/favicon.ico" rel="Shortcut Icon">
<script src="https://res.wx.qq.com/connect/zh_CN/htmledition/js/jquery.min.js"></script>
</head>
<body style="background-color: rgb(51, 51, 51); padding: 50px;">
<div class="old-template" style="">
<div class="main impowerBox">
<div class="loginPanel normalPanel">
<div class="title">{SITE_NAME}</div>
<div class="waiting panelContent">
<div class="wrp_code"><img class="qrcode lightBorder" src="{$qrcode_url}"></div>
<div class="info">
<div class="status status_browser js_status js_wx_default_tip normal" id="wx_default_tip">
<p>请使用微信扫描二维码关注公众号</p>
<p><a href="javascript:dr_weixin_notify();">扫码之后单击登录网站</a></p>
</div>
<div class="status status_succ js_status js_wx_after_scan normal" style="display:none" id="wx_after_scan">
<i class="status_icon icon38_msg succ"></i>
<div class="status_txt">
<h4>扫码成功</h4>
<p>请在返回网站进行操作</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
function dr_weixin_notify() {
$.ajax({
type : "post",
url : "{$notify_url}",
dataType : "json",
success : function(json){
if (json.code == 1) {
$('#wx_default_tip').hide();
$('#wx_after_scan').show();
var oss_url = json.data.sso;
// 发送同步登录信息
for(var i in oss_url){
$.ajax({
type: "GET",
url:oss_url[i],
dataType: "jsonp",
success: function(json){ },
error: function(){ }
});
}
if (json.data.url) {
setTimeout("window.location.href = '"+json.data.url+"'", 2000);
} else{
setTimeout("window.location.href = '{$back_url}'", 2000);
}
} else {
alert('没有收到扫码信息');
}
},
error:function(){ }
});
}
</script>
</body>
</html>
+76
View File
@@ -0,0 +1,76 @@
{template "header.html"}
<div class="note note-danger">
<p><a href="javascript:dr_admin_menu_ajax('{dr_url($uriprefix.'/sync_index')}');">{dr_lang('立即将菜单同步更新到公众号')}</a></p>
</div>
<div class="right-card-box">
<form class="form-horizontal" role="form" id="myform">
{dr_form_hidden()}
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
{if $ci->_is_admin_auth('del')}
<th class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
</th>
{/if}
<th width="70" style="text-align:center"> {dr_lang('排序')} </th>
<th class="{dr_sorting('name')}" name="name">{dr_lang('名称')}</th>
<th style="text-align:center" width="120">{dr_lang('动作')}</th>
<th>{dr_lang('操作')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
{if $ci->_is_admin_auth('del')}
<td class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="checkboxes" name="ids[]" value="{$t.id}" />
<span></span>
</label>
</td>
{/if}
<td style="text-align:center">
<input type="text" onblur="dr_ajax_save(this.value, '{dr_url($uriprefix.'/displayorder_edit', ['id'=>$t.id])}')" value="{$t.displayorder}" class="displayorder form-control input-sm input-inline input-mini">
</td>
<td {if $t.pid} style="padding-left: 30px" {/if}>{dr_html2emoji($t.name)}</td>
<td style="text-align:center"> {$menu_type[$t.type]} </td>
<td>
{if $ci->_is_admin_auth('edit')}
{if !$t.pid && !$t.type}
<label><a href="javascript:dr_iframe('edit', '{dr_url($uriprefix.'/edit', ['id'=>$t.id,'gid'=>$gid])}', '50%', '50%');" class="btn btn-xs green"> <i class="fa fa-edit"></i> {dr_lang('修改')}</a></label>
<label><a href="{dr_url($uriprefix.'/add', ['pid'=>$t.id,'gid'=>$gid])}" class="btn btn-xs red"> <i class="fa fa-plus"></i> {dr_lang('添加')}</a></label>
{else}
<label><a href="{dr_url($uriprefix.'/edit', ['id'=>$t.id,'gid'=>$gid])}" class="btn btn-xs green"> <i class="fa fa-edit"></i> {dr_lang('修改')}</a></label>
{/if}
{/if}
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
<div class="row fc-list-footer table-checkable ">
<div class="col-md-5 fc-list-select">
{if $ci->_is_admin_auth('del')}
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
<button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/del')}', '{dr_lang('你确定要删除它们吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('删除')}</button>
{/if}
</div>
<div class="col-md-7 fc-list-page">
{$mypages}
</div>
</div>
</form>
{template "footer.html"}
+165
View File
@@ -0,0 +1,165 @@
{template "header.html"}
<div class="note note-danger">
<p>1、自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。</p>
<p>2、一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。</p>
</div>
<script src="{THEME_PATH}assets/js/jquery.insert.js" type="text/javascript"></script>
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="portlet bordered light myfbody">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject font-green "><i class="fa fa-list"></i> 自定义菜单</span>
</div>
</div>
<div class="portlet-body">
<div class="tab-content">
<div class="form-body">
<div class="form-group" id="dr_row_pid">
<label class="col-xs-2 control-label">{dr_lang('菜单级别')}</label>
<div class="col-xs-8">
<div class="input-group input-xlarge">
<label><select name="data[pid]" class="form-control">
<option value="0"> 一级菜单</option>
{loop $menu_top $t}
<option value="{$t.id}" {if $pid== $t.id} selected {/if}> {dr_html2emoji($t.name)}</option>
{/loop}
</select></label>
</div>
</div>
</div>
<div class="form-group" id="dr_row_name">
<label class="col-xs-2 control-label">{dr_lang('菜单名称')}</label>
<div class="col-xs-8">
<div class="input-group input-xlarge">
<input type="text" class="form-control" name="data[name]" value="{dr_html2emoji($name)}" id="dr_name" />
<span class="input-group-btn">
<button class="btn green" type="button" onclick="dr_insert_emoji('name')"> <i class="fa fa-smile-o"></i> 表情</button>
</span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-xs-2 control-label">动作类型</label>
<div class="col-xs-8">
<div class=" mt-radio-inline">
{loop $menu_type $n $v}
<label class="mt-radio mt-radio-outline"> {$v}
<input type="radio" onclick="dr_menu_type('{$n}')" value="{$n}" {if $type==$n} checked{/if} name="data[type]">
<span></span>
</label>
{/loop}
</div>
</div>
</div>
<div class="mytype form-group type_view" style="display: none">
<label class="col-md-2 control-label">网页地址</label>
<div class="col-md-9">
<div class="input-group">
<input type="text" class="form-control" name="value_view" value="{$value}" id="dr_value_view" />
<div class="input-group-btn dropup">
<button type="button" class="btn green dropdown-toggle" data-toggle="dropdown" tabindex="-1" aria-expanded="false">
<i class="fa fa-angle-up"></i>
</button>
<ul class="dropdown-menu pull-right" role="menu">
{loop $view_url $t}
<li>
<a href="javascript:;" onclick="$('#dr_value_view').val('{$t.value}')"> {$t.name} </a>
</li>
{/loop}
</ul>
</div>
</div>
</div>
</div>
<div class="mytype form-group type_article_view_limited" style="display: none">
<label class="col-md-2 control-label">图文素材</label>
<div class="col-md-9">
<label><select name="value_article_view_limited" class="form-control">
<option value="0"> --</option>
{loop $twsc $t}
<option value="{$t.article_id}" {if $value== $t.article_id} selected {/if}> {$t.title}</option>
{/loop}
</select></label>
<span class="help-block">只显示已经同步成功的图文素材</span>
</div>
</div>
<div class="mytype form-group type_click" style="display: none">
<label class="col-md-2 control-label">小插件</label>
<div class="col-md-9">
<div class="input-group input-xlarge">
<input type="text" class="form-control" name="value_click" value="{$value}" id="dr_value_click" />
<div class="input-group-btn dropup">
<button type="button" class="btn green dropdown-toggle" data-toggle="dropdown" tabindex="-1" aria-expanded="false">
<i class="fa fa-angle-up"></i>
</button>
<ul class="dropdown-menu pull-right" role="menu">
{loop $plugin $t}
<li>
<a href="javascript:;" onclick="$('#dr_value_click').val('{$t.value}')"> {$t.name} </a>
</li>
{/loop}
</ul>
</div>
</div>
<div class="alert alert-info input-xlarge margin-top-20">
自定义小插件目录为./Plugins/程序名/Run.php
</div>
</div>
</div>
<div class="mytype form-group type_login" style="display: none">
<label class="col-md-2 control-label">跳转地址</label>
<div class="col-md-9">
<input type="text" class="form-control" name="value_login" value="{$value}" />
<span class="help-block">弹出登录授权之后再跳转的地址,例如会员中心的功能</span>
</div>
</div>
<div class="mytype form-group type_miniprogram" style="display: none">
<label class="col-md-2 control-label">小程序appid</label>
<div class="col-md-9">
<input type="text" class="form-control" name="value_miniprogram[appid]" value="{php echo is_array($value) ? $value.appid : '';}" />
<span class="help-block">小程序的APPID</span>
</div>
</div>
<div class="mytype form-group type_miniprogram" style="display: none">
<label class="col-md-2 control-label">小程序路径</label>
<div class="col-md-9">
<input type="text" class="form-control" name="value_miniprogram[path]" value="{php echo is_array($value) ? $value.path : '';}" />
<span class="help-block">例如:pages/lunar/index</span>
</div>
</div>
<div class="mytype form-group type_miniprogram" style="display: none">
<label class="col-md-2 control-label">小程序url</label>
<div class="col-md-9">
<input type="text" class="form-control" name="value_miniprogram[url]" value="{php echo is_array($value) ? $value.url : '';}" />
<span class="help-block">不支持小程序的老版本客户端将打开本url。</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<button type="button" onclick="dr_ajax_submit('{dr_now_url()}&page='+$('#dr_page').val(), 'myform', '2000', '{$reply_url}')" class="btn green"> <i class="fa fa-save"></i> {dr_lang('保存')}</button>
</div>
</div>
</form>
<script type="text/javascript">
$(function(){
dr_menu_type('{$type}');
});
function dr_menu_type(i) {
$('.mytype').hide();
$('.type_'+i).show();
}
</script>
{template "footer.html"}
@@ -0,0 +1,24 @@
{template "header.html"}
<script src="{THEME_PATH}assets/js/jquery.insert.js" type="text/javascript"></script>
<form class="form-horizontal" method="post" role="form" id="myform">
{$form}
<div class="form-body">
<div class="form-group" id="dr_row_name">
<label class="col-xs-3 control-label ajax_name">{dr_lang('菜单名称')}</label>
<div class="col-xs-8">
<div class="input-group input-xlarge">
<input type="text" class="form-control" name="data[name]" value="{dr_html2emoji($name)}" id="dr_name" />
<span class="input-group-btn">
<button class="btn green" type="button" onclick="dr_insert_emoji('name')"> <i class="fa fa-smile-o"></i> 表情</button>
</span>
</div>
</div>
</div>
</div>
</form>
{template "footer.html"}
+113
View File
@@ -0,0 +1,113 @@
{template "header.html"}
{template "api_list_date_search.html"}
<div class="right-card-box">
<div class="row table-search-tool">
<form action="{SELF}" method="get">
{dr_form_search_hidden()}
<div class="col-md-12 col-sm-12">
<label>
<select name="field" class="form-control">
{loop $field $t}
{if $t.ismain}
<option value="{$t.fieldname}" {if $param.field==$t.fieldname}selected{/if}>{$t.name}</option>
{/if}
{/loop}
</select>
</label>
<label><i class="fa fa-caret-right"></i></label>
<label><input type="text" class="form-control" placeholder="" value="{$param['keyword']}" name="keyword" /></label>
</div>
<div class="col-md-12 col-sm-12">
<label>
<div class="input-group input-medium date-picker input-daterange" data-date="" data-date-format="yyyy-mm-dd">
<input type="text" class="form-control" value="{$param.date_form}" name="date_form">
<span class="input-group-addon"> {dr_lang('到')} </span>
<input type="text" class="form-control" value="{$param.date_to}" name="date_to">
</div>
</label>
</div>
<div class="col-md-12 col-sm-12">
<label><button type="submit" class="btn blue btn-sm onloading" name="submit" > <i class="fa fa-search"></i> {dr_lang('搜索')}</button></label>
</div>
</form>
</div>
<form class="form-horizontal" role="form" id="myform">
{dr_form_hidden()}
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
<th class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
</th>
<th style="text-align:center" width="60" class="{dr_sorting('id')}" name="id">Id</th>
<th style="text-align:center" width="70" class="{dr_sorting('openid')}" name="openid">头像</th>
<th width="150" class="{dr_sorting('nikcname')}" name="nikcname">{dr_lang('昵称')}</th>
<th width="80" style="text-align:center" class="{dr_sorting('tid')}" name="tid">{dr_lang('类型')}</th>
<th width="80" style="text-align:center" class="{dr_sorting('status')}" name="status">{dr_lang('状态')}</th>
<th width="150" class="{dr_sorting('inputtime')}" name="inputtime">{dr_lang('录入时间')}</th>
<th>{dr_lang('内容')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
<td class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="checkboxes" name="ids[]" value="{$t.id}" />
<span></span>
</label>
</td>
<td style="text-align:center"> {$t.id}</td>
<td style="text-align:center"> <img width="45" class="img-circle" src="{$t.headimgurl}"> </td>
<td>{dr_html2emoji($t.nickname)}</td>
<td style="text-align:center">{$t.tid_name}</td>
<td style="text-align:center">{$t.status_name}</td>
<td>{dr_date($t.inputtime, '', 'red')}</td>
<td class="member_info_p">
{if $t.tid == 'text'}
<p>{$t.content}</p>
{if $ci->_is_admin_auth('weixin/send/add')}
<p><a href="{dr_url('weixin/send/index', ['uid'=>$t.userid])}" class="btn btn-xs green"> <i class="fa fa-send"></i> {dr_lang('发送消息')}</a></p>
{/if}
{else}
{if $t.status==1}
<label><a href="javascript:dr_iframe_show('详情', '{dr_url('weixin/message/show')}&file={$t.file}&tid={$t.tid}');" class="btn btn-xs dark"> <i class="fa fa-search"></i> 查看详情</a></label>
{/if}
{if $ci->_is_admin_auth('weixin/send/add')}
<label><a href="{dr_url('weixin/send/index', ['uid'=>$t.userid])}" class="btn btn-xs green"> <i class="fa fa-send"></i> {dr_lang('发送消息')}</a></label>
{/if}
{/if}
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
<div class="row fc-list-footer table-checkable ">
<div class="col-md-5 fc-list-select">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
<button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/del')}', '{dr_lang('你确定要删除它们吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('删除')}</button>
<button type="button" onclick="dr_admin_menu_ajax('{dr_url($uriprefix.'/update_add')}')" class="btn green btn-sm"> <i class="fa fa-refresh"></i> {dr_lang('一键更新状态')}</button>
</div>
<div class="col-md-7 fc-list-page">
{$mypages}
</div>
</div>
</form>
{template "footer.html"}
+32
View File
@@ -0,0 +1,32 @@
<div style="text-align:center">
<p>{$url}</p>
{if $tid=='image'}
<img src="{$url}" width="100%" >
{elseif $tid=='voice'}
{if strpos($url, 'amr') !== false}
<button class="icon-audio" id="playerBtn" style="margin:0 5px;cursor:pointer;" playerurl="{$url}">播放</button>
<div style="width:1px;height:1px;" id="playerQT">
</div>
<script src="{THEME_PATH}assets/global/plugins/jquery.min.js" type="text/javascript"></script>
<script>
//js代码如下。。好吧用到了jquery自己替换吧
var playerQT = document.getElementById("playerQT");
$("#playerBtn").bind("click",function(e){
var playerUrl = e.target.getAttribute("playerUrl");
playerAudio(playerUrl);
});
function playerAudio(url){
var html = '<embed width="1px" height="1px" name="plugin" src="'+url+'" type="audio/amr" id="QT_EMB">';
playerQT.innerHTML = html;
}
</script>
{else}
<audio src="{$url}" controls preload></audio>
{/if}
{else}
<video src="{$url}" controls preload></video>
{/if}
</div>
+68
View File
@@ -0,0 +1,68 @@
{template "header.html"}
<div class="right-card-box">
<form class="form-horizontal" role="form" id="myform">
{dr_form_hidden()}
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
{if $ci->_is_admin_auth('del')}
<th class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
</th>
{/if}
<th width="80" class="{dr_sorting('id')}" name="id">{dr_lang('Id')}</th>
<th width="200" class="{dr_sorting('name')}" name="name">{dr_lang('名称')}</th>
<th style="text-align:center" width="100">{dr_lang('粉丝数')}</th>
<th>{dr_lang('操作')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
{if $ci->_is_admin_auth('del')}
<td class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="checkboxes" name="ids[]" value="{$t.id}" />
<span></span>
</label>
</td>
{/if}
<td>{$t.id}</td>
<td>{$t.name}</td>
<td style="text-align:center"> {$t.count} </td>
<td>
{if $ci->_is_admin_auth('edit')}
<label><a href="javascript:dr_iframe('edit', '{dr_url($uriprefix.'/edit', ['id'=>$t.id])}', '', '200px');" class="btn btn-xs green"> <i class="fa fa-edit"></i> {dr_lang('修改')}</a></label>
{/if}
<label><a href="{dr_url($uriprefix.'/go_index', ['id'=>$t.id])}" class="btn btn-xs red"> <i class="fa fa-cog"></i> {dr_lang('进入')}</a></label>
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
<div class="row fc-list-footer table-checkable ">
<div class="col-md-5 fc-list-select">
{if $ci->_is_admin_auth('del')}
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
<button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/del')}', '{dr_lang('你确定要删除它们吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('删除')}</button>
{/if}
</div>
<div class="col-md-7 fc-list-page">
{$mypages}
</div>
</div>
</form>
{template "footer.html"}
+18
View File
@@ -0,0 +1,18 @@
{template "header.html"}
<form class="form-horizontal" method="post" role="form" id="myform">
{$form}
<div class="form-body">
<div class="form-group" id="dr_row_name">
<label class="col-xs-3 control-label ajax_name">{dr_lang('公众号名称')}</label>
<div class="col-xs-8">
<input type="text" class="form-control" id="dr_name" name="data[name]" value="{$name}">
</div>
</div>
</div>
</form>
{template "footer.html"}
+95
View File
@@ -0,0 +1,95 @@
{template "header.html"}
{template "api_list_date_search.html"}
<div class="right-card-box">
<div class="row table-search-tool">
<form action="{SELF}" method="get">
{dr_form_search_hidden()}
<div class="col-md-12 col-sm-12">
<label><input type="text" class="form-control" placeholder="" value="{$param['keyword']}" name="keyword" /></label>
</div>
<div class="col-md-12 col-sm-12">
<label>
<div class="input-group input-medium date-picker input-daterange" data-date="" data-date-format="yyyy-mm-dd">
<input type="text" class="form-control" value="{$param.date_form}" name="date_form">
<span class="input-group-addon"> {dr_lang('到')} </span>
<input type="text" class="form-control" value="{$param.date_to}" name="date_to">
</div>
</label>
</div>
<div class="col-md-12 col-sm-12">
<label><button type="submit" class="btn blue btn-sm onloading" name="submit" > <i class="fa fa-search"></i> {dr_lang('搜索')}</button></label>
</div>
</form>
</div>
<form class="form-horizontal" role="form" id="myform">
{dr_form_hidden()}
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
<th class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
</th>
<th width="70" style="text-align:center"> {dr_lang('排序')} </th>
<th width="200" class="{dr_sorting('title')}" name="title">{dr_lang('名称')}</th>
<th class="{dr_sorting('keyword')}" name="keyword">{dr_lang('关键词')}</th>
<th width="100" style="text-align:center" class="{dr_sorting('counts')}" name="counts">{dr_lang('命中次数')}</th>
<th width="170" class="{dr_sorting('updatetime')}" name="updatetime">{dr_lang('命中时间')}</th>
<th>{dr_lang('操作')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
<td class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="checkboxes" name="ids[]" value="{$t.id}" />
<span></span>
</label>
</td>
<td style="text-align:center">
<input type="text" onblur="dr_ajax_save(this.value, '{dr_url($uriprefix.'/displayorder_edit', ['id'=>$t.id])}')" value="{$t.displayorder}" class="displayorder form-control input-sm input-inline input-mini">
</td>
<td>{$t.title}</td>
<td>{$t.keyword}</td>
<td style="text-align:center">{$t.counts}</td>
<td>{dr_date($t.updatetime, '', 'red')}</td>
<td>
{if $ci->_is_admin_auth('edit')}
<label><a href="{dr_url($uriprefix.'/edit', ['id'=>$t.id, 'tid'=>$tid])}" class="btn btn-xs green"> <i class="fa fa-edit"></i> {dr_lang('修改')}</a></label>
{/if}
{if strpos($t.content, 'CID:')===0}<label style="display: none;"><a target="_blank" href="/index.php?s=weixin&c=news&id={substr($t.content, 5)}" class="btn btn-xs dark"> <i class="fa fa-search"></i> {dr_lang('预览')}</a></label>{/if}
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
<div class="row fc-list-footer table-checkable ">
<div class="col-md-5 fc-list-select">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
<button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/del')}', '{dr_lang('你确定要删除它们吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('删除')}</button>
</div>
<div class="col-md-7 fc-list-page">
{$mypages}
</div>
</div>
</form>
{template "footer.html"}
+121
View File
@@ -0,0 +1,121 @@
{template "header.html"}
<div class="note note-danger">
<p>多个关键词以分号分开,权重值越大匹配几率越高</p>
</div>
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="portlet bordered light myfbody">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject font-green sbold ">{dr_lang('回复规则')}</span>
</div>
<div class="actions">
<div class="btn-group">
<a class="btn" href="{$reply_url}"> <i class="fa fa-mail-reply"></i> {dr_lang('返回列表')}</a>
</div>
</div>
</div>
<div class="portlet-body form">
<div class="form-body wx-content-field">
<div class="form-group" id="dr_row_title">
<label class="col-xs-2 control-label">{dr_lang('规则名称')}</label>
<div class="col-xs-8">
<input type="text" class="form-control input-xlarge" name="data[title]" value="{$title}" id="dr_title" />
</div>
</div>
<div class="form-group" id="dr_row_keyword">
<label class="col-xs-2 control-label">{dr_lang('匹配关键字')}</label>
<div class="col-xs-8">
<input type="text" class="form-control input-xlarge" name="data[keyword]" value="{$keyword}" data-role="tagsinput" id="dr_keyword" />
</div>
</div>
<div class="form-group" id="dr_row_displayorder">
<label class="col-xs-2 control-label">{dr_lang('匹配权重值')}</label>
<div class="col-xs-8">
<label><input type="text" class="form-control" name="data[displayorder]" value="{$displayorder}" /></label>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">回复类型</label>
<div class="col-md-9">
<div class=" mt-radio-inline">
<label class="mt-radio mt-radio-outline"> 文本
<input type="radio" onclick="dr_content_type(0)" value="0" {if !$tid}checked{/if} name="data[tid]">
<span></span>
</label>
<label class="mt-radio mt-radio-outline"> 素材
<input type="radio" onclick="dr_content_type(1)" value="1" {if $tid}checked{/if} name="data[tid]">
<span></span>
</label>
</div>
</div>
</div>
<div class="form-group mytype" id="dr_type_0" style="display: none">
<label class="col-md-2 control-label">文本内容</label>
<div class="col-md-9">
<textarea class="form-control" rows="5" name="value[0]">{$content}</textarea>
</div>
</div>
<div class="form-group mytype" id="dr_type_1" style="display: none">
<label class="col-md-2 control-label">素材选择</label>
<div class="col-md-9">
<div class="input-group input-xlarge">
<input type="text" class="form-control" name="value[1]" id="gz_value_1" value="{$content}" >
<span class="input-group-btn">
<button class="btn green" type="button" onclick="dr_get_weixin_content('gz_value_1')">选择素材</button>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<button type="button" onclick="dr_ajax_submit('{dr_now_url()}', 'myform', '2000')" class="btn green"> <i class="fa fa-save"></i> {dr_lang('保存内容')}</button>
<button type="button" onclick="dr_ajax_submit('{dr_now_url()}', 'myform', '2000', '{$reply_url}')" class="btn yellow"> <i class="fa fa-mail-reply-all"></i> {dr_lang('保存并返回')}</button>
</div>
</div>
</form>
<script type="text/javascript">
$(function(){
dr_content_type('{intval($tid)}');
});
function dr_content_type(i) {
$('.mytype').hide();
$('#dr_type_'+i).show();
}
function dr_get_weixin_content(id) {
layer.open({
type: 2,
title: '选择素材',
fix:true,
scrollbar: false,
shadeClose: true,
shade: 0,
area: ['70%', '70%'],
btn: [lang['ok'], lang['esc']],
yes: function(index, layero){
var body = layer.getChildFrame('body', index);
$(body).find('.form-group').removeClass('has-error');
var form2 = $(body).find('#myform').serializeArray();
for ( var p in form2 ){ // 方法
if (form2[p].name == 'id') {
$('#'+id).val(form2[p].value);
}
}
//$('#'+id).val(form.cid);
layer.closeAll();
},
content: '{dr_url('weixin/api/content')}&is_ajax=1'
});
}
</script>
{template "footer.html"}
+131
View File
@@ -0,0 +1,131 @@
{template "header.html"}
<div class="note note-danger">
<p>只能推送给48小时内互动过的粉丝,否则就会提示发送失败</p>
</div>
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="portlet bordered light ">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject font-green ">客服群发</span>
</div>
</div>
<div class="portlet-body">
<div class="form-group">
<label class="col-xs-2 control-label">接收粉丝</label>
<div class="col-xs-8">
<div class=" mt-radio-inline">
<label class="mt-radio mt-radio-outline"> 全部粉丝【{$ucount}】
<input type="radio" value="0" {if !$uuid}checked{/if} name="data[groupid]">
<span></span>
</label>
{loop $group $v}
<label class="mt-radio mt-radio-outline"> {$v.name}【{$v.count}】
<input type="radio" {if $v.tag == $uuid}checked{/if} value="{$v.tag}" name="data[groupid]">
<span></span>
</label>
{/loop}
</div>
</div>
</div>
<div class="form-group">
<label class="col-xs-2 control-label">内容类型</label>
<div class="col-xs-8">
<div class=" mt-radio-inline">
<label class="mt-radio mt-radio-outline "> 内容
<input type="radio" onclick="dr_content_type(1)" value="1" checked name="data[type]">
<span></span>
</label>
<label class="mt-radio mt-radio-outline"> 文本
<input type="radio" onclick="dr_content_type(0)" value="0" name="data[type]">
<span></span>
</label>
</div>
</div>
</div>
</div>
</div>
<div class="portlet bordered light myfbody">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject font-green ">消息内容</span>
</div>
</div>
<div class="portlet-body mytype" id="dr_type_1" style="display: none">
<div class="row table-search-tool ">
<div class="col-xs-12">
<label><input type="text" class="form-control" value="{$param['keyword']}" name="search[keyword]" /></label>
<label><button type="submit" class="btn blue btn-sm onloading" name="submit" > <i class="fa fa-search"></i> {dr_lang('搜索')}</button></label>
<label>如果图文数超过1,则将会发送失败</label>
</div>
</div>
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
<th class="myselect"></th>
<th>{dr_lang('主题')}</th>
<th width="80" style="text-align:center" >{dr_lang('状态')}</th>
<th width="80" style="text-align:center" >{dr_lang('图文数')}</th>
<th width="170" >{dr_lang('发布时间')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
<td class="myselect" style="padding-left:10px !important">
<label class="mt-radio mt-radio-outline">
<input type="radio" name="data[content][1]" value="{$t.id}">
<span></span>
</label>
</td>
<td>{$t.title}</td>
<td style="text-align:center">
{if !$t.media_id}
<span class="label label-sm label-danger"> {dr_lang('未同步')} </span>
{else}
<span class="label label-sm label-success"> {dr_lang('已同步')} </span>
{/if}</td>
<td style="text-align:center">
{$t.nums}
</td>
<td>{dr_date($t.inputtime, '', 'red')}</td>
</tr>
{/loop}
</tbody>
</table>
</div>
</div>
<div class="portlet-body mytype" id="dr_type_0" style="display: none">
<textarea class="form-control" rows="5" name="data[content][0]"></textarea>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<button type="button" onclick="dr_ajax_submit('{dr_now_url()}&ac=send', 'myform', '2000')" class="btn green"> <i class="fa fa-send"></i> {dr_lang('发送')}</button>
</div>
</div>
</form>
<script type="text/javascript">
$(function(){
dr_content_type('1');
});
function dr_content_type(i) {
$('.mytype').hide();
$('#dr_type_'+i).show();
}
</script>
{template "footer.html"}
@@ -0,0 +1,92 @@
{template "header.html"}
<div class="note note-danger">
<p>在公众平台网站上,为订阅号提供了每天一条的群发权限,为服务号提供每月(自然月)4条的群发权限。</p>
</div>
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="portlet bordered light ">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject font-green ">接收粉丝</span>
</div>
</div>
<div class="portlet-body">
<div class=" mt-radio-inline">
<label class="mt-radio mt-radio-outline"> 全部粉丝【{$ucount}】
<input type="radio" value="0" checked name="data[groupid]">
<span></span>
</label>
{loop $group $v}
<label class="mt-radio mt-radio-outline"> {$v.name}【{$v.count}】
<input type="radio" value="{$v.tag}" name="data[groupid]">
<span></span>
</label>
{/loop}
</div>
</div>
</div>
<div class="portlet bordered light myfbody">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject font-green ">内容选择</span>
</div>
</div>
<div class="portlet-body">
<div class="row table-search-tool">
<div class="col-xs-12">
<label><input type="text" class="form-control" value="{$param['keyword']}" name="search[keyword]" /></label>
<label><button type="submit" class="btn blue btn-sm onloading" name="submit" > <i class="fa fa-search"></i> {dr_lang('搜索')}</button></label>
</div>
</div>
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
<th class="myselect"></th>
<th>{dr_lang('主题')}</th>
<th width="80" style="text-align:center" >{dr_lang('状态')}</th>
<th width="150" >{dr_lang('发布时间')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
<td class="myselect" style="padding-left:10px !important">
<label class="mt-radio mt-radio-outline">
<input type="radio" name="data[content]" value="{$t.id}">
<span></span>
</label>
</td>
<td>{$t.title}</td>
<td style="text-align:center">
{if !$t.media_id}
<span class="label label-sm label-danger"> {dr_lang('未同步')} </span>
{else}
<span class="label label-sm label-success"> {dr_lang('已同步')} </span>
{/if}</td>
<td>{dr_date($t.inputtime, '', 'red')}</td>
</tr>
{/loop}
</tbody>
</table>
</div>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<button type="button" onclick="dr_ajax_submit('{dr_now_url()}&ac=send', 'myform', '2000')" class="btn green"> <i class="fa fa-send"></i> {dr_lang('发送')}</button>
</div>
</div>
</form>
{template "footer.html"}
+112
View File
@@ -0,0 +1,112 @@
{template "header.html"}
<div class="note note-danger">
<p>模板消息发送对象是已关注本公众号的粉丝</p>
</div>
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="row myfbody">
<div class="col-md-12">
<div class="form-horizontal">
<div class="portlet bordered light ">
<div class="portlet-title tabbable-line">
<ul class="nav nav-tabs" style="float:left;">
{loop $module $dir $t}
<li class="{if $page == $dir}active{/if}">
<a href="#tab_{$dir}" data-toggle="tab" onclick="$('#dr_page').val('{$dir}')"> <i class="{dr_icon($t.icon)}"></i> {$t.name} </a>
</li>
{/loop}
</ul>
</div>
<input type="hidden" id="dr_page" value="{$page}">
<div class="portlet-body">
<div class="tab-content" style="padding-top: 30px">
{loop $module $dir $m}
{php $i=$dir;}
<div class="tab-pane {if $page==$dir}active{/if}" id="tab_{$dir}">
<div class="tab-pane {if $i == $page}active{/if}" id="tab_{$i}">
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">可用状态</label>
<div class="col-md-9">
<input type="checkbox" name="data[{$dir}][use]" value="1" {if $data[$dir]['use']}checked{/if} data-on-text="{dr_lang('已开启')}" data-off-text="{dr_lang('已关闭')}" data-on-color="success" data-off-color="danger" class="make-switch" data-size="small">
<span class="help-block">{dr_lang('开启后会出现在模块记录列表中')}</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label ">{dr_lang('模版ID')}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="data[{$dir}][id]" value="{$data[$dir]['id']}">
<span class="help-block">在微信公众号中-功能-模板消息-我的模板:模板ID</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label ">{dr_lang('主题颜色')}</label>
<div class="col-md-6">
<label> <input type="text" class="form-control" name="data[{$dir}][color]" value="{$data[$dir]['color']}"></label>
<span class="help-block">微信消息主题显示的颜色,例如:红色是#ff0000</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label ">{dr_lang('模板内容参数')}</label>
<div class="col-md-9">
<table class="table table-mtotal table-nomargin table-bordered table-striped table-bordered table-advance">
<thead>
<tr>
<th width="200">参数名</th>
<th>参数值</th>
</tr>
</thead>
<tbody>
{php for ($i = 0;$i < 10 ;$i++) { }
<?php
if (!isset($data[$dir]['content'])) {
$data[$dir]['content'] = [];
}
?>
<tr>
<td><input type="text" class="form-control" name="data[{$dir}][content][{$i}][name]" value="{$data[$dir]['content'][$i]['name']}"></td>
<td><textarea class="form-control" style="height:80px" name="data[{$dir}][content][{$i}][value]">{$data[$dir]['content'][$i]['value']}</textarea></td>
</tr>
{php } }
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{/loop}
</div>
</div>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<label><button type="button" onclick="dr_ajax_submit('{dr_now_url()}&page='+$('#dr_page').val(), 'myform', '2000')" class="btn green"> <i class="fa fa-save"></i> {dr_lang('保存内容')}</button></label>
</div>
</div>
</form>
{template "footer.html"}
+108
View File
@@ -0,0 +1,108 @@
{template "header.html"}
{template "api_list_date_search.html"}
<div class="right-card-box">
<div class="row table-search-tool">
<form action="{SELF}" method="get">
{dr_form_search_hidden()}
<div class="col-md-12 col-sm-12">
<label>
<select name="field" class="form-control">
{loop $field $t}
<option value="{$t.fieldname}" {if $param.field==$t.fieldname}selected{/if}>{$t.name}</option>
{/loop}
<option value="id"> Id </option>
</select>
</label>
<label><i class="fa fa-caret-right"></i></label>
<label><input type="text" class="form-control" placeholder="" value="{$param['keyword']}" name="keyword" /></label>
</div>
<div class="col-md-12 col-sm-12">
<label>
<div class="input-group input-medium date-picker input-daterange" data-date="" data-date-format="yyyy-mm-dd">
<input type="text" class="form-control" value="{$param.date_form}" name="date_form">
<span class="input-group-addon"> {dr_lang('到')} </span>
<input type="text" class="form-control" value="{$param.date_to}" name="date_to">
</div>
</label>
</div>
<div class="col-md-12 col-sm-12">
<label><button type="submit" class="btn blue btn-sm onloading" name="submit" > <i class="fa fa-search"></i> {dr_lang('搜索')}</button></label>
</div>
</form>
</div>
<form class="form-horizontal" role="form" id="myform">
{dr_form_hidden()}
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
{if $ci->_is_admin_auth('del')}
<th class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
</th>
{/if}
<th class="{dr_sorting('title')}" name="title">{dr_lang('主题')}</th>
<th width="100" class="{dr_sorting('counts')}" name="counts">{dr_lang('发送人数')}</th>
<th width="170" class="{dr_sorting('inputtime')}" name="inputtime">{dr_lang('发布时间')}</th>
<th>{dr_lang('操作')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
{if $ci->_is_admin_auth('del')}
<td class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="checkboxes" name="ids[]" value="{$t.id}" />
<span></span>
</label>
</td>
{/if}
<td>{dr_list_function('title', $t['title'], $param)}</td>
<td>{$t.counts}</td>
<td>{dr_date($t.inputtime)}</td>
<td>
{if $ci->_is_admin_auth('edit')}
<label><a href="{dr_url($uriprefix.'/edit', ['id'=>$t.id])}" class="btn btn-xs green"> <i class="fa fa-edit"></i> {dr_lang('修改')}</a></label>
<label><a href="javascript:dr_admin_menu_ajax('{dr_url($uriprefix.'/copy_edit', ['id'=>$t.id])}');" class="btn btn-xs dark"> <i class="fa fa-copy"></i> {dr_lang('复制')}</a></label>
{/if}
<label><a href="javascript:;" onclick="dr_bfb_submit('{dr_lang('发送给微信粉丝')}', 'myform', '{dr_url('weixin/template/todo_add', ['id' => $t.id])}')" class="btn btn-xs dark"> <i class="fa fa-send"></i> {dr_lang('发送')}</a></label>
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
<div class="row fc-list-footer table-checkable ">
<div class="col-md-5 fc-list-select">
{if $ci->_is_admin_auth('del')}
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
<button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/del')}', '{dr_lang('你确定要删除它们吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('删除')}</button>
{/if}
</div>
<div class="col-md-7 fc-list-page">
{$mypages}
</div>
</div>
</form>
{template "footer.html"}
+130
View File
@@ -0,0 +1,130 @@
{template "header.html"}
<div class="note note-danger">
<p>模板消息发送对象是已关注本公众号的粉丝</p>
</div>
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="row myfbody">
<div class="col-md-12">
<div class="portlet light bordered">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject font-green sbold ">{dr_lang('消息信息')}</span>
</div>
<div class="actions">
<div class="btn-group">
<a class="btn" href="{$reply_url}"> <i class="fa fa-mail-reply"></i> {dr_lang('返回列表')}</a>
</div>
</div>
</div>
<div class="portlet-body">
<div class="form-body">
<div class="form-group" id="dr_row_title">
<label class="col-md-2 control-label ">{dr_lang('主题')}</label>
<div class="col-md-6">
<input type="text" class="form-control" id="dr_title" name="data[title]" value="{$title}">
<span class="help-block">在CMS中描述这个消息是干什么的,不会在微信中显示</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label ">{dr_lang('模版ID')}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="data[template]" value="{$template}">
<span class="help-block">在微信公众号中-功能-模板消息-我的模板:模板ID</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label ">{dr_lang('跳转URL')}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="data[url]" value="{$url}">
<span class="help-block">在微信公众号中单击这个模板消息的跳转url,需要https://或者http://开头</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label ">{dr_lang('主题颜色')}</label>
<div class="col-md-6">
<label> <input type="text" class="form-control" name="data[color]" value="{$color}"></label>
<span class="help-block">微信消息主题显示的颜色,例如:红色是#ff0000</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label ">{dr_lang('已发统计')}</label>
<div class="col-md-6">
<label> <input type="text" class="form-control" name="data[counts]" value="{$counts}"></label>
</div>
</div>
<div class="form-group">
<label class="col-xs-2 control-label">接收粉丝</label>
<div class="col-xs-8">
<div class=" mt-radio-inline">
<label class="mt-radio mt-radio-outline"> 全部粉丝【{$ucount}】
<input type="radio" onclick="$('.is_openid').hide()" value="0" {if !$groupid}checked{/if} name="data[groupid]">
<span></span>
</label>
{loop $group $v}
<label class="mt-radio mt-radio-outline"> {$v.name}【{$v.count}】
<input type="radio" onclick="$('.is_openid').hide()" {if $groupid == $v.tag}checked{/if} value="{$v.tag}" name="data[groupid]">
<span></span>
</label>
{/loop}
{loop $ci->member_cache['group'] $v}
<label class="mt-radio mt-radio-outline"> {$v.name}
<input type="radio" onclick="$('.is_openid').hide()" {if $groupid == -$v.id}checked{/if} value="-{$v.id}" name="data[groupid]">
<span></span>
</label>
{/loop}
</div>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label ">{dr_lang('模板内容参数')}</label>
<div class="col-md-9">
<table class="table table-mtotal table-nomargin table-bordered table-striped table-bordered table-advance">
<thead>
<tr>
<th width="200">参数名</th>
<th>参数值</th>
</tr>
</thead>
<tbody>
{php for ($i = 0;$i < 10 ;$i++) { }
<tr>
<td><input type="text" class="form-control" name="data[content][{$i}][name]" value="{$content[$i]['name']}"></td>
<td>
<textarea class="form-control" style="height:80px" name="data[content][{$i}][value]">{$content[$i]['value']}</textarea>
</td>
</tr>
{php } }
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<label><button type="button" onclick="dr_ajax_submit('{dr_now_url()}', 'myform', '2000')" class="btn green"> <i class="fa fa-save"></i> {dr_lang('保存内容')}</button></label>
<label><button type="button" onclick="dr_ajax_submit('{dr_now_url()}', 'myform', '2000', '{$reply_url}')" class="btn yellow"> <i class="fa fa-send"></i> {dr_lang('保存并返回')}</button></label>
</div>
</div>
</form>
{template "footer.html"}
+119
View File
@@ -0,0 +1,119 @@
{template "header.html"}
<div class="note note-danger">
<p><a href="https://developers.weixin.qq.com/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html" target="_blank">2021年12月27日之后,微信关注后回调接口不再获取微信头像和昵称</a></p>
</div>
<div class="right-card-box">
<div class="row table-search-tool">
<form action="{SELF}" method="get">
{dr_form_search_hidden()}
<div class="col-md-12 col-sm-12">
<label>
<select name="groupid" class="form-control">
<option value=""> {dr_lang('全部')} </option>
{loop $group $t}
<option value="{$t.tag}" {if $param.groupid==$t.tag}selected{/if}>{$t.name}</option>
{/loop}
</select>
</label>
</div>
<div class="col-md-12 col-sm-12">
<label>
<select name="field" class="form-control">
{loop $field $t}
{if $t.ismain}
<option value="{$t.fieldname}" {if $param.field==$t.fieldname}selected{/if}>{$t.name}</option>
{/if}
{/loop}
</select>
</label>
<label><i class="fa fa-caret-right"></i></label>
<label><input type="text" class="form-control" placeholder="" value="{$param['keyword']}" name="keyword" /></label>
</div>
<div class="col-md-12 col-sm-12">
<label><button type="submit" class="btn blue btn-sm onloading" name="submit" > <i class="fa fa-search"></i> {dr_lang('搜索')}</button></label>
</div>
</form>
</div>
<form class="form-horizontal" role="form" id="myform">
{dr_form_hidden()}
<div class="table-scrollable">
<table class="table table-striped table-bordered table-hover table-checkable dataTable">
<thead>
<tr class="heading">
<th class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
</th>
<th style="text-align:center" width="70" class="{dr_sorting('id')}" name="id">Id</th>
<th width="80" style="text-align:center" class="{dr_sorting('id')}" name="id">{dr_lang('头像')}</th>
<th width="180" class="{dr_sorting('nickname')}" name="nickname">{dr_lang('昵称')}</th>
<th width="210" class="{dr_sorting('openid')}" name="openid">{dr_lang('OID')}</th>
<th style="text-align:center" class="{dr_sorting('groupids')}" name="groupids">{dr_lang('标签组')}</th>
<th width="200" style="text-align:center" class="{dr_sorting('uid')}" name="uid">{dr_lang('绑定账号')}</th>
<th width="170" class="{dr_sorting('subscribe')}" name="subscribe">{dr_lang('关注时间')}</th>
<th>{dr_lang('操作')}</th>
</tr>
</thead>
<tbody>
{loop $list $t}
<tr class="odd gradeX" id="dr_row_{$t.id}">
<td class="myselect">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="checkboxes" name="ids[]" value="{$t.id}" />
<span></span>
</label>
</td>
<td style="text-align:center"> {$t.id} </td>
<td style="text-align:center"> <img width="30" class="img-circle" src="{if $t.headimgurl}{$t.headimgurl}{else}{dr_avatar(0)}{/if}"> </td>
<td>{dr_html2emoji($t.nickname)}</td>
<td>{trim($t.openid)}</td>
<td style="text-align:center">{if !$t.groupids}--{else}
{php $gids=dr_string2array($t.groupids);}
{loop $gids $i}
<span class="label label-sm label-success" id="{$i}">{$group[$i]['name']}</span>
{/loop}
{/if}</td>
<td style="text-align:center">{if !$t.uid}--{else}<a href="javascript:;" member="{$t.username}" class="fc_member_show"> {$t.username} </a>{/if}</td>
<td>{dr_date($t.subscribe, '', 'red')}</td>
<td>
{if $ci->_is_admin_auth('weixin/send/add')}
<label><a href="{dr_url('weixin/send/index', ['uid'=>$t.id])}" class="btn btn-xs green"> <i class="fa fa-send"></i> {dr_lang('发送消息')}</a></label>
{/if}
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
<div class="row fc-list-footer table-checkable ">
<div class="col-md-5 fc-list-select">
<label class="mt-table mt-checkbox mt-checkbox-single mt-checkbox-outline">
<input type="checkbox" class="group-checkable" data-set=".checkboxes" />
<span></span>
</label>
<button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/del')}', '{dr_lang('你确定要删除它们吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('删除')}</button>
<label>
<select name="groupid" class="form-control">
<option value=""> -- </option>
{loop $group $t}
<option value="{$t.tag}" {if $param.groupid==$t.id}selected{/if}>{$t.name}</option>
{/loop}
</select>
</label>
<label><button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/move_edit')}', '{dr_lang('你确定要操作它们吗?')}', 1)" class="btn green btn-sm"> <i class="fa fa-edit"></i> {dr_lang('设置分组')}</button></label>
<label><button type="button" onclick="dr_ajax_option('{dr_url($uriprefix.'/move_del')}', '{dr_lang('你确定要操作它们吗?')}', 1)" class="btn red btn-sm"> <i class="fa fa-trash"></i> {dr_lang('取消分组')}</button></label>
</div>
<div class="col-md-7 fc-list-page">
{$mypages}
</div>
</div>
</form>
{template "footer.html"}
+126
View File
@@ -0,0 +1,126 @@
{template "header.html"}
<script src="{THEME_PATH}assets/global/plugins/amcharts/amcharts/amcharts.js" type="text/javascript"></script>
<script src="{THEME_PATH}assets/global/plugins/amcharts/amcharts/serial.js" type="text/javascript"></script>
<script src="{THEME_PATH}assets/global/plugins/amcharts/amcharts/themes/light.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
var chart = AmCharts.makeChart("chartdiv", {
"theme": "light",
"type": "serial",
"dataProvider": {$data_tj},
"valueAxes": [{
"unit": "人",
"position": "left",
"title": "最近关注详情",
}],
"startDuration": 1,
"graphs": [{
"balloonText": "[[category]] 新关注粉丝数: <b>[[value]]</b>",
"fillAlphas": 0.9,
"lineAlpha": 0.2,
"title": "新关注",
"type": "column",
"valueField": "year2004"
}, {
"balloonText": "[[category]] 累计关注粉丝数: <b>[[value]]</b>",
"fillAlphas": 0.9,
"lineAlpha": 0.2,
"title": "累计关注",
"type": "column",
"clustered":false,
"columnWidth":0.5,
"valueField": "year2005"
}],
"plotAreaFillAlphas": 0.1,
"categoryField": "country",
"categoryAxis": {
"gridPosition": "start"
},
"export": {
"enabled": true
}
});
});
</script>
<div class="row widget-row">
<div class="col-md-3">
<!-- BEGIN WIDGET THUMB -->
<div class="widget-thumb widget-bg-color-white text-uppercase margin-bottom-20 bordered">
<h4 class="widget-thumb-heading">今日新关注</h4>
<div class="widget-thumb-wrap">
<i class="widget-thumb-icon bg-green fa fa-plus"></i>
<div class="widget-thumb-body" style="padding-top:10px">
<span class="widget-thumb-body-stat">{intval($fans[$today]['new'])}</span>
</div>
</div>
</div>
<!-- END WIDGET THUMB -->
</div>
<div class="col-md-3">
<!-- BEGIN WIDGET THUMB -->
<div class="widget-thumb widget-bg-color-white text-uppercase margin-bottom-20 bordered">
<h4 class="widget-thumb-heading">今日取消关注 </h4>
<div class="widget-thumb-wrap">
<i class="widget-thumb-icon bg-red fa fa-minus"></i>
<div class="widget-thumb-body" style="padding-top:10px">
<span class="widget-thumb-body-stat">{intval($fans[$today]['cancel'])}</span>
</div>
</div>
</div>
<!-- END WIDGET THUMB -->
</div>
<div class="col-md-3">
<!-- BEGIN WIDGET THUMB -->
<div class="widget-thumb widget-bg-color-white text-uppercase margin-bottom-20 bordered">
<h4 class="widget-thumb-heading">累积关注 </h4>
<div class="widget-thumb-wrap">
<i class="widget-thumb-icon bg-blue icon-bar-chart"></i>
<div class="widget-thumb-body" style="padding-top:10px">
<span class="widget-thumb-body-stat">{intval($usercount)}</span>
</div>
</div>
</div>
<!-- END WIDGET THUMB -->
</div>
<div class="col-md-3">
<!-- BEGIN WIDGET THUMB -->
<div class="widget-thumb widget-bg-color-white text-uppercase margin-bottom-20 bordered">
<h4 class="widget-thumb-heading">今日消息数 </h4>
<div class="widget-thumb-wrap">
<i class="widget-thumb-icon bg-purple fa fa-envelope"></i>
<div class="widget-thumb-body" style="padding-top:10px">
<span class="widget-thumb-body-stat">{intval($msgcount)}</span>
</div>
</div>
</div>
<!-- END WIDGET THUMB -->
</div>
</div>
<div class="row">
<div class="col-md-12 col-sm-12">
<div class="portlet light bordered">
<div class="portlet-title">
<div class="caption">
<span class="caption-subject bold uppercase font-dark">关注详情</span>
</div>
</div>
<div class="portlet-body">
<div id="chartdiv" class="chart" style="height: 400px;"> </div>
</div>
</div>
</div>
</div>
{template "footer.html"}
+91
View File
@@ -0,0 +1,91 @@
{template "header.html"}
<form action="" class="form-horizontal" method="post" name="myform" id="myform">
{$form}
<div class="portlet bordered light myfbody">
<div class="portlet-title tabbable-line">
<ul class="nav nav-tabs" style="float:left;">
<li class="{if $page==0}active{/if}">
<a href="#tab_0" data-toggle="tab" onclick="$('#dr_page').val('0')"> <i class="fa fa-cog"></i> {dr_lang('账号设置')} </a>
</li>
</ul>
</div>
<div class="portlet-body">
<div class="tab-content">
<div class="tab-pane {if $page==0}active{/if}" id="tab_0">
<div class="form-body">
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">AppId</label>
<div class="col-md-9">
<input class="form-control input-xlarge" type="text" name="data[appid]" value="{$data['appid']}" >
</div>
</div>
</div>
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">AppSecret</label>
<div class="col-md-9">
<input class="form-control input-xlarge" type="text" name="data[appsecret]" value="{$data['appsecret']}" >
</div>
</div>
</div>
<div class="form-body">
<div class="form-group">
<label class="col-md-2 control-label">授权登录模式</label>
<div class="col-md-9">
<div class="mt-radio-inline">
<label class="mt-radio mt-checkbox-outline"><input type="radio" name="data[login]" value="0" {if !$data['login']}checked{/if} /> {dr_lang('绑定账号')} <span></span></label>
<label class="mt-radio mt-checkbox-outline"><input type="radio" name="data[login]" value="1" {if $data['login']}checked{/if} /> {dr_lang('直接登录')} <span></span></label>
</div>
<span class="help-block">{dr_lang('绑定账号:点击授权登录按钮后会提示账号绑定或者注册账号;直接登录:直接创建一个新账号')}</span>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane {if $page==1}active{/if}" id="tab_1">
<div class="form-body">
</div>
</div>
</div>
</div>
</div>
<div class="portlet-body form myfooter">
<div class="form-actions text-center">
<button type="button" onclick="dr_ajax_submit('{dr_now_url()}&page='+$('#dr_page').val(), 'myform', '2000')" class="btn green"> <i class="fa fa-save"></i> {dr_lang('保存')}</button>
</div>
</div>
</form>
<script type="text/javascript">
function dr_to_token() {
$.get("{dr_url(APP_DIR.'/api/token')}", function(data){
$("#sys_token").val(data);
});
}
function dr_to_aeskey() {
$.get("{dr_url(APP_DIR.'/api/asckey')}", function(data){
$("#sys_asckey").val(data);
});
}
</script>
{template "footer.html"}