创建版本

This commit is contained in:
2021-02-22 12:17:00 +08:00
commit af555f49c3
2332 changed files with 369202 additions and 0 deletions
@@ -0,0 +1,136 @@
<?php namespace Gdoo\Wechat\Controllers;
use Request;
use DB;
use Gdoo\System\Models\Setting;
use Gdoo\Wechat\Models\Config;
use Gdoo\Wechat\Services\WechatService;
use Gdoo\Wechat\Services\MenuService;
use Gdoo\Index\Controllers\DefaultController;
class ConfigController extends DefaultController
{
public $permission = [];
protected $layout = 'layouts.wechat';
protected $menu = [];
protected $config = [];
public function __construct(MenuService $menu) {
parent::__construct();
$this->menu = $menu;
}
public function configAction()
{
if (Request::method() == 'POST') {
$gets = Request::all();
foreach ($gets as $key => $value) {
Setting::where('type', 'wechat')->where('key', $key)->update([
'value' => $value,
]);
}
return $this->json('保存成功。', true);
}
$header['tabs'] = Config::$tabs;
$app = Setting::where('type', 'wechat')->pluck('value', 'key');
return $this->display([
'app' => $app,
'header' => $header,
]);
}
/**
* 自定义菜单
*/
public function menuAction()
{
if (Request::ajax()) {
$app = WechatService::getApp();
$gets = Request::all();
$data = $gets['data'];
// 空菜单认为删除全部菜单
if (empty($data)) {
Setting::where('type', 'wechat')->where('key', 'menu')->update(['value' => '']);
$app->menu->delete();
return $this->json('保存成功', true);
}
$menu_type = [
'view' => '跳转URL',
'click' => '点击推事件',
'scancode_push' => '扫码推事件',
'scancode_waitmsg' => '扫码推事件且弹出“消息接收中”提示框',
'pic_sysphoto' => '弹出系统拍照发图',
'pic_photo_or_album' => '弹出拍照或者相册发图',
'pic_weixin' => '弹出微信相册发图器',
'location_select' => '弹出地理位置选择器',
];
Setting::where('type', 'wechat')->where('key', 'menu')->update([
'value' => json_encode($data, JSON_UNESCAPED_UNICODE)
]);
foreach ($data as &$row) {
if (empty($row['content'])) {
$row['content'] = uniqid();
}
switch ($row['type']) {
case 'miniprogram':
list($row['appid'], $row['url'], $row['pagepath']) = explode(',', $row['content'].',,');
break;
case 'view':
$row['url'] = preg_match('#^(\w+:)?//#i', $row['content']) ? $row['content'] : url($row['content']);
break;
case 'event':
if (isset($menu_type[$row['content']])) {
$row['type'] = $row['content'];
$row['key'] = "wechat_menu#id#{$row['id']}";
}
break;
case 'media_id':
$row['media_id'] = $row['content'];
break;
default:
(!in_array($row['type'], $menu_type)) && $row['type'] = 'click';
$row['key'] = "{$row['content']}";
}
unset($row['content']);
}
$menus = $this->menu->GetTreeByMenu($data, 'index', 'pindex', 'sub_button');
foreach ($menus as &$menu) {
unset($menu['index'], $menu['pindex'], $menu['id']);
if (empty($menu['sub_button'])) {
continue;
}
foreach ($menu['sub_button'] as &$submenu) {
unset($submenu['index'], $submenu['pindex'], $submenu['id']);
}
unset($menu['type']);
}
$ret = $app->menu->create($menus);
if ($ret['errcode'] == 0) {
return $this->json('发布成功', true);
} else {
return $this->json('errcode:'.$ret['errcode'].' errmsg:'.$ret['errmsg']);
}
}
$app = Setting::where('type', 'wechat')->pluck('value', 'key');
$menus = (array)json_decode($app['menu'], JSON_UNESCAPED_UNICODE);
$menus = $this->menu->GetTreeByMenu($menus, 'index', 'pindex');
$header['tabs'] = Config::$tabs;
return $this->display([
'header' => $header,
'menus' => $menus,
]);
}
}
@@ -0,0 +1,252 @@
<?php namespace Gdoo\Wechat\Controllers;
use Cache;
use DB;
use Log;
use Gdoo\Wechat\Models\WechatUser;
use Gdoo\Wechat\Services\WechatService;
use Gdoo\Index\Controllers\Controller;
use Gdoo\System\Models\Setting;
use EasyWeChat\Factory;
use EasyWeChat\Kernel\Messages\News;
use EasyWeChat\Kernel\Messages\NewsItem;
use EasyWeChat\Kernel\Messages\Text;
class EchoController extends Controller
{
private $wechat = null;
private $openid = null;
public function __construct() {
parent::__construct();
}
public function indexAction()
{
if (empty($_GET['echostr']) && empty($_GET["signature"]) && empty($_GET["nonce"])) {
exit('Access denied');
}
$app = WechatService::getApp();
$app->server->push(function ($msg) {
$config = WechatService::getConfig();
$this->openid = $msg['FromUserName'];
// $fc = new \GdooWord('igb', database_path().'/dict.igb');
// $arr = $fc->getAutoWord($msg['Content']);
// Log::info('anc', $arr);
/*
$items = [
new NewsItem([
'title' => '某某某公司发货提醒',
'description' => "单据编号:123456\n发货时间:2020-01-12",
'url' => "http://israel.sinaapp.com/cet/index.php?openid=".$this->openid,
'image' => '',
]),
];
*/
/*
$items = [
new NewsItem([
'title' => '流程[办公用品采购]审核提醒',
'description' => "转交人:李先生\n时间:2020-01-12",
'url' => "http://shenghua.test/index.php?openid=".$this->openid,
'image' => '',
]),
];
$news = new News($items);
return $news;
$msg = new Text("订单发货最新三条\n1.单据编号:123456,发货时间:2020-01-12,件数:123,金额:100\n2.单据编号:123456,发货时间:2020-01-12,件数:123,金额:100\n2.单据编号:123456,发货时间:2020-01-12,件数:123,金额:100");
$msg = new Text("促销最新三条\n1.单据编号:123456,发货时间:2020-01-12,件数:123,金额:100\n2.单据编号:123456,发货时间:2020-01-12,件数:123,金额:100\n2.单据编号:123456,发货时间:2020-01-12,件数:123,金额:100");
$msg = new Text("进店最新三条\n1.单据编号:123456,发货时间:2020-01-12,件数:123,金额:100\n2.单据编号:123456,发货时间:2020-01-12,件数:123,金额:100\n2.单据编号:123456,发货时间:2020-01-12,件数:123,金额:100");
return $msg;
*/
//print_R($arr);
//exit;
if ($config['status'] == 0) {
return '服务关闭中,请稍后再试。';
}
switch ($msg['MsgType']) {
case 'text':
return $msg['Content'];
break;
case 'image':
//$this->special('image', $msg);
break;
case 'voice':
return $msg['Content'];
//$this->special('voice', $msg);
break;
case 'video':
return '收到视频消息';
break;
case 'location':
return '收到坐标消息';
break;
case 'link':
return '收到链接消息';
break;
case 'file':
return '收到文件消息';
break;
case 'event':
switch (strtolower($msg['Event'])) {
// 关注
case 'subscribe':
//$this->subscribe($msg);
break;
// 取消关注
case 'unsubscribe':
//$this->subscribe($msg, 'unsubscribe');
break;
// 用户扫码已关注时的事件推送
case 'scan':
//$this->scan($msg);
break;
// 上报地理位置事件 event_location
case 'location':
//$this->special('event_location', $msg);
break;
// 自定义菜单事件
case 'click':
//$this->keyword($msg['EventKey'], $msg);
break;
// 点击菜单跳转链接时的事件推送
case 'view':
//$this->special('view', $msg);
break;
default:
break;
break;
}
// 其它消息
default:
// return '收到其它消息';
break;
}
});
return $app->server->serve();
}
/**
* 文件消息处理
*/
protected function api()
{
return $this->keys("wechat_keys#keys#{$this->receive['content']}", false, $this->forceCustom);
}
/**
* 文件消息处理
*/
protected function text()
{
return $this->keys("wechat_keys#keys#{$this->receive['content']}", false, $this->forceCustom);
}
/**
* 粉丝关注\取消关注
*/
public function subscribe($msg, $type = 'subscribe')
{
$friendInfo = $this->api->get_user_info($this->openid);
$friendInfo = (array)$friendInfo[1];
$model = WechatUser::firstOrNew(['openid' => $this->openid]);
// 公众号没有权限获取用户基本信息 可按需求扩展
if (empty($friendInfo)) {
if ($type == 'subscribe') {
} elseif ($type == 'unsubscribe') {
}
} else {
if ($type == 'subscribe') {
$model->avatar = $friendInfo['headimgurl'];
$model->openid = $friendInfo['openid'];
$model->gender = $friendInfo['sex'];
$model->name = $friendInfo['nickname'];
$model->address = $friendInfo['country']."\n".$friendInfo['province']."\n".$friendInfo['city'];
$model->subscribe = 1;
$model->created_at = time();
$model->status = 1;
// 有场景参数
if (isset($msg['Ticket'])) {
$recommend = WechatUser::where('ticket', $msg['Ticket'])->first();
$model->parent_id = $recommend['id'];
}
// 关注成功后发送消息
} elseif ($type == 'unsubscribe') {
$model->subscribe = 0;
$model->unsubscribe_time = time();
$model->status = 0;
}
$model->save();
}
if (isset($msg['Ticket'])) {
$this->replyNews($msg);
} else {
$rule = Db::table('wx_mp_rule')
->where('mpid', $this->mid)
->where('event', 'subscribe')
->first();
if ($rule) {
$reply = DB::table('wx_mp_reply')->where('reply_id', $rule['reply_id'])->first();
$this->we->reply($reply['content']);
}
}
}
public function replyNews($msg) {
$temple = DB::table('house_temple')->where('ticket', $msg['Ticket'])->first();
$this->we->reply([
'type' => 'news',
'articles' => [[
'title' => $temple['name'],
'description' => $temple['remark'],
'picurl' => url('uploads/'.$temple['image']),
'url' => url('wap/index/info', ['id' => $temple['id']]),
],[
'title' => '立即供灯',
'description' => '立即供灯',
'picurl' => '',
'url' => url('wap/light/index', ['temple_id' => $temple['id']]),
]
]
]);
}
/**
* 扫描二维码事件
*/
public function scan($msg)
{
// 有场景参数
if (isset($msg['Ticket'])) {
$this->replyNews($msg);
}
}
public function json($data, $status = false)
{
$json = [
'data' => $data,
'status' => $status,
];
return response()->json($json)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
}
}
+12
View File
@@ -0,0 +1,12 @@
<?php namespace Gdoo\Wechat\Models;
class Config
{
static public $tabs = [
'name' => 'tab',
'items' => [
['value' => 'config.config', 'url' => 'wechat/config/config', 'name' => '微信配置'],
['value' => 'config.menu', 'url' => 'wechat/config/menu', 'name' => '微信菜单'],
]
];
}
+8
View File
@@ -0,0 +1,8 @@
<?php namespace Gdoo\Wechat\Models;
use Gdoo\Index\Models\BaseModel;
class WechatUser extends BaseModel
{
protected $table = 'wechat_user';
}
+23
View File
@@ -0,0 +1,23 @@
<?php namespace Gdoo\Wechat\Services;
use Cache;
class MenuService
{
public function GetTreeByMenu($list, $id = 'id', $pid = 'pid', $son = 'sub')
{
$tree = $map = [];
foreach ($list as $item) {
$map[$item[$id]] = $item;
}
foreach ($list as $item) {
if (isset($item[$pid]) && isset($map[$item[$pid]])) {
$map[$item[$pid]][$son][] = &$map[$item[$id]];
} else {
$tree[] = &$map[$item[$id]];
}
}
unset($map);
return $tree;
}
}
@@ -0,0 +1,39 @@
<?php namespace Gdoo\Wechat\Services;
use Cache;
use Gdoo\System\Models\Setting;
use EasyWeChat\Factory;
class WechatService
{
public static function getApp()
{
static $app = null;
if ($app == null) {
$config = static::getConfig();
$app = Factory::officialAccount([
'app_id' => $config['wechat_appid'],
'secret' => $config['wechat_secret'],
'token' => $config['wechat_token'],
'aes_key' => $config['wechat_aeskey'],
'response_type' => 'array',
'log' => [
'level' => 'debug',
'file' => storage_path().'/logs/wechat.log',
],
]);
}
return $app;
}
public static function getConfig()
{
static $config = null;
if ($config == null) {
$config = Setting::where('type', 'wechat')->pluck('value', 'key');
}
return $config;
}
}
+19
View File
@@ -0,0 +1,19 @@
<?php
return [
"name" => "微信管理",
"version" => "1.0",
"description" => "微信管理。",
"controllers" => [
"config" => [
"name" => "微信管理",
"actions" => [
"menu" => [
"name" => "菜单",
],
"config" => [
"name" => "配置",
],
]
]
]
];
@@ -0,0 +1,95 @@
<div class="panel">
@include('tabs2')
<form class="form-horizontal" method="post" id="myform" action="{{url()}}">
<div class="panel-body">
<div class="form-group">
<label class="control-label col-sm-2">AppId</label>
<div class="col-sm-6">
<input type="text" name="wechat_appid" value="{{$app['wechat_appid']}}" required lay-verify="required" placeholder="请输入AppId" autocomplete="off"
class="form-control input-sm">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">AppSecret</label>
<div class="col-sm-6">
<input type="text" name="wechat_secret" value="{{$app['wechat_secret']}}" required lay-verify="required" placeholder="请输入AppSecret"
autocomplete="off" class="form-control input-sm">
</div>
</div>
<!--
<div class="form-group">
<label class="control-label col-sm-2">关闭回复</label>
<div class="col-sm-6">
<textarea name="desc" placeholder="请输入内容" class="form-control input-sm">{{$mp['desc']}}</textarea>
</div>
</div>
-->
<div class="form-group">
<label class="control-label col-sm-2">URL(服务器地址)</label>
<div class="col-sm-6">
<code>{{url('wechat/echo/index')}}</code>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Token(令牌)</label>
<div class="col-sm-6">
<input type="text" name="token" value="{{$app['wechat_token']}}" required lay-verify="required" placeholder="请输入令牌" autocomplete="off" class="form-control input-sm">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">EncodingAESKey(消息加解密密钥)</label>
<div class="col-sm-6">
<input type="text" name="wechat_aeskey" value="{{$app['wechat_aeskey']}}" required lay-verify="required" placeholder="请输入消息加解密密钥" autocomplete="off" class="form-control input-sm">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">开关状态</label>
<div class="col-sm-6">
<div class="radio">
<label class="i-checks i-checks-sm">
<input type="radio" @if($app['wechat_status']==1) checked @endif value="1" name="wechat_status">
<i></i>开启</label>
&nbsp;&nbsp;
<label class="i-checks i-checks-sm">
<input type="radio" @if($app['wechat_status']==0) checked @endif value="0" name="wechat_status">
<i></i>关闭</label>
</div>
</div>
</div>
<div class="form-group m-b-none">
<label class="control-label col-sm-2"></label>
<div class="col-sm-6">
<button class="btn btn-success" lay-submit lay-filter="sbm">立即提交</button>
<button type="reset" class="btn btn-default">重置</button>
</div>
</div>
</div>
</form>
</div>
<script>
layui.use('form', function () {
var form = layui.form;
form.on('submit(sbm)', function () {
var data = $('#myform').serialize();
$.post('{{url()}}', data, function (res) {
if (res.status == '1') {
toastrSuccess(res.data);
}
})
return false;
});
});
</script>
+381
View File
@@ -0,0 +1,381 @@
<div class="panel">
@include('tabs2')
<style>
.mobile-preview {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
}
.menu-editor {
left: 317px;
display: block;
max-width: 500px;
width: 500px;
height: 581px;
border-radius: 0;
border-color: #dbdbdb;
box-shadow: 0 5px 10px rgba(0,0,0,.1);
}
.menu-editor .arrow {
top: auto !important;
bottom: 15px
}
.menu-editor .popover-title {
margin-top: 0
}
.menu-delete {
font-weight: 400;
font-size: 12px;
}
</style>
<div class="panel-body">
<div class="mp-menu">
<div class='mobile-preview pull-left'>
<div class='mobile-header'>{{$mp['name']}}</div>
<div class='mobile-body'></div>
<ul class='mobile-footer'>
@foreach($menus as $menu)
<li class="parent-menu">
<a>
<i class="icon-sub hide"></i>
<span data-type="{{$menu['type']}}" data-content="{{$menu['content']}}">{{$menu['name']}}</span>
</a>
<div class="sub-menu text-center hide">
<ul>
@if($menu['sub']) @foreach($menu['sub'] as $submenu)
<li>
<a class="bottom-border">
<span data-type="{{$submenu['type']}}" data-content="{{$submenu['content']}}">{{$submenu['name']}}</span>
</a>
</li>
@endforeach @endif
<li class="menu-add">
<a>
<i class="icon-add"></i>
</a>
</li>
</ul>
<i class="arrow arrow_out"></i>
<i class="arrow arrow_in"></i>
</div>
</li>
@endforeach
<li class="parent-menu menu-add">
<a>
<i class="icon-add"></i>
</a>
</li>
</ul>
</div>
<div class="pull-left" style="position:absolute">
<div class="popover fade right up in menu-editor">
<div class="arrow"></div>
<h3 class="popover-title">
菜单名称
<a class="pull-right menu-delete">删除</a>
</h3>
<div class="popover-content menu-content"></div>
</div>
</div>
<div class="hide menu-editor-parent-tpl">
<form class="form-horizontal">
<p>已添加子菜单,仅可设置菜单名称。</p>
<div class="form-group">
<label class="control-label col-sm-2">菜单名称</label>
<div class="col-sm-6">
<input name="menu-name" class="form-control input-sm">
<span class="layui-form-mid layui-word-aux">字数不超过5个汉字或16个字母</span>
</div>
</div>
</form>
</div>
<div class="hide menu-editor-content-tpl">
<form class="form-horizontal m-t-xs">
<div class="form-group">
<label class="control-label col-sm-3">菜单名称</label>
<div class="col-sm-9">
<input name="menu-name" class="form-control input-sm">
<span class="layui-form-mid layui-word-aux">字数不超过13个汉字或40个字母</span>
</div>
</div>
<!--
<div class="layui-form-item" style="margin-top:50px">
<label class="layui-form-label">菜单名称</label>
<div class="layui-input-block">
<input name="menu-name" class="form-control input-sm">
<span class="layui-form-mid layui-word-aux">字数不超过13个汉字或40个字母</span>
</div>
</div>
-->
<div class="form-group">
<label class="control-label col-sm-3">菜单名称</label>
<div class="col-sm-9">
<!--<label class="col-xs-5 font-noraml">-->
<!--<input class="cuci-radio" type="radio" name="menu-type" value="text"> 文字消息-->
<!--</label>-->
<div class="radio">
<label class="col-xs-5">
<input class="cuci-radio" type="radio" name="menu-type" value="keys"> 关键字
</label>
<label class="col-xs-5">
<input class="cuci-radio" type="radio" name="menu-type" value="view"> 跳转网页
</label>
<label class="col-xs-5">
<input class="cuci-radio" type="radio" name="menu-type" value="event"> 事件功能
</label>
<label class="col-xs-5">
<input class="cuci-radio" type="radio" name="menu-type" value="miniprogram"> 小程序
</label>
<!--<label class="col-xs-5 font-noraml">-->
<!--<input class="cuci-radio" type="radio" name="menu-type" value="customservice"> 多客服-->
<!--</label>-->
</div>
</div>
</div>
<div class="editor-content-input"></div>
</form>
</div>
</div>
</div>
<div class="panel-footer">
<button class="btn btn-info menu-submit" lay-filter="formDemo">保存发布</button>
<button class="btn btn-danger">取消发布</button>
</div>
</div>
<script>
$(function () {
/**
* 菜单事件构造方法
* @returns {menu.index_L2.menu}
*/
var menu = function () {
this.version = '1.0';
this.$btn;
this.listen();
};
/**
* 控件默认事件
* @returns {undefined}
*/
var layer;
layui.use('layer', function () {
layer = layui.layer;
});
menu.prototype.listen = function () {
var self = this;
$('.mobile-footer').on('click', 'li a', function () {
self.$btn = $(this);
self.$btn.parent('li').hasClass('menu-add') ? self.add() : self.checkShow();
}).find('li:first a:first').trigger('click');
$('.menu-delete').on('click', function () {
var index = layer.confirm('确定删除吗?', function () {
self.del(), layer.close(index);
});
});
$('.menu-submit').on('click', function () {
self.submit();
});
};
/**
* 添加一个菜单
* @returns {undefined}
*/
menu.prototype.add = function () {
var $add = this.$btn.parent('li'), $ul = $add.parent('ul');
if ($ul.hasClass('mobile-footer')) { /* 添加一级菜单 */
var $li = $('<li class="parent-menu"><a class="active"><i class="icon-sub hide"></i> <span>一级菜单</span></a></li>').insertBefore($add);
this.$btn = $li.find('a');
$('<div class="sub-menu text-center hide"><ul><li class="menu-add"><a><i class="icon-add"></i></a></li></ul><i class="arrow arrow_out"></i><i class="arrow arrow_in"></i></div>').appendTo($li);
} else { /* 添加二级菜单 */
this.$btn = $('<li><a class="bottom-border"><span>二级菜单</span></a></li>').prependTo($ul).find('a');
}
this.checkShow();
};
/**
* 数据校验显示
* @returns {unresolved}
*/
menu.prototype.checkShow = function () {
var $li = this.$btn.parent('li'), $ul = $li.parent('ul');
/* 选中一级菜单时显示二级菜单 */
if ($li.hasClass('parent-menu')) {
$('.parent-menu .sub-menu').not(this.$btn.parent('li').find('.sub-menu').removeClass('hide')).addClass('hide');
}
/* 一级菜单添加按钮 */
var $add = $('li.parent-menu:last');
$add.siblings('li').size() >= 3 ? $add.addClass('hide') : $add.removeClass('hide');
/* 二级菜单添加按钮 */
$add.siblings('li').map(function () {
var $add = $(this).find('ul li:last');
$add.siblings('li').size() >= 5 ? $add.addClass('hide') : $add.removeClass('hide');
});
/* 处理一级菜单 */
var parentWidth = 100 / $('li.parent-menu:visible').size() + '%';
$('li.parent-menu').map(function () {
var $icon = $(this).find('.icon-sub');
$(this).width(parentWidth).find('ul li').size() > 1 ? $icon.removeClass('hide') : $icon.addClass('hide');
});
/* 更新选择中状态 */
$('.mobile-footer a.active').not(this.$btn.addClass('active')).removeClass('active');
this.renderEdit();
return $ul;
};
/**
* 删除当前菜单
* @returns {undefined}
*/
menu.prototype.del = function () {
var $li = this.$btn.parent('li'), $ul = $li.parent('ul');
var $default = function () {
if ($li.prev('li').size() > 0) {
return $li.prev('li');
}
if ($li.next('li').size() > 0 && !$li.next('li').hasClass('menu-add')) {
return $li.next('li');
}
if ($ul.parents('li.parent-menu').size() > 0) {
return $ul.parents('li.parent-menu');
}
return $('null');
}.call(this);
$li.remove();
this.$btn = $default.find('a:first');
this.checkShow();
};
/**
* 显示当前菜单的属性值
* @returns {undefined}
*/
menu.prototype.renderEdit = function () {
var $span = this.$btn.find('span'), $li = this.$btn.parent('li'), $ul = $li.parent('ul');
var $html = '';
if ($li.find('ul li').size() > 1) { /*父菜单*/
$html = $($('.menu-editor-parent-tpl').html());
$html.find('input[name="menu-name"]').val($span.text()).on('change keyup', function () {
$span.text(this.value || ' ');
});
$('.menu-editor .menu-content').html($html);
} else {
$html = $($('.menu-editor-content-tpl').html());
$html.find('input[name="menu-name"]').val($span.text()).on('change keyup', function () {
$span.text(this.value || ' ');
});
$('.menu-editor .menu-content').html($html);
var type = $span.attr('data-type') || 'text';
$html.find('input[name="menu-type"]').on('click', function () {
$span.attr('data-type', this.value || 'text');
var content = $span.data('content') || '';
var type = this.value;
var html = function () {
switch (type) {
case 'miniprogram':
var tpl = '<div><div class="form-group"><label class="control-label col-sm-3">appid</label><div class="col-sm-9"><input type="text" name="appid" required="" lay-verify="required" placeholder="appid" autocomplete="off" class="form-control input-sm" value="{appid}"></div></div><div class="form-group"><label class="control-label col-sm-3">url</label><div class="col-sm-9"><input type="text" name="url" required="" lay-verify="required" placeholder="url" autocomplete="off" class="form-control input-sm" value="{url}"></div></div><div class="form-group"><label class="control-label col-sm-3">pagepath</label><div class="col-sm-9"><input type="text" name="pagepath" required="" lay-verify="required" placeholder="pagepath" autocomplete="off" class="form-control input-sm" value="{pagepath}"></div></div></div>';
var _appid = '', _pagepath = '', _url = '';
if (content.indexOf(',') > 0) {
_appid = content.split(',')[0] || '';
_url = content.split(',')[1] || '';
_pagepath = content.split(',')[2] || '';
}
$span.data('appid', _appid), $span.data('url', _url), $span.data('pagepath', _pagepath);
return tpl.replace('{appid}', _appid).replace('{url}', _url).replace('{pagepath}', _pagepath);
case 'customservice':
case 'text':
return '<div>回复内容<textarea style="resize:none;height:225px" name="content" class="form-control input-sm">{content}</textarea></div>'.replace('{content}', content);
case 'view':
return '<div class="form-group"><label class="control-label col-sm-3">跳转地址</label><div class="col-sm-9"><textarea placeholder="请输入内容" class="form-control" name="content">{content}</textarea></div></div>'.replace('{content}', content);
case 'keys':
return '<div class="form-group"><label class="control-label col-sm-3">匹配内容</label><div class="col-sm-9"><textarea placeholder="请输入内容" class="form-control" name="content">{content}</textarea></div></div>'.replace('{content}', content);
case 'event':
var options = {
'scancode_push': '扫码推事件',
'scancode_waitmsg': '扫码推事件且弹出“消息接收中”提示框',
'pic_sysphoto': '弹出系统拍照发图',
'pic_photo_or_album': '弹出拍照或者相册发图',
'pic_weixin': '弹出微信相册发图器',
'location_select': '弹出地理位置选择器'
};
var select = [], tpl = '<div class="form-group" style="margin-bottom:auto;"><label class="control-label col-sm-3"></label><div class="col-sm-9"><div class="radio"><label><input class="cuci-radio" name="content" type="radio" {checked} value="{value}"> {title}</label></div></div></div>';
if (!(options[content] || false)) {
content = 'scancode_push';
$span.data('content', content);
}
for (var i in options) {
select.push(tpl.replace('{value}', i).replace('{title}', options[i]).replace('{checked}', (i === content) ? 'checked' : ''));
}
return select.join('');
}
}.call(this);
var $html = $(html), $input = $html.find('input,textarea');
$input.on('change keyup click', function () {
// 将input值写入到span上
$span.data(this.name, $(this).val() || $(this).html());
// 如果是小程序,合并内容到span的content上
if (type === 'miniprogram') {
$span.data('content', $span.data('appid') + ',' + $span.data('url') + ',' + $span.data('pagepath'));
}
});
$('.editor-content-input').html($html);
}).filter('input[value="{type}"]'.replace('{type}', type)).trigger('click');
}
};
/**
* 提交数据
* @returns {undefined}
*/
menu.prototype.submit = function () {
var data = [];
function getdata($span) {
var menudata = {};
menudata.name = $span.text();
menudata.type = $span.attr('data-type');
menudata.content = $span.data('content') || '';
return menudata;
}
$('li.parent-menu').map(function (index, item) {
if (!$(item).hasClass('menu-add')) {
var menudata = getdata($(item).find('a:first span'));
menudata.index = index + 1;
menudata.pindex = 0;
menudata.sub = [];
menudata.sort = index;
data.push(menudata);
$(item).find('.sub-menu ul li:not(.menu-add) span').map(function (ii, span) {
var submenudata = getdata($(span));
submenudata.index = (index + 1) + '' + (ii + 1);
submenudata.pindex = menudata.index;
submenudata.sort = ii;
data.push(submenudata);
});
}
});
var data = (data == '') ? '' : data;
var load = layer.load(2);
$.post('{{url("wechat/mp/menuedit")}}', {data: data}, function (res) {
layer.close(load);
if (res.status) {
layer.msg(res.data, {time: 1000}, function () {});
} else {
layer.alert(res.data);
}
}, 'json')};
new menu();
});
</script>
@@ -0,0 +1,145 @@
<script src="{{$asset_url}}/vendor/zclip/jquery.zclip.min.js" type="text/javascript"></script>
<div class="panel">
@include('tabs', ['tabKey' => 'mp'])
<div class="panel-heading tabs-box">
<ul class="nav nav-tabs">
<li class="@if($type == 'list') active @endif">
<a class="text-sm" href="{{url('wechat/mp/qrcode',['type'=>'list'])}}">二维码列表</a>
</li>
<li class="@if($type == 'statistics') active @endif">
<a class="text-sm" href="{{url('wechat/mp/qrcode',['type'=>'statistics'])}}">二维码扫描统计</a>
</li>
</ul>
</div>
<div class="wrapper-sm">
<a href="{{url('qrcodeadd')}}" id="addkw" class="btn btn-info btn-sm">增加二维码</a>
</div>
<div class="table-responsive">
<table class="table table-hover m-b-none b-t table-hover">
@if($type == 'list')
<tr>
<th>二维码</th>
<th>场景名称</th>
<th>对应关键字</th>
<th>类型</th>
<th>到期时间</th>
<th>链接</th>
<th>操作</th>
</tr>
@foreach($data as $vo)
<tr>
<td class="text-center">
<div style="padding: 1px; border: #e6e6e6 solid 1px; width:50px; float: left; ">
<img class="form_logo" src="{{$vo['qrcode_url']}}" width="50" height="50">
</div>
</td>
<td class="text-center">{{$vo['scene_name']}}</td>
<td class="text-center">{{$vo['keyword']}}</td>
<td class="text-center">@if($vo['qr_type'] == 0) 临时 @else 永久 @endif
</td>
<td class="text-center">@if($vo['qr_type'] == 0) @datetime($vo['create_time']) @else 长期有效 @endif
</td>
<td class="text-center">
{{$vo['url']}}
</td>
<td class="text-center">
<a class="option" href="javascript:;" onclick="delQrcode('{{$vo['id']}}')">删除</a>
<a target="_blank" href="{{$vo['qrcode_url']}}" class="option">查看</a>
</td>
</tr>
@endforeach
@endif
@if($type == 'statistics')
<tr>
<th>二维码</th>
<th>场景名称</th>
<th>触发关键字</th>
<th>类型</th>
<th>被扫总数</th>
<th>粉丝增加</th>
<th>操作</th>
</tr>
@foreach($data as $vo)
<tr>
<td>
<div style="padding: 1px; border: #e6e6e6 solid 1px; width:50px; float: left; ">
<img class="form_logo" src="{{$vo['qrcode_url']}}" width="50" height="50">
</div>
</td>
<td>{{$vo['scene_name']}}</td>
<td>{{$vo['keyword']}}</td>
<td>@if($vo['qr_type'] == 0) 临时 @else 永久 @endif
</td>
<td>{{$vo['scan_count']}}</td>
<td>{{$vo['gz_count']}}</td>
<td>
<a href="{{url('qrcode',['scene_id'=>$vo['scene_id'],'type'=>'friend'])}}" class="rha-bt-a">查看增加粉丝</a>
</td>
</tr>
@endforeach
@endif
@if($type == 'friend')
<tr>
<th>场景 ID</th>
<th>呢称</th>
<th>头像</th>
<th>扫码次数</th>
<th>扫码时间</th>
</tr>
@foreach($data as $vo)
<tr>
<td>{$vo['scene_id']}</td>
<td>{$vo['nickname']}</td>
<td>
<img height="38" width="38" style="border-radius: 3px;" src="{{$vo['headimgurl']}}">
</td>
<td>{$vo['scan_count']}</td>
<td>{{date('Y-m-d H:i', $vo['create_time'])}}</td>
</tr>
@endforeach
@endif
</table>
</div>
<footer class="panel-footer">
<div class="row">
<div class="col-sm-1 hidden-xs">
</div>
<div class="col-sm-11 text-right text-center-xs">
{{$data->render()}}
</div>
</div>
</footer>
</div>
<script>
function delQrcode(id) {
layui.use('layer', function () {
var layer = layui.layer;
layer.confirm('你确定需要删除吗?', {
btn: ['是', '不'] //按钮
}, function () {
$.post("{{url('wechat/mp/delQrcode')}}", { 'id': id }, function (res) {
if (res.status == 1) {
layer.alert(res.msg, function (index) {
window.location.reload();
layer.close(index);
})
} else {
layer.alert(res.msg)
}
})
}, function () {
});
});
}
</script>
@@ -0,0 +1,79 @@
<form class="layui-form" action="" style="padding-right:10px; ">
<div class="layui-form-item">
<label class="layui-form-label">场景名称</label>
<div class="layui-input-block">
<input type="text" name="name" required lay-verify="required" placeholder="请输入名称" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">关联关键词</label>
<div class="layui-input-block">
<input type="text" name="keyword" required lay-verify="required" placeholder="请输入关键词" autocomplete="off"
class="layui-input">
<p class="tip_for_p">扫描此二维码的同时也会触发此关键词。</p>
</div>
</div>
<div id="qrcodes" class="layui-form-item">
<label class="layui-form-label">类型</label>
<div id="replyType" class="layui-input-block">
<input type="radio" checked name="qr_type" value="2" title="永久">
<input type="radio" name="qr_type" value="0" title="临时">
<p class="tip_for_p">注:目前腾讯规定了永久二维码只能生成10万个,请悠着点使用永久类型二维码。</p>
</div>
</div>
<div id="qrcode">
<div class="qr_2 layui-form-item layui-show layui-tab-item">
<label class="layui-form-label">场景值ID</label>
<div class="layui-input-block">
<input type="text" name="scene_str" placeholder="请输入场景值字符串" autocomplete="off"
class="layui-input">
<p class="tip_for_p">场景值ID(字符串形式的ID),字符串类型,长度限制为1到64。</p>
</div>
</div>
<div class="qr_0 layui-form-item layui-tab-item">
<div class="layui-inline">
<label class="layui-form-label">有效时间/</label>
<div class="layui-input-inline">
<input name="time" required lay-verify="required" autocomplete="off" value="2592000" class="layui-input" type="tel">
</div>
<div class="layui-form-mid layui-word-aux">临时二维码过期时间, 最大为30天(2592000秒)</div>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<script>
$(function () {
$("#qrcodes").click(function () {
var class_a = 'qr_' + $("input[name='qr_type']:checked").val();
$('#qrcode div').removeClass('layui-show')
$('.' + class_a).addClass('layui-show')
});
})
layui.use('form', function () {
var form = layui.form;
//监听提交
form.on('submit(formDemo)', function (data) {
// layer.msg(JSON.stringify(data.field));
$.post('',data.field,function (res) {
if (res.status=='0') {
layer.msg(res.msg);
}
if (res.status=='1') {
layer.msg(res.msg);
window.location.href = res.url;
}
})
return false;
});
});
</script>
@@ -0,0 +1,59 @@
<div class="panel">
@include('tabs', ['tabKey' => 'mp'])
<div class="panel-body">
<form class="form-horizontal" id="myform" method="POST" action="{{url()}}">
<div class="form-group">
<label class="control-label col-sm-2">开始ID</label>
<div class="col-sm-6">
<input type="text" name="start_id" value="{{(int)$qrcode['scene_id'] + 1}}" required lay-verify="required" placeholder="请输入开始ID"
autocomplete="off" class="form-control input-sm">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">结束ID</label>
<div class="col-sm-6">
<input type="text" name="end_id" value="{{(int)$qrcode['scene_id'] + $max}}" required lay-verify="required" placeholder="请输入结束ID"
autocomplete="off" class="form-control input-sm">
</div>
</div>
<div class="form-group m-b-none">
<label class="control-label col-sm-2"></label>
<div class="col-sm-6">
<button class="btn btn-success" lay-submit lay-filter="formDemo">保存</button>
<button type="reset" class="btn btn-default">重置</button>
</div>
</div>
</form>
</div>
</div>
<script>
$(function () {
layui.use('form', function () {
var form = layui.form;
// 监听提交
form.on('submit(formDemo)', function () {
var data = $('#myform').serialize();
var load = layer.load(2);
$.post('{{url()}}', data, function (res) {
layer.close(load);
if (res.status == '0') {
layer.msg(res.msg);
}
if (res.status == '1') {
layer.msg(res.msg);
window.location.href = res.url;
}
})
return false;
});
});
});
</script>
@@ -0,0 +1,94 @@
<div class="panel">
@include('tabs', ['tabKey' => 'mp'])
<!--
<div class="panel-heading tabs-box">
<ul class="nav nav-tabs">
<li class="@if($type == 'list') active @endif">
<a class="text-sm" href="{{url('wechat/mp/qrcode',['type'=>'list'])}}">二维码列表</a>
</li>
<li class="@if($type == 'statistics') active @endif">
<a class="text-sm" href="{{url('wechat/mp/qrcode',['type'=>'statistics'])}}">二维码扫描统计</a>
</li>
</ul>
</div>
-->
<div class="wrapper">
<form id="search-form" class="form-inline" name="mysearch" action="{{url()}}" method="get">
<div class="pull-right">
@if(isset($access['showdelete']))
<a class="btn btn-sm btn-danger" href="javascript:optionDelete('#myform','{{url('showdelete')}}');">
<i class="icon icon-remove"></i> 删除</a>
@endif
</div>
@include('searchForm')
</form>
<script type="text/javascript">
$(function () {
$('#search-form').searchForm({
data: {{ json_encode($search['forms'])}},
init: function (e) {
var self = this;
}
});
});
</script>
</div>
<div class="table-responsive">
<table class="table table-hover m-b-none table-hover">
<tr>
<th align="center">
<input type="checkbox" class="select-all">
</th>
<th>场景ID</th>
<th>类型</th>
<th>到期时间</th>
<th>二维码链接</th>
<th>ID</th>
<th></th>
</tr>
@foreach($rows as $vo)
<tr>
<td align="center">
<input type="checkbox" class="select-row" value="{{$vo['id']}}" name="id[]">
</td>
<td class="text-center">{{$vo['scene_id']}}</td>
<td class="text-center">
@if($vo['qr_type'] == 0)
临时
@else
永久
@endif
</td>
<td class="text-center">
@if($vo['qr_type'] == 0)
@datetime($vo['created_at'] + $vo['expire'])
@else
长期有效
@endif
</td>
<td class="text-center">
{{$vo['url']}}
</td>
<td class="text-center">
{{$vo['id']}}
</td>
<td class="text-center">
<a target="_blank" href="{{$vo['qrcode_url']}}" class="option">查看</a>
</td>
</tr>
@endforeach
</table>
</div>
<footer class="panel-footer">
<div class="row">
<div class="col-sm-1 hidden-xs">
</div>
<div class="col-sm-11 text-right text-center-xs">
{{$rows->render()}}
</div>
</div>
</footer>
</div>