初始上传

This commit is contained in:
2026-04-04 17:27:12 +08:00
parent 4d80d28eb4
commit b7e11774ee
11191 changed files with 1588469 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\api\controller;
use addon\weapp\model\Weapp;
use app\Controller;
use think\facade\Log;
class Auth extends Controller
{
public $wechat;
public function __construct()
{
parent::__construct();
$site_id = request()->siteid();
$this->wechat = new Weapp($site_id);
}
/**
* 小程序消息推送
*/
public function relateWeixin()
{
Log::write('微信小程序消息推送');
$this->wechat->relateWeixin();
}
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\api\controller;
use addon\weapp\model\Config;
use addon\weapp\model\Message;
use app\api\controller\BaseApi;
use addon\weapp\model\Weapp as WeappModel;
use app\model\system\Pay as PayModel;
class Weapp extends BaseApi
{
/**
* 获取openid
*/
public function authCodeToOpenid()
{
$weapp_model = new WeappModel($this->site_id);
$res = $weapp_model->authCodeToOpenid($this->params);
return $this->response($res);
}
/**
* 获取消息模板id(最多三条)
*/
public function messageTmplIds()
{
$keywords = $this->params[ 'keywords' ] ?? '';
$message = new Message();
$res = $message->getMessageTmplIds($this->site_id, $keywords);
return $this->response($res);
}
/*
* 获取小程序码
*/
public function qrcode()
{
$config_model = new Config();
$config = $config_model->getWeappConfig($this->site_id);
$qrcode = $config[ 'data' ][ 'value' ][ 'qrcode' ] ?? '';
return $this->response($this->success($qrcode));
}
/**
* 分享
* @return false|string
*/
public function share()
{
/*$config_model = new Config();
$config = $config_model->getShareConfig($this->site_id, 'shop');
$share_config = $config['data']['value'];*/
$this->checkToken();
//页面路径
$path = $this->params[ 'path' ] ?? '';
//分享配置
$share_config = [];
$share_data = event('WeappShareData', [
'path' => $path,
'site_id' => $this->site_id,
'member_id' => $this->member_id,
], true);
if (!empty($share_data)) {
$share_config[ 'permission' ] = $share_data[ 'permission' ];
$share_config[ 'data' ] = $share_data[ 'data' ];
} else {
$share_config[ 'permission' ] = [
'onShareAppMessage' => false,
'onShareTimeline' => false,
];
$share_config[ 'data' ] = null;
}
return $this->response($this->success($share_config));
}
}

38
addon/weapp/config/diy_view.php Executable file
View File

@@ -0,0 +1,38 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
return [
// 自定义模板页面类型,格式:[ 'title' => '页面类型名称', 'name' => '页面标识', 'path' => '页面路径', 'value' => '页面数据json格式' ]
'template' => [],
// 后台自定义组件——装修
'util' => [],
// 自定义页面路径
'link' => [],
// 自定义图标库
'icon_library' => [],
// uni-app 组件,格式:[ 'name' => '组件名称/文件夹名称', 'path' => '文件路径/目录路径' ]多个逗号隔开自定义组件名称前缀必须是diy-,也可以引用第三方组件
'component' => [],
// uni-app 页面,多个逗号隔开
'pages' => [],
// 模板信息,格式:'title' => '模板名称', 'name' => '模板标识', 'cover' => '模板封面图', 'preview' => '模板预览图', 'desc' => '模板描述'
'info' => [],
// 主题风格配色格式可以自由定义扩展【在uni-app中通过this.themeStyle... 获取定义的颜色字段例如this.themeStyle.main_color】
'theme' => [],
// 自定义页面数据,格式:[ 'title' => '页面名称', 'name' => "页面标识", 'value' => [页面数据json格式] ]
'data' => []
];

63
addon/weapp/config/event.php Executable file
View File

@@ -0,0 +1,63 @@
<?php
// 事件定义文件
return [
'bind' => [
],
'listen' => [
// 生成获取二维码
'Qrcode' => [
'addon\weapp\event\Qrcode'
],
// 开放数据解密
'DecryptData' => [
'addon\weapp\event\DecryptData'
],
// 获取手机号
'PhoneNumber' => [
'addon\weapp\event\PhoneNumber'
],
// 发货成功
'OrderDeliveryAfter' => [
'addon\weapp\event\OrderDeliveryAfter'
],
// 发货成功后小程序发货
'OrderDeliveryAfterWeappDelivery' => [
'addon\weapp\event\OrderDeliveryAfterWeappDelivery'
],
// 订单收货后执行事件(异步)
'OrderTakeDeliveryAfter' => [
'addon\weapp\event\OrderTakeDeliveryAfter'
],
/************************** 虚拟发货相关 *****************************/
// 盲盒订单支付后
'BlindboxOrderPay' => [
'addon\weapp\event\BlindboxOrderPay'
],
// 礼品卡订单支付后
'GiftCardOrderPay' => [
'addon\weapp\event\GiftCardOrderPay'
],
// 充值订单支付后
'MemberRechargeOrderPay' => [
'addon\weapp\event\MemberRechargeOrderPay'
],
// 超级会员卡订单支付后
'MemberLevelOrderPay' => [
'addon\weapp\event\MemberLevelOrderPay'
],
// 积分兑换订单支付后
'PointExchangeOrderPay' => [
'addon\weapp\event\PointExchangeOrderPay'
],
// 小程序虚拟发货
'WeappVirtualDelivery' => [
'addon\weapp\event\WeappVirtualDelivery'
],
/************************** 虚拟发货相关 *****************************/
],
'subscribe' => [
],
];

20
addon/weapp/config/info.php Executable file
View File

@@ -0,0 +1,20 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
return [
'name' => 'weapp',
'title' => '微信小程序',
'description' => '微信小程序功能',
'type' => 'system', //插件类型 system :系统插件(自动安装), promotion:扩展营销插件 tool:工具插件
'status' => 1,
'author' => '',
'version' => '5.5.3',
'version_no' => '553250709001',
'content' => '',
];

View File

@@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | 平台端菜单设置
// +----------------------------------------------------------------------
return [
[
'name' => 'WEAPP_ROOT',
'title' => '微信小程序',
'url' => 'weapp://shop/weapp/setting',
'parent' => 'CHANNEL_ROOT',
'picture_select' => '',
'picture' => 'addon/weapp/shop/view/public/img/menu_icon/wechat_app_new.png',
'picture_selected' => 'addon/weapp/shop/view/public/img/menu_icon/wechat_app_select.png',
'is_show' => 1,
'sort' => 4,
'child_list' => [
[
'name' => 'WEAPP_CONFIG',
'title' => '基础配置',
'url' => 'weapp://shop/weapp/config',
'is_show' => 0,
'sort' => 2,
'type' => 'button',
],
[
'name' => 'WEAPP_PACKAGE',
'title' => '小程序发布',
'url' => 'weapp://shop/weapp/package',
'is_show' => 0,
'sort' => 3,
'type' => 'button',
],
[
'name' => 'WEAPP_PACKAGE',
'title' => '订阅消息',
'url' => 'weapp://shop/message/config',
'is_show' => 0,
'sort' => 4,
'type' => 'button',
],
[
'name' => 'WEAPP_PACKAGE_EDIT',
'parent' => 'MESSAGE_LISTS',
'title' => '编辑订阅消息',
'url' => 'weapp://shop/message/edit',
'is_show' => 0,
'sort' => 1,
'type' => 'button',
],
[
'name' => 'WEAPP_SHARE',
'title' => '小程序分享',
'url' => 'weapp://shop/weapp/share',
'is_show' => 0,
'sort' => 6,
'type' => 'button',
]
]
]
];

View File

@@ -0,0 +1,26 @@
<?php
return [
40001 => '获取 access_token 时 AppSecret 错误,或者 access_token 无效。请认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口',
40002 => '不合法的凭证类型',
40013 => '不合法的 AppID ,请检查 AppID 的正确性,避免异常字符,注意大小写',
40014 => '不合法的 access_token ,请认真比对 access_token 的有效性',
40029 => '无效的 oauth_code',
40030 => '不合法的 refresh_token',
40125 => '无效的appsecret',
40132 => '微信号不合法',
40164 => 'IP' . request()->ip() . '未加入公众号ip白名单',
41008 => '缺少 oauth code',
41009 => '缺少 openid',
42001 => 'access_token 超时,请检查 access_token 的有效期',
42002 => 'refresh_token 超时',
42003 => 'oauth_code 超时',
43001 => '需要 GET 请求',
43002 => '需要 POST 请求',
43003 => '需要 HTTPS 请求',
45011 => '频率限制每个用户每分钟100次',// API 调用太频繁,请稍候再试
48004 => 'api 接口被封禁,请登录 mp.weixin.qq.com 查看详情',
48005 => 'api 禁止删除被自动回复和自定义菜单引用的素材',
48006 => 'api 禁止清零调用次数,因为清零次数达到上限',
40226 => '高风险等级用户,小程序登录拦截 。风险等级详见用户安全解方案',
];

1
addon/weapp/data/install.sql Executable file
View File

@@ -0,0 +1 @@
SET NAMES 'utf8';

1
addon/weapp/data/uninstall.sql Executable file
View File

@@ -0,0 +1 @@
SET NAMES 'utf8';

View File

@@ -0,0 +1,24 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use app\model\system\Cron;
/**
* 礼品卡订单支付后
*/
class BlindboxOrderPay
{
public function handle($param)
{
return (new Cron())->addCron(1, 0, "小程序虚拟发货", "WeappVirtualDelivery", time() + 60, $param['out_trade_no']);
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use addon\weapp\model\Weapp;
/**
* 开放数据解密
*/
class DecryptData
{
/**
* 执行安装
*/
public function handle($param = [])
{
if ($param['app_type'] == 'weapp') {
$weapp = new Weapp($param['site_id']);
return $weapp->decryptData($param);
}
}
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use app\model\system\Cron;
/**
* 礼品卡订单支付后
*/
class GiftCardOrderPay
{
public function handle($param)
{
return (new Cron())->addCron(1, 0, "小程序虚拟发货", "WeappVirtualDelivery", time() + 60, $param['out_trade_no']);
}
}

25
addon/weapp/event/Install.php Executable file
View File

@@ -0,0 +1,25 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
/**
* 应用安装
*/
class Install
{
/**
* 执行安装
*/
public function handle()
{
return success();
}
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use app\model\system\Cron;
/**
* 礼品卡订单支付后
*/
class MemberLevelOrderPay
{
public function handle($param)
{
return (new Cron())->addCron(1, 0, "小程序虚拟发货", "WeappVirtualDelivery", time() + 60, $param['out_trade_no']);
}
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use app\model\system\Cron;
/**
* 充值订单完成后
*/
class MemberRechargeOrderPay
{
public function handle($param)
{
return (new Cron())->addCron(1, 0, "小程序虚拟发货", "WeappVirtualDelivery", time() + 60, $param['out_trade_no']);
}
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use app\model\system\Cron;
/**
* 订单发货完成,小程序发货信息录入
*/
class OrderDeliveryAfter
{
public function handle($data)
{
//支付后立即调用发货接口,微信会提示订单不存在,所以延迟一分钟执行,如果是
//{"errcode":10060001,"errmsg":"支付单不存在 rid: 66235dcf-4803e8cf-5c30a69e"}
//如果是物流发货和同城配送不会有问题,自提订单和虚拟订单有可能支付后就立即发货
(new Cron())->addCron(1, 0, "订单发货后小程序发货", "OrderDeliveryAfterWeappDelivery", time() + 60, $data[ 'order_id' ]);
}
}

View File

@@ -0,0 +1,175 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use addon\weapp\model\Weapp;
use app\model\order\Order;
use app\model\shop\Shop as ShopModel;
use app\dict\order\OrderDict;
use think\facade\Log;
/**
* 订单发货完成,小程序发货信息录入
*/
class OrderDeliveryAfterWeappDelivery
{
public function handle($param)
{
try{
//订单信息
$order_model = new Order();
$filed = 'o.order_id,o.site_id,o.order_type,o.out_trade_no,o.pay_type,o.mobile,o.promotion_type,m.weapp_openid';
$join = [
[ 'member m', 'o.member_id=m.member_id', 'left' ]
];
$order_info = model('order')->getInfo([ [ 'order_id', '=', $param[ 'relate_id' ] ] ], $filed, 'o', $join);
if (empty($order_info)) return $order_model->success();
if ($order_info[ 'pay_type' ] != 'wechatpay') return $order_model->success();
// 检测微信小程序是否已开通发货信息管理服务
$weapp_model = new Weapp($order_info[ 'site_id' ]);
$is_trade_managed = $weapp_model->orderShippingIsTradeManaged()['data'];
if (!$is_trade_managed) return $weapp_model->success();
//商家信息
$shop_model = new ShopModel();
$shop_info = $shop_model->getShopInfo([ [ 'site_id', '=', $order_info[ 'site_id' ] ] ], '')[ 'data' ];
//物流模式和发货方式
$logistics_type_config = [
OrderDict::express => Weapp::LOGISTICS_TYPE_EXPRESS,
OrderDict::local => Weapp::LOGISTICS_TYPE_LOCAL,
OrderDict::store => Weapp::LOGISTICS_TYPE_STORE,
OrderDict::virtual => Weapp::LOGISTICS_TYPE_VIRTUAL,
];
$logistics_type = $logistics_type_config[$order_info['order_type']];
$delivery_mode = $order_info['order_type'] == OrderDict::express ? Weapp::SPLIT_DELIVERY : Weapp::UNIFIED_DELIVERY;
//小程序物流公司
$delivery_list = [];
if ($logistics_type == OrderDict::express) {
$delivery_list = $weapp_model->orderShippingGetDeliveryList()[ 'data' ];
}
//订单商品
$order_goods_field = 'order_goods_id,sku_name,num,delivery_no,delivery_status';
$order_goods_list = $order_model->getOrderGoodsList([
[ 'order_id', '=', $order_info[ 'order_id' ] ]
], $order_goods_field, 'order_goods_id asc')[ 'data' ];
$order_goods_list = array_column($order_goods_list, null, 'order_goods_id');
//寄件人联系方式
$consignor_contact = $this->mobileShow($shop_info[ 'mobile' ]);
//收件人联系方式
$receiver_contact = $this->mobileShow($order_info[ 'mobile' ]);
//组装小程序发货信息
$shipping_list = [];
$delivery_goods_count = 0;
$is_all_delivered = true;
if ($logistics_type == OrderDict::express) {
$package_list = model('express_delivery_package')->getList([
[ 'order_id', '=', $order_info[ 'order_id' ] ],
], '*');
foreach($package_list as $package_info){
//商品信息
$order_goods_ids = explode(',', $package_info['order_goods_id_array']);
$item_desc = [];
foreach($order_goods_ids as $order_goods_id){
$order_goods_info = $order_goods_list[$order_goods_id];
$item_desc_text = $order_goods_info['sku_name'].'*'.$order_goods_info['num'];
$item_desc[] = $item_desc_text;
$delivery_goods_count ++;
}
//物流公司
$express_company = '';
if (!empty($package_info[ 'express_company_name' ]) && !empty($delivery_list)) {
$delivery_index = array_search($package_info[ 'express_company_name' ], array_column($delivery_list, 'delivery_name'));
if ($delivery_index === false) continue;
$express_company = $delivery_list[ $delivery_index ][ 'delivery_id' ];
}
if(empty($express_company)) continue;
//数据结构
$item = [
'tracking_no' => $package_info[ 'delivery_no' ], // 物流单号,物流快递发货时必填,示例值: 323244567777 字符字节限制: [1, 128]
'express_company' => $express_company, // 物流公司编码快递公司ID参见「查询物流公司编码列表」物流快递发货时必填 示例值: DHL 字符字节限制: [1, 128]
'item_desc' => $weapp_model->handleOrderShippingItemDesc($item_desc), // 商品信息,例如:微信红包抱枕*1个限120个字以内
'contact' => [
'consignor_contact' => $consignor_contact,
'receiver_contact' => $receiver_contact,
]
];
//最多只能有9个包裹
if(count($shipping_list) < 9){
$shipping_list[] = $item;
}
}
if(empty($shipping_list)){
$logistics_type = Weapp::LOGISTICS_TYPE_LOCAL;
$delivery_mode = Weapp::UNIFIED_DELIVERY;
}
if($delivery_goods_count < count($order_goods_list)){
$is_all_delivered = false;
}
}
//统一发货的发货信息
if($delivery_mode == Weapp::UNIFIED_DELIVERY){
$item_desc = [];
foreach($order_goods_list as $order_goods_info){
$item_desc_text = $order_goods_info['sku_name'].'*'.$order_goods_info['num'];
$item_desc[] = $item_desc_text;
}
$shipping_list[] = [
'tracking_no' => '', // 物流单号,物流快递发货时必填,示例值: 323244567777 字符字节限制: [1, 128]
'express_company' => '', // 物流公司编码快递公司ID参见「查询物流公司编码列表」物流快递发货时必填 示例值: DHL 字符字节限制: [1, 128]
'item_desc' => $weapp_model->handleOrderShippingItemDesc($item_desc), // 商品信息,例如:微信红包抱枕*1个限120个字以内
'contact' => [
'consignor_contact' => $consignor_contact,
'receiver_contact' => $receiver_contact,
]
];
}
$param = [
'site_id' => $order_info['site_id'],
'out_trade_no' => $order_info['out_trade_no'],
'logistics_type' => $logistics_type,
'delivery_mode' => $delivery_mode,
'shipping_list' => $shipping_list,
'weapp_openid' => $order_info[ 'weapp_openid' ],
'is_all_delivered' => $is_all_delivered,
];
$res = $weapp_model->orderShippingUploadShippingInfo($param);
//如果是预售,尾款也需要同步发货信息
if($order_info['promotion_type'] == 'presale'){
$param['out_trade_no'] = $order_info['out_trade_no_2'];
$res = $weapp_model->orderShippingUploadShippingInfo($param);
}
Log::write('小程序发货结果' . json_encode($res, JSON_UNESCAPED_UNICODE));
//dd($param,$res);
return $res;
}catch(\Exception $e){
Log::write('小程序发货错误' . json_encode([
'file' => $e->getFile(),
'line' => $e->getLine(),
'message' => $e->getMessage(),
], JSON_UNESCAPED_UNICODE));
//dd($e->getFile(),$e->getLine(),$e->getMessage());
return error(-1, '小程序上传发货信息错误,'.$e->getMessage());
}
}
// 寄件人和收件人联系方式采用掩码传输最后4位数字不能打掩码 示例值: `189****1234, 021-****1234, ****1234, 0**2-***1234, 0**2-******23-10, ****123-8008` 值限制: 0 ≤ value ≤ 1024
protected function mobileShow($mobile)
{
if($mobile){
$mobile =substr($mobile, 0, 3) . '****' . substr($mobile, 7);
}
return $mobile;
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use addon\weapp\model\Weapp;
use addon\wechatpay\model\Config as WechatPayModel;
use think\facade\Log;
/**
* 订单收货,小程序确认收货提醒
*/
class OrderTakeDeliveryAfter
{
public function handle($data)
{
//通知应该是在用户实际收货后去提醒,正确的做法是通过物流信息获取到用户已收货,然后发出提醒。但是目前做不到这一点,只能是后台商家点击收货,系统自动收货和用户自己点击了收货后发出提醒。
try {
$weapp_model = new Weapp($data[ 'site_id' ]);
// 检测微信小程序是否已开通发货信息管理服务
$is_trade_managed = $weapp_model->orderShippingIsTradeManaged()['data'];
if (!$is_trade_managed) return $weapp_model->success();
$filed = 'o.order_id,o.site_id,o.order_type,o.out_trade_no,o.pay_type,o.mobile,m.weapp_openid';
$join = [
[ 'member m', 'o.member_id=m.member_id', 'left' ]
];
$order_info = model('order')->getInfo([ [ 'order_id', '=', $data[ 'order_id' ] ] ], $filed, 'o', $join);
if (empty($order_info)) {
return $weapp_model->error('', '订单不存在');
}
if ($order_info[ 'pay_type' ] != 'wechatpay') {
return $weapp_model->success('', '订单未使用微信支付');
}
if ($order_info[ 'order_type' ] != 1) {
return $weapp_model->success('', '只有物流订单才能进行提醒');
}
$param = [
'site_id' => $order_info['site_id'],
'out_trade_no' => $order_info['out_trade_no'],
];
$res = $weapp_model->orderShippingNotifyConfirmReceive($param);
//dd($param,$res);
return $res;
}catch(\Exception $e){
return error(-1, '小程序发送确认发货信息提醒错误,'.$e->getMessage());
}
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use addon\weapp\model\Weapp;
/**
* 开放数据解密
*/
class PhoneNumber
{
public function handle($param = [])
{
if ($param[ 'app_type' ] == 'weapp') {
$res = ( new Weapp($param[ 'site_id' ]) )->decryptData($param);
if ($res[ 'code' ] != 0) return $res;
return success(0, '', $res[ 'data' ][ 'purePhoneNumber' ]);
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use app\model\system\Cron;
/**
* 礼品卡订单支付后
*/
class PointExchangeOrderPay
{
public function handle($param)
{
//类型 1商品 2优惠券 3红包 商品类型要在真实发货后才同步发货消息
if($param['type'] != 1 && $param['exchange_price'] > 0){
return (new Cron())->addCron(1, 0, "小程序虚拟发货", "WeappVirtualDelivery", time() + 60, $param['out_trade_no']);
}
}
}

41
addon/weapp/event/Qrcode.php Executable file
View File

@@ -0,0 +1,41 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use addon\weapp\model\Weapp;
/**
* 二维码
*/
class Qrcode
{
/**
* 二维码生成获取
*/
public function handle($param)
{
if ($param[ "app_type" ] == 'weapp' || $param[ "app_type" ] == 'all') {
if ($param[ "app_type" ] == 'all') $param[ "app_type" ] = 'weapp';
$weapp = new Weapp($param[ 'site_id' ]);
if ($param[ "type" ] == 'create') {
$res = $weapp->createQrcode($param);
} else {
$filename = $param[ 'qrcode_path' ] . '/' . $param[ 'qrcode_name' ] . '_' . $param[ 'app_type' ] . '.png';
if (file_exists($filename)) {
$res = success(0, '', [ 'type' => 'weapp', 'path' => $filename ]);
} else {
$res = $weapp->createQrcode($param);
}
}
return $res;
}
}
}

25
addon/weapp/event/UnInstall.php Executable file
View File

@@ -0,0 +1,25 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
/**
* 应用卸载
*/
class UnInstall
{
/**
* 执行卸载
*/
public function handle()
{
return error("系统插件不能卸载");
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\event;
use addon\weapp\model\Weapp;
use app\model\member\Member;
use app\model\system\Pay as PayModel;
/**
* 小程序虚拟发货
* 支付后立即调用发货接口,微信会提示订单不存在,所以延迟一分钟执行,如果是
* {"errcode":10060001,"errmsg":"支付单不存在 rid: 66235dcf-4803e8cf-5c30a69e"}
*/
class WeappVirtualDelivery
{
public function handle($param)
{
return $this->delivery($param['relate_id']);
}
protected function delivery($out_trade_no)
{
//获取支付信息
$pay_model = new PayModel();
$pay_info = $pay_model->getPayInfo($out_trade_no)['data'];
if(empty($pay_info)) return success();
if ($pay_info[ 'pay_type' ] != 'wechatpay') return success();
// 检测微信小程序是否已开通发货信息管理服务
$weapp_model = new Weapp($pay_info[ 'site_id' ]);
$is_trade_managed = $weapp_model->orderShippingIsTradeManaged()['data'];
if (!$is_trade_managed) return $weapp_model->success();
//用户信息
$member_service = new Member();
$member_info = $member_service->getMemberInfo([
[ 'site_id', '=', $pay_info[ 'site_id' ] ],
[ 'member_id', '=', $pay_info[ 'member_id' ] ]
], 'weapp_openid')[ 'data' ];
if(empty($member_info)) return success();
//组装发货信息
$shipping_list = [
[
'tracking_no' => '', // 物流单号,物流快递发货时必填,示例值: 323244567777 字符字节限制: [1, 128]
'express_company' => '', // 物流公司编码快递公司ID参见「查询物流公司编码列表」物流快递发货时必填 示例值: DHL 字符字节限制: [1, 128]
'item_desc' => $weapp_model->handleOrderShippingItemDesc([$pay_info['pay_body']]), // 商品信息,例如:微信红包抱枕*1个限120个字以内
'contact' => [
'consignor_contact' => '',
'receiver_contact' => ''
]
]
];
$data = [
'site_id' => $pay_info[ 'site_id' ],
'out_trade_no' => $pay_info[ 'out_trade_no' ],
'logistics_type' => Weapp::LOGISTICS_TYPE_VIRTUAL, // 3、虚拟商品虚拟商品例如话费充值点卡等无实体配送形式
'delivery_mode' => Weapp::UNIFIED_DELIVERY, // 发货模式发货模式枚举值1、UNIFIED_DELIVERY统一发货
'shipping_list' => $shipping_list,
'weapp_openid' => $member_info[ 'weapp_openid' ], // 用户标识用户在小程序appid下的唯一标识。 下单前需获取到用户的Openid 示例值: oUpF8uMuAJO_M2pxb1Q9zNjWeS6o 字符字节限制: [1, 128]
'is_all_delivered' => true
];
return $weapp_model->orderShippingUploadShippingInfo($data);
}
}

BIN
addon/weapp/icon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

126
addon/weapp/model/Config.php Executable file
View File

@@ -0,0 +1,126 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\model;
use app\model\system\Config as ConfigModel;
use app\model\BaseModel;
use think\facade\Cache;
use app\model\upload\Upload;
/**
* 微信小程序配置
*/
class Config extends BaseModel
{
/******************************************************************** 微信小程序配置 start ****************************************************************************/
/**
* 设置微信小程序配置
* @return multitype:string mixed
*/
public function setWeappConfig($data, $is_use, $site_id = 0)
{
$config_info = $this->getWeappConfig($site_id);
if (!empty($config_info[ 'data' ][ 'value' ][ 'qrcode' ]) && !empty($data[ 'qrcode' ]) && $config_info[ 'data' ][ 'value' ][ 'qrcode' ] != $data[ 'qrcode' ]) {
$upload_model = new Upload();
$upload_model->deletePic($config_info[ 'data' ][ 'value' ][ 'qrcode' ], $site_id);
}
$config = new ConfigModel();
$res = $config->setConfig($data, '微信小程序设置', $is_use, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', 'shop' ], [ 'config_key', '=', 'WEAPP_CONFIG' ] ]);
if ($res && $data[ 'qrcode' ]) {
copy($data[ 'qrcode' ], 'public/static/img/default_img/wxewm.png');
}
return $res;
}
/**
* 获取微信小程序配置信息
* @param int $site_id
* @return array
*/
public function getWeappConfig($site_id = 0)
{
$config = new ConfigModel();
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', 'shop' ], [ 'config_key', '=', 'WEAPP_CONFIG' ] ]);
return $res;
}
/******************************************************************** 微信小程序配置 end ****************************************************************************/
/**
* 设置小程序版本信息
* @param $data
* @param $is_use
* @param int $site_id
* @return array
*/
public function setWeappVersion($data, $is_use, $site_id = 0)
{
$config = new ConfigModel();
$res = $config->setConfig($data, '小程序版本', $is_use, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', 'shop' ], [ 'config_key', '=', 'WEAPP_VERSION' ] ]);
return $res;
}
/**
* 获取小程序版本信息
* @param int $site_id
* @return array
*/
public function getWeappVersion($site_id = 0)
{
$config = new ConfigModel();
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', 'shop' ], [ 'config_key', '=', 'WEAPP_VERSION' ] ]);
return $res;
}
/**
* 清除小程序版本信息
*/
public function clearWeappVersion()
{
model('config')->update([ 'value' => '' ], [ [ 'app_module', '=', 'shop' ], [ 'config_key', '=', 'WEAPP_VERSION' ] ]);
Cache::tag('config')->clear();
}
/**
* 设置小程序分享
* @param $site_id
* @param $app_module
* @param $key
* @param $value
*/
public function setShareConfig($site_id, $app_module, $key, $value)
{
$config = model('config')->getInfo([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'WEAPP_SHARE' ] ], 'value');
if (!empty($config) && !empty($config[ 'value' ])) $data = json_decode($config[ 'value' ], true);
if (!empty($data[ $key ][ 'path' ]) && !empty($value[ 'path' ]) && $data[ $key ][ 'path' ] != $value[ 'path' ]) {
$upload_model = new Upload();
$upload_model->deletePic($data[ $key ][ 'path' ], $site_id);
}
$data[ $key ] = $value;
$model = new ConfigModel();
$res = $model->setConfig($data, '小程序分享', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'WEAPP_SHARE' ] ]);
return $res;
}
/**
* 获取小程序分享配置
* @param $site_id
* @param $app_module\
*/
public function getShareConfig($site_id, $app_module)
{
$config = new ConfigModel();
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'WEAPP_SHARE' ] ]);
return $res;
}
}

174
addon/weapp/model/Message.php Executable file
View File

@@ -0,0 +1,174 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\model;
use app\model\BaseModel;
/**
* 微信小程序订阅消息
*/
class Message extends BaseModel
{
/**
* 消息分页列表
* @param array $condition
* @param int $site_id
* @param int $page
* @param int $page_size
* @param string $order
* @return array
*/
public function getMessagePageList($condition = [], $site_id = 0, $page = 1, $page_size = PAGE_LIST_ROWS, $order = '')
{
$list = model('message_template')->pageList($condition, 'id,keywords,title,message_type,weapp_json', $order, $page, $page_size);
if ($site_id > 0) {
if (!empty($list[ 'list' ])) {
foreach ($list[ 'list' ] as $k => $v) {
$list[ 'list' ][ $k ]['message_info'] = json_decode($v['weapp_json'], true);
$message_info = model('message')->getInfo([ [ "keywords", "=", $v[ 'keywords' ] ], [ 'site_id', '=', $site_id ] ], 'weapp_is_open,weapp_template_id');
$list[ 'list' ][ $k ][ 'weapp_is_open' ] = $message_info == null ? 0 : $message_info[ 'weapp_is_open' ];
$list[ 'list' ][ $k ][ 'weapp_template_id' ] = $message_info == null ? 0 : $message_info[ 'weapp_template_id' ];
}
}
}
return $this->success($list);
}
/**
* 获取微信模板消息id
* @param string $keywords
* todo 批量获取模板消息
*/
public function getWeappTemplateNo(string $keywords, $site_id, $weapp_is_open = 0)
{
$keyword = explode(',', $keywords);
$wechat = new Weapp($site_id);
if ($weapp_is_open == 1) {
// 启用
foreach ($keyword as $item) {
$shop_message = model('message')->getInfo([ [ 'keywords', '=', $item ], [ "site_id", "=", $site_id ] ], 'weapp_template_id');
$data = [
'weapp_is_open' => $weapp_is_open,
'site_id' => $site_id,
'keywords' => $item,
];
// 开启时没有模板则进行添加
if (!empty($shop_message)) {
if (empty($shop_message[ 'weapp_template_id' ])) {
$template_info = model('message_template')->getInfo([ [ 'keywords', '=', $item ], [ 'weapp_json', '<>', '' ] ], 'weapp_json');
if (!empty($template_info)) {
$template = json_decode($template_info[ 'weapp_json' ], true);
$res = $wechat->getTemplateId($template);
if (isset($res[ 'errcode' ]) && $res[ 'errcode' ] == 0) {
$data[ 'weapp_template_id' ] = $res[ 'priTmplId' ];
} else {
return $this->error($res, $res[ 'errmsg' ]);
}
}
}
model('message')->update($data, [ [ 'keywords', '=', $item ], [ "site_id", "=", $site_id ] ]);
} else {
$template_info = model('message_template')->getInfo([ [ 'keywords', '=', $item ], [ 'weapp_json', '<>', '' ] ], 'weapp_json');
if (!empty($template_info)) {
$template = json_decode($template_info[ 'weapp_json' ], true);
$res = $wechat->getTemplateId($template);
if (isset($res[ 'errcode' ]) && $res[ 'errcode' ] == 0) {
$data[ 'weapp_template_id' ] = $res[ 'priTmplId' ];
} else {
return $this->error($res, $res[ 'errmsg' ]);
}
}
model('message')->add($data);
}
}
} else if ($weapp_is_open == 0) {
// 关闭
foreach ($keyword as $item) {
$shop_message = model('message')->getInfo([ [ 'keywords', '=', $item ], [ "site_id", "=", $site_id ] ], 'weapp_template_id');
if (!empty($shop_message)) {
model('message')->update([ 'weapp_is_open' => $weapp_is_open ], [ [ 'keywords', '=', $item ], [ "site_id", "=", $site_id ] ]);
} else {
model('message')->add([
'site_id' => $site_id,
'keywords' => $item,
'weapp_is_open' => $weapp_is_open
]);
}
}
} else {
// 获取
$list = model('message_template')->getList([ [ 'keywords', 'in', $keyword ], [ 'weapp_json', '<>', '' ] ], 'keywords,weapp_json');
if (!empty($list)) {
foreach ($list as $item) {
$template = json_decode($item[ 'weapp_json' ], true);
$res = $wechat->getTemplateId($template);
if (isset($res[ 'errcode' ]) && $res[ 'errcode' ] != 0) return $this->error($res, $res[ 'errmsg' ]);
$shop_message = model('message')->getInfo([ [ 'keywords', '=', $item[ 'keywords' ] ], [ "site_id", "=", $site_id ] ], 'weapp_template_id');
if (!empty($shop_message)) {
model('message')->update([ 'weapp_template_id' => $res[ 'priTmplId' ] ], [ [ 'keywords', '=', $item[ 'keywords' ] ], [ "site_id", "=", $site_id ] ]);
} else {
model('message')->add([
'site_id' => $site_id,
'keywords' => $item[ 'keywords' ],
'weapp_template_id' => $res[ 'priTmplId' ]
]);
}
}
}
}
return $this->success();
}
/**
* 发送订阅消息
* @param array $param
*/
public function sendMessage(array $param)
{
try {
$site_id = $param['site_id'] ?: 1;
$support_type = $param['message_info']["support_type"] ?? [];
if (empty($support_type) || strpos($support_type, "weapp") === false) return $this->success();
if (empty($param['openid'])) return $this->success('缺少必需参数openid');
$message_info = $param['message_info'];
if ($message_info['weapp_is_open'] == 0) return $this->error('未启用模板消息');
if (empty($message_info['weapp_template_id'])) return $this->error('未配置模板消息');
$data = [
'openid' => $param['openid'],
'template_id' => $message_info['weapp_template_id'],
'data' => $param['template_data'],
'page' => $param['page'] ?? ''
];
$weapp = new Weapp($site_id);
$res = $weapp->sendTemplateMessage($data);
return $res;
} catch (\Exception $e) {
return $this->error('', "消息发送失败");
}
}
/**
* 获取订阅消息模板id集合
* @param $site_id
* @param $keywords
*/
public function getMessageTmplIds($site_id, $keywords){
$data = model('message')->getColumn([ ['weapp_is_open', '=', 1], ['weapp_template_id', '<>', ''], ['site_id', '=', $site_id], ['keywords', 'in', explode(',', $keywords) ] ], 'weapp_template_id');
return $this->success($data);
}
}

199
addon/weapp/model/Stat.php Executable file
View File

@@ -0,0 +1,199 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\model;
use app\model\BaseModel;
use think\facade\Cache;
/**
* 微信小程序数据统计与分析
*/
class Stat extends BaseModel
{
/**
* 小程序 访问日趋势
* @param $from
* @param $to
*/
public function dailyVisitTrend($begin_date, $end_date)
{
$info = Cache::get("weapp_daily_visit_trend" . "_" . $begin_date . "_" . $end_date);
if (!empty($info)) {
return success($info);
}
$wepp_model = new Weapp();
$result = $wepp_model->dailyVisitTrend($begin_date, $end_date);
if ($result["code"] < 0)
return $result;
Cache::tag("weapp_visit")->set("weapp_daily_visit_trend" . "_" . $begin_date . "_" . $end_date, $result["data"]);
return $result;
}
/**
* 小程序 访问周趋势
* @param $from
* @param $to
*/
public function weeklyVisitTrend($begin_date, $end_date)
{
$info = Cache::get("weapp_weekly_visit_trend" . "_" . $begin_date . "_" . $end_date);
if (!empty($info)) {
return success($info);
}
$wepp_model = new Weapp();
$result = $wepp_model->weeklyVisitTrend($begin_date, $end_date);
if ($result["code"] < 0)
return $result;
Cache::tag("weapp_visit")->set("weapp_weekly_visit_trend" . "_" . $begin_date . "_" . $end_date, $result["data"]);
return $result;
}
/**
* 小程序 访问月趋势
* @param $from
* @param $to
*/
public function monthlyVisitTrend($begin_date, $end_date)
{
$info = Cache::get("weapp_monthly_visit_trend" . "_" . $begin_date . "_" . $end_date);
if (!empty($info)) {
return success($info);
}
$wepp_model = new Weapp();
$result = $wepp_model->monthlyVisitTrend($begin_date, $end_date);
if ($result["code"] < 0)
return $result;
Cache::tag("weapp_visit")->set("weapp_monthly_visit_trend" . "_" . $begin_date . "_" . $end_date, $result["data"]);
return $result;
}
/**
* 小程序 访问日趋势
* @param $from
* @param $to
*/
public function visitPage($begin_date, $end_date)
{
$info = Cache::get("weapp_visit_page" . "_" . $begin_date . "_" . $end_date);
if (!empty($info)) {
return success($info);
}
$wepp_model = new Weapp();
$result = $wepp_model->dailyVisitTrend($begin_date, $end_date);
if ($result["code"] < 0)
return $result;
Cache::tag("weapp_visit")->set("weapp_visit_page" . "_" . $begin_date . "_" . $end_date, $result["data"]);
return $result;
}
/**
* 查询微信小程序访问数据
* @param $date_type
* @param $daterange
*/
public function visitData($date_type)
{
$result = [];
switch ($date_type) {
case 'yesterday':
$begin_date = date('Ymd', strtotime('-1 days'));
$end_date = date('Ymd', strtotime('-1 days'));
$result = $this->dailyVisitTrend($begin_date, $end_date);
break;
case 'month':
$begin_date = date('Y-m-d', strtotime(date('Y-m-01') . ' -1 month'));
$end_date = date('Y-m-d', strtotime(date('Y-m-01') . ' -1 day'));
$result = $this->monthlyVisitTrend($begin_date, $end_date);
break;
}
return $result;
}
/**
* 获取微信小程序 数据分析统计
*/
public function visitStatistics($daterange)
{
if (empty($daterange))
return $this->success([]);
$is_error = true;
$daterange_array = explode("", $daterange);
$start_date = date_format(date_create($daterange_array[0]), "Ymd");
$end_date = date_format(date_create($daterange_array[1]), "Ymd");
$date_x = periodGroup(strtotime($start_date), strtotime($end_date));
$session_cnt_data = [];//打开次数
$visit_pv_data = [];//访问次数
$visit_uv_data = [];//访问人数
$visit_uv_new_data = [];//新用户数
$stay_time_uv_data = [];//人均停留时长 (浮点型,单位:秒)
$stay_time_session_data = [];//次均停留时长 (浮点型,单位:秒)
$visit_depth_data = [];//平均访问深度 (浮点型)
foreach ($date_x as $k => $v) {
$session_cnt = 0;//打开次数
$visit_pv = 0;//访问次数
$visit_uv = 0;//访问人数
$visit_uv_new = 0;//新用户数
$stay_time_uv = 0;//人均停留时长 (浮点型,单位:秒)
$stay_time_session = 0;//次均停留时长 (浮点型,单位:秒)
$visit_depth = 0;//平均访问深度 (浮点型)
if ($is_error) {
// $temp_daterange = array(
// "begin_date" => $v,
// "end_date" => $v,
// "site_id" => $site_id
// );
$result = $this->dailyVisitTrend($v, $v);
$temp_data = $result["data"];
if (!empty($temp_data)) {
$session_cnt = $temp_data["session_cnt"];//打开次数
$visit_pv = $temp_data["visit_pv"];//访问次数
$visit_uv = $temp_data["visit_uv"];//访问人数
$visit_uv_new = $temp_data["visit_uv_new"];//新用户数
$stay_time_uv = $temp_data["stay_time_uv"];//人均停留时长 (浮点型,单位:秒)
$stay_time_session = $temp_data["stay_time_session"];//次均停留时长 (浮点型,单位:秒)
$visit_depth = $temp_data["visit_depth"];//平均访问深度 (浮点型)
} else {
$is_error = false;
}
}
$session_cnt_data[] = $session_cnt;//打开次数
$visit_pv_data[] = $visit_pv;//访问次数
$visit_uv_data[] = $visit_uv;//访问人数
$visit_uv_new_data[] = $visit_uv_new;//新用户数
$stay_time_uv_data[] = $stay_time_uv;//人均停留时长 (浮点型,单位:秒)
$stay_time_session_data[] = $stay_time_session;//次均停留时长 (浮点型,单位:秒)
$visit_depth_data[] = $visit_depth;//平均访问深度 (浮点型)
}
$statistics_data = array(
"date" => $date_x,
"data" => array(
"session_cnt_data" => $session_cnt_data,
"visit_pv_data" => $visit_pv_data,
"visit_uv_data" => $visit_uv_data,
"visit_uv_new_data" => $visit_uv_new_data,
"stay_time_uv_data" => $stay_time_uv_data,
"stay_time_session_data" => $stay_time_session_data,
"visit_depth_data" => $visit_depth_data,
)
);
return $this->success($statistics_data);
}
}

873
addon/weapp/model/Weapp.php Executable file
View File

@@ -0,0 +1,873 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\model;
use addon\wechatpay\model\Config as WechatPayModel;
use app\model\BaseModel;
use app\model\order\Order;
use app\model\shop\Shop as ShopModel;
use app\model\system\Api;
use app\model\system\Config as ConfigModel;
use EasyWeChat\Factory;
use think\facade\Cache;
use addon\weapp\model\Config as WeappConfigModel;
use addon\wxoplatform\model\Config as WxOplatformConfigModel;
use app\model\web\Config as WebConfig;
use think\facade\Log;
/**
* 微信小程序配置
*/
class Weapp extends BaseModel
{
private $app;//微信模型
//小程序类型
public $service_type = array (
0 => "小程序",
);
//小程序认证类型
public $verify_type = array (
-1 => "未认证",
0 => "微信认证",
);
//business_info 说明
public $business_type = array (
'open_store' => "是否开通微信门店功能",
'open_scan' => "是否开通微信扫商品功能",
'open_pay' => "是否开通微信支付功能",
'open_card' => "是否开通微信卡券功能",
'open_shake' => "是否开通微信摇一摇功能",
);
// 站点ID
private $site_id;
public function __construct($site_id = 0)
{
$this->site_id = $site_id;
//微信小程序配置
$weapp_config_model = new WeappConfigModel();
$weapp_config = $weapp_config_model->getWeappConfig($site_id)[ "data" ][ "value" ];
if (isset($weapp_config[ 'is_authopen' ]) && addon_is_exit('wxoplatform')) {
$plateform_config_model = new WxOplatformConfigModel();
$plateform_config = $plateform_config_model->getOplatformConfig()[ "data" ][ "value" ];
$config = [
'app_id' => $plateform_config[ "appid" ] ?? '',
'secret' => $plateform_config[ "secret" ] ?? '',
'token' => $plateform_config[ "token" ] ?? '',
'aes_key' => $plateform_config[ "aes_key" ] ?? '',
'log' => [
'level' => 'debug',
'permission' => 0777,
'file' => 'runtime/log/wechat/oplatform.logs',
],
];
$open_platform = Factory::openPlatform($config);
$this->app = $open_platform->miniProgram($weapp_config[ 'authorizer_appid' ], $weapp_config[ 'authorizer_refresh_token' ]);
} else {
$config = [
'app_id' => $weapp_config[ "appid" ] ?? '',
'secret' => $weapp_config[ "appsecret" ] ?? '',
'response_type' => 'array',
'log' => [
'level' => 'debug',
'permission' => 0777,
'file' => 'runtime/log/wechat/easywechat.logs',
],
];
if(!empty($weapp_config[ "appid" ]) && !empty($weapp_config[ "appsecret" ])){
$this->app = Factory::miniProgram($config);
}
}
}
/**
* TODO
* 根据 jsCode 获取用户 session 信息
* @param $param
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
*/
public function authCodeToOpenid($param)
{
try {
$result = $this->app->auth->session($param[ 'code' ]);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->handleError($result[ 'errcode' ], $result[ 'errmsg' ]);
} else {
Cache::set('weapp_' . $result[ 'openid' ], $result);
unset($result[ 'session_key' ]);
return $this->success($result);
}
} catch (\Exception $e) {
if (property_exists($e, 'formattedResponse')) {
return $this->handleError($e->formattedResponse[ 'errcode' ], $e->formattedResponse[ 'errmsg' ]);
}
return $this->error('', $e->getMessage());
}
}
/**
* 生成二维码
* @param unknown $param
*/
public function createQrcode($param)
{
try {
$checkpath_result = $this->checkPath($param[ 'qrcode_path' ]);
if ($checkpath_result[ "code" ] != 0) return $checkpath_result;
// scene:场景值最大32个可见字符只支持数字大小写英文以及部分特殊字符!#$&'()*+,/:;=?@-._~
$scene = '';
if (!empty($param[ 'data' ])) {
foreach ($param[ 'data' ] as $key => $value) {
//防止参数过长source_member用m代替
if ($key == 'source_member') {
$key = 'm';
}
if ($scene == '') $scene .= $key . '-' . $value;
else $scene .= '&' . $key . '-' . $value;
}
}
$response = $this->app->app_code->getUnlimit($scene, [
'page' => substr($param[ 'page' ], 1),
'width' => $param['width'] ?? 120
]);
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$filename = $param[ 'qrcode_path' ] . '/';
$filename .= $response->saveAs($param[ 'qrcode_path' ], $param[ 'qrcode_name' ] . '_' . $param[ 'app_type' ] . '.png');
return $this->success([ 'type' => 'weapp', 'path' => $filename ]);
} else {
return $this->handleError($response[ 'errcode' ], $response[ 'errmsg' ]);
}
} catch (\Exception $e) {
if (property_exists($e, 'formattedResponse')) {
return $this->handleError($e->formattedResponse[ 'errcode' ], $e->formattedResponse[ 'errmsg' ]);
}
return $this->error('', $e->getMessage());
}
}
/**
* 校验目录是否可写
* @param unknown $path
* @return multitype:number unknown |multitype:unknown
*/
private function checkPath($path)
{
if (is_dir($path) || mkdir($path, intval('0755', 8), true)) {
return $this->success();
}
return $this->error('', "directory {$path} creation failed");
}
/************************************************************* 数据统计与分析 start **************************************************************/
/**
* 访问日趋势
* @param $from 格式 20170313
* @param $to 格式 20170313
*/
public function dailyVisitTrend($from, $to)
{
try {
$result = $this->app->data_cube->dailyVisitTrend($from, $to);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error([], $result[ "errmsg" ]);
}
return $this->success($result[ "list" ]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 访问周趋势
* @param $from
* @param $to
* @return array
*/
public function weeklyVisitTrend($from, $to)
{
try {
$result = $this->app->data_cube->weeklyVisitTrend($from, $to);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error([], $result[ "errmsg" ]);
}
return $this->success($result[ "list" ]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 访问月趋势
* @param $from
* @param $to
* @return array
*/
public function monthlyVisitTrend($from, $to)
{
try {
$result = $this->app->data_cube->monthlyVisitTrend($from, $to);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error([], $result[ "errmsg" ]);
}
return $this->success($result[ "list" ]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 访问分布
* @param $from
* @param $to
* @return array
*/
public function visitDistribution($from, $to)
{
try {
$result = $this->app->data_cube->visitDistribution($from, $to);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error($result, $result[ "errmsg" ]);
}
return $this->success($result[ "list" ]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 访问页面
* @param $from
* @param $to
* @return array
*/
public function visitPage($from, $to)
{
try {
$result = $this->app->data_cube->visitPage($from, $to);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error([], $result[ "errmsg" ]);
}
return $this->success($result[ "list" ]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/************************************************************* 数据统计与分析 end **************************************************************/
/**
* 下载小程序代码包
* @param $site_id
*/
public function download($site_id)
{
$source_file_path = $this->createTempPackage($site_id, 'public/weapp');
$file_arr = getFileMap($source_file_path);
if (!empty($file_arr)) {
$zipname = 'upload/weapp_' . $site_id . '_' . date('Ymd') . '.zip';
$zip = new \ZipArchive();
$res = $zip->open($zipname, \ZipArchive::CREATE);
if ($res === TRUE) {
foreach ($file_arr as $file_path => $file_name) {
if (is_dir($file_path)) {
$file_path = str_replace($source_file_path . '/', '', $file_path);
$zip->addEmptyDir($file_path);
} else {
$zip_path = str_replace($source_file_path . '/', '', $file_path);
$zip->addFile($file_path, $zip_path);
}
}
$zip->close();
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: Binary");
header("Content-Length: " . filesize($zipname));
header("Content-Disposition: attachment; filename=\"" . basename($zipname) . "\"");
readfile($zipname);
@unlink($zipname);
deleteDir($source_file_path);
}
}
}
/**
* 创建临时包
* @param $site_id
* @param $package_path
* @param string $to_path
* @return string
*/
private function createTempPackage($site_id, $package_path, $to_path = '')
{
if (is_dir($package_path)) {
$package = scandir($package_path);
if (empty($to_path)) {
$to_path = 'upload/temp/' . $site_id . '/';
dir_mkdir($to_path);
}
foreach ($package as $path) {
$temp_path = $package_path . '/' . $path;
if (is_dir($temp_path)) {
if ($path == '.' || $path == '..') {//判断是否为系统隐藏的文件.和.. 如果是则跳过否则就继续往下走,防止无限循环再这里。
continue;
}
dir_mkdir($to_path . $path);
$this->createTempPackage($site_id, $temp_path, $to_path . $path . '/');
} else {
if (file_exists($temp_path)) {
copy($temp_path, $to_path . $path);
if (stristr($temp_path, 'common/vendor.js')) {
$content = file_get_contents($to_path . $path);
$content = $this->paramReplace($site_id, $content);
file_put_contents($to_path . $path, $content);
}
}
}
}
return $to_path;
}
}
/**
* 参数替换
* @param $site_id
* @param $string
* @return null|string|string[]
*/
private function paramReplace($site_id, $string)
{
$api_model = new Api();
$api_config = $api_model->getApiConfig()[ 'data' ];
$web_config_model = new WebConfig();
$web_config = $web_config_model->getMapConfig()[ 'data' ][ 'value' ];
$socket_url = ( strstr(ROOT_URL, 'https://') === false ? str_replace('http', 'ws', ROOT_URL) : str_replace('https', 'wss', ROOT_URL) ) . '/wss';
$patterns = [
'/\{\{\$baseUrl\}\}/',
'/\{\{\$imgDomain\}\}/',
'/\{\{\$h5Domain\}\}/',
'/\{\{\$mpKey\}\}/',
'/\{\{\$apiSecurity\}\}/',
'/\{\{\$publicKey\}\}/',
'/\{\{\$webSocket\}\}/'
];
$replacements = [
ROOT_URL,
ROOT_URL,
ROOT_URL . '/h5',
$web_config[ 'tencent_map_key' ] ?? '',
$api_config[ 'is_use' ] ?? 0,
$api_config[ 'value' ][ 'public_key' ] ?? '',
$socket_url
];
$string = preg_replace($patterns, $replacements, $string);
return $string;
}
/**
* 消息解密
* @param array $param
*/
public function decryptData($param = [])
{
try {
$cache = Cache::get('weapp_' . $param[ 'weapp_openid' ]);
$session_key = $cache[ 'session_key' ] ?? '';
$result = $this->app->encryptor->decryptData($session_key, $param[ 'iv' ], $param[ 'encryptedData' ]);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->handleError($result[ 'errcode' ], $result[ 'errmsg' ]);
}
return $this->success($result);
} catch (\Exception $e) {
if (property_exists($e, 'formattedResponse')) {
return $this->handleError($e->formattedResponse[ 'errcode' ], $e->formattedResponse[ 'errmsg' ]);
}
return $this->error([], $e->getMessage());
}
}
/**
* 获取用户手机号
* @param $code
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function getUserPhoneNumber($code)
{
try {
$result = $this->app->auth->phoneNumber($code);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->handleError($result[ 'errcode' ], $result[ 'errmsg' ]);
}
return $this->success($result[ 'phone_info' ]);
} catch (\Exception $e) {
if (property_exists($e, 'formattedResponse')) {
return $this->handleError($e->formattedResponse[ 'errcode' ], $e->formattedResponse[ 'errmsg' ]);
}
return $this->error([], $e->getMessage());
}
}
/**
* 获取订阅消息template_id
* @param array $param
*/
public function getTemplateId(array $param)
{
try {
$result = $this->app->subscribe_message->addTemplate($param[ 'tid' ], $param[ 'kidList' ], $param[ 'sceneDesc' ]);
return $result;
} catch (\Exception $e) {
return [ 'errcode' => -1, 'errmsg' => $e->getMessage() ];
}
}
/**
* 发送订阅消息
* @param array $param
* @return array
*/
public function sendTemplateMessage(array $param)
{
$result = $this->app->subscribe_message->send([
'template_id' => $param[ 'template_id' ],// 模板id
'touser' => $param[ 'openid' ], // openid
'page' => $param[ 'page' ], // 点击模板卡片后的跳转页面 支持带参数
'data' => $param[ 'data' ] // 模板变量
]);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error($result, $result[ "errmsg" ]);
}
return $this->success($result);
}
/**
* 消息推送
*/
public function relateWeixin()
{
$server = $this->app->server;
$message = $server->getMessage();
Log::write('微信小程序消息推送:' . json_encode($message));
if (isset($message[ 'MsgType' ])) {
switch ( $message[ 'MsgType' ] ) {
case 'event':
$this->app->server->push(function($res) {
// 商品审核结果通知
if ($res[ 'Event' ] == 'open_product_spu_audit' && addon_is_exit('shopcomponent', $this->site_id)) {
model('shopcompoent_goods')->update([
'edit_status' => $res[ 'OpenProductSpuAudit' ][ 'status' ],
'reject_reason' => !empty($res[ 'OpenProductSpuAudit' ][ 'reject_reason' ]) ? : '',
'audit_time' => time()
], [
[ 'out_product_id', '=', $res[ 'OpenProductSpuAudit' ][ 'out_product_id' ] ]
]);
}
// 类目审核结果通知
if ($res[ 'Event' ] == 'open_product_category_audit' && addon_is_exit('shopcomponent', $this->site_id)) {
model('shopcompoent_category_audit')->update([
'status' => $res[ 'QualificationAuditResult' ][ 'status' ],
'reject_reason' => !empty($res[ 'QualificationAuditResult' ][ 'reject_reason' ]) ? : '',
'audit_time' => time()
], [
[ 'audit_id', '=', $res[ 'QualificationAuditResult' ][ 'audit_id' ] ]
]);
}
// 视频号支付订单回调
if ($res[ 'Event' ] == 'open_product_order_pay' && addon_is_exit('shopcomponent', $this->site_id)) {
event("shopcomponentNotify", $res);
}
// todo trade_manage_remind_access_api 提醒接入发货信息管理服务API
if ($res[ 'Event' ] == 'trade_manage_remind_access_api' && addon_is_exit('weapp', $this->site_id)) {
Log::write('提醒接入发货信息管理服务APItrade_manage_remind_access_api' . json_encode($res));
}
// todo trade_manage_remind_shipping 提醒需要上传发货信息
if ($res[ 'Event' ] == 'trade_manage_remind_shipping' && addon_is_exit('weapp', $this->site_id)) {
Log::write('提醒需要上传发货信息trade_manage_remind_shipping' . json_encode($res));
}
// todo trade_manage_order_settlement 订单将要结算或已经结算
if ($res[ 'Event' ] == 'trade_manage_order_settlement' && addon_is_exit('weapp', $this->site_id)) {
Log::write('订单将要结算或已经结算trade_manage_order_settlement' . json_encode($res));
}
});
break;
}
}
$response = $this->app->server->serve();
return $response->send();
}
/**
* 检查场景值是否在支付校验范围内
* @param $scene
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function sceneCheck($scene)
{
try {
$result = $this->app->mini_store->checkScene($scene);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] == 0) {
return $this->success($result[ 'is_matched' ]);
} else {
return $this->error('', $result[ 'errmsg' ]);
}
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
public function createOrder($order_info)
{
try {
$result = $this->app->mini_store->addOrder($order_info);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] == 0) {
return $this->success($result[ 'is_matched' ]);
} else {
return $this->error('', $result[ 'errmsg' ]);
}
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 处理错误信息
* @param $errcode
* @param string $message
* @return array
*/
public function handleError($errcode, $message = '')
{
$error = require 'addon/weapp/config/weapp_error.php';
return $this->error([], $error[ $errcode ] ?? $message);
}
//物流模式,发货方式枚举值
//1、实体物流配送采用快递公司进行实体物流配送形式
//2、同城配送
//3、虚拟商品虚拟商品例如话费充值点卡等无实体配送形式
//4、用户自提
const LOGISTICS_TYPE_EXPRESS = 1;
const LOGISTICS_TYPE_LOCAL = 2;
const LOGISTICS_TYPE_VIRTUAL = 3;
const LOGISTICS_TYPE_STORE = 4;
//发货模式发货模式枚举值1、UNIFIED_DELIVERY统一发货2、SPLIT_DELIVERY分拆发货
const UNIFIED_DELIVERY = 1;
const SPLIT_DELIVERY = 2;
/**
* 查询小程序是否已开通发货信息管理服务
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function orderShippingIsTradeManaged()
{
try {
$result = $this->app->order_shipping->isTradeManaged();
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error(false, $result[ "errmsg" ]);
}
return $this->success($result[ 'is_trade_managed' ]);
} catch (\Exception $e) {
return $this->error(false, $e->getMessage());
}
}
/**
* 查询订单列表
* @param array $data
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function orderShippingGetOrderList($data = [])
{
try {
$params = [
'pay_time_range' => [
'begin_time' => $data[ 'begin_time' ] ?? 0, // 起始时间时间戳形式不填则视为从0开始。
'end_time' => $data[ 'end_time' ] ?? time() // 结束时间时间戳形式不填则视为32位无符号整型的最大值。
],
'page_size' => $data[ 'page_size' ] ?? 100 // 翻页时使用返回列表的长度默认为100。
];
// 订单状态枚举:(1) 待发货;(2) 已发货;(3) 确认收货;(4) 交易完成;(5) 已退款。
if (!empty($data[ 'order_state' ])) {
$params[ 'order_state' ] = $data[ 'order_state' ];
}
// 翻页时使用,获取第一页时不用传入,如果查询结果中 has_more 字段为 true则传入该次查询结果中返回的 last_index 字段可获取下一页。
if (!empty($data[ 'last_index' ])) {
$params[ 'last_index' ] = $data[ 'last_index' ];
}
$result = $this->app->order_shipping->getOrderList($params);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error([], $result[ "errmsg" ]);
}
return $this->success($result);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 查询订单发货状态
* @param array $data
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function orderShippingGetOrder($data = [])
{
try {
$params = [];
// 原支付交易对应的微信订单号
if (!empty($data[ 'transaction_id' ])) {
$params[ 'transaction_id' ] = $data[ 'transaction_id' ];
}
// 支付下单商户的商户号,由微信支付生成并下发
if (!empty($data[ 'merchant_id' ])) {
$params[ 'merchant_id' ] = $data[ 'merchant_id' ];
}
// 商户系统内部订单号,只能是数字、大小写字母`_-*`且在同一个商户号下唯一
if (!empty($data[ 'merchant_trade_no' ])) {
$params[ 'merchant_trade_no' ] = $data[ 'merchant_trade_no' ];
}
// 二级商户号
if (!empty($data[ 'sub_merchant_id' ])) {
$params[ 'sub_merchant_id' ] = $data[ 'sub_merchant_id' ];
}
$result = $this->app->order_shipping->getOrder($params);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error([], $result[ "errmsg" ]);
}
return $this->success($result[ 'order' ]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 设置消息跳转路径
* @return array
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function setMsgJumpPath()
{
$config = new ConfigModel();
$config_condition = [['site_id','=',0],['app_module','=','shop'],['config_key','=','WEAPP_ORDER_SHIPPINT_CONFIG']];
$res = $config->getConfig($config_condition);
$config_data = $res['data']['value'];
$jump_path = 'pages_tool/weapp/order_shipping';
if(empty($config_data['jump_path']) || $config_data['jump_path'] != $jump_path){
$result = $this->app->order_shipping->setMsgJumpPath($jump_path);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error($result, 'setMsgJumpPathError:'.$result[ "errmsg" ]);
}
$config_data['jump_path'] = $jump_path;
$config->setConfig($config_data, '小程序发货配置', 1, $config_condition);
}
return $this->success();
}
/**
* 发货信息录入接口,自备数据
* @param array $data
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function orderShippingUploadShippingInfo($data = [])
{
try {
//设置消息跳转路径
$result = $this->setMsgJumpPath();
if($result['code'] < 0) return $result;
$pay_config = ( new WechatPayModel() )->getPayConfig($data[ 'site_id' ])[ 'data' ][ 'value' ];
$params = [
'order_key' => [
'order_number_type' => 1, // 订单单号类型用于确认需要上传详情的订单。枚举值1使用下单商户号和商户侧单号枚举值2使用微信支付单号。
'mchid' => $pay_config[ 'mch_id' ], // 支付下单商户的商户号,由微信支付生成并下发。
'out_trade_no' => $data[ 'out_trade_no' ] // 商户系统内部订单号,只能是数字、大小写字母`_-*`且在同一个商户号下唯一
],
'logistics_type' => $data[ 'logistics_type' ], // 物流模式发货方式枚举值1、实体物流配送采用快递公司进行实体物流配送形式 2、同城配送 3、虚拟商品虚拟商品例如话费充值点卡等无实体配送形式 4、用户自提
'delivery_mode' => $data[ 'delivery_mode' ], // 发货模式发货模式枚举值1、UNIFIED_DELIVERY统一发货2、SPLIT_DELIVERY分拆发货 示例值: UNIFIED_DELIVERY
// 同城配送没有物流信息,只能传一个订单
'shipping_list' => $data[ 'shipping_list' ], // 物流信息列表,发货物流单列表,支持统一发货(单个物流单)和分拆发货(多个物流单)两种模式,多重性: [1, 10]
'upload_time' => date("c", time()), // 上传时间,用于标识请求的先后顺序 示例值: `2022-12-15T13:29:35.120+08:00`
'payer' => [
'openid' => $data[ 'weapp_openid' ] // 用户标识用户在小程序appid下的唯一标识。 下单前需获取到用户的Openid 示例值: oUpF8uMuAJO_M2pxb1Q9zNjWeS6o 字符字节限制: [1, 128]
],
'is_all_delivered' => $data[ 'is_all_delivered' ] // 分拆发货模式时必填,用于标识分拆发货模式下是否已全部发货完成,只有全部发货完成的情况下才会向用户推送发货完成通知。示例值: true/false
];
Log::write('发货信息录入接口,自备数据(参数):' . json_encode($params, JSON_UNESCAPED_UNICODE));
$result = $this->app->order_shipping->uploadShippingInfo($params);
Log::write('发货信息录入接口,自备数据(结果):' . json_encode($result, JSON_UNESCAPED_UNICODE));
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error($result, 'uploadShippingInfoError:'.$result[ "errmsg" ]);
}
return $this->success($result);
} catch (\Exception $e) {
return $this->error([], $e->getMessage() . ",File" . $e->getFile() . "line" . $e->getLine());
}
}
/**
* todo【暂时没有用到】发货信息合单录入接口
* @param array $data
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function orderShippingUploadCombinedShippingInfo($data = [])
{
try {
$params = [
'order_key' => [
'order_number_type' => $data[ 'order_number_type' ] ?? 1, // 订单单号类型用于确认需要上传详情的订单。枚举值1使用下单商户号和商户侧单号枚举值2使用微信支付单号。
],
'logistics_type' => $data[ 'logistics_type' ], // 物流模式发货方式枚举值1、实体物流配送采用快递公司进行实体物流配送形式 2、同城配送 3、虚拟商品虚拟商品例如话费充值点卡等无实体配送形式 4、用户自提
'delivery_mode' => $data[ 'delivery_mode' ], // 发货模式发货模式枚举值1、UNIFIED_DELIVERY统一发货2、SPLIT_DELIVERY分拆发货 示例值: UNIFIED_DELIVERY
'sub_orders' => $data[ 'sub_orders' ], // 子单物流详情
'upload_time' => $data[ 'upload_time' ], // 上传时间,用于标识请求的先后顺序 示例值: `2022-12-15T13:29:35.120+08:00`
'payer' => [
'openid' => $data[ 'openid' ] // 用户标识用户在小程序appid下的唯一标识。 下单前需获取到用户的Openid 示例值: oUpF8uMuAJO_M2pxb1Q9zNjWeS6o 字符字节限制: [1, 128]
]
];
// 原支付交易对应的微信订单号
if (!empty($data[ 'transaction_id' ])) {
$params[ 'order_key' ][ 'transaction_id' ] = $data[ 'transaction_id' ];
}
// 支付下单商户的商户号,由微信支付生成并下发。
if (!empty($data[ 'mchid' ])) {
$params[ 'order_key' ][ 'mchid' ] = $data[ 'mchid' ];
}
// 商户系统内部订单号,只能是数字、大小写字母`_-*`且在同一个商户号下唯一
if (!empty($data[ 'out_trade_no' ])) {
$params[ 'order_key' ][ 'out_trade_no' ] = $data[ 'out_trade_no' ];
}
$result = $this->app->order_shipping->uploadCombinedShippingInfo($params);
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error([], $result[ "errmsg" ]);
}
return $this->success($result);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 确认收货提醒接口
* @param array $data
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function orderShippingNotifyConfirmReceive($data = [])
{
try {
$pay_config = ( new WechatPayModel() )->getPayConfig($data[ 'site_id' ])[ 'data' ][ 'value' ];
$params = [
'merchant_id' => $pay_config[ 'mch_id' ], // 支付下单商户的商户号,由微信支付生成并下发
'merchant_trade_no' => $data[ 'out_trade_no' ], // 商户系统内部订单号只能是数字、大小写字母_-*且在同一个商户号下唯一
'received_time' => time() // 快递签收时间,时间戳形式
];
Log::write('确认收货提醒接口(参数):' . json_encode($params));
$result = $this->app->order_shipping->notifyConfirmReceive($params);
Log::write('确认收货提醒接口(结果):' . json_encode($result));
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
Log::write('微信小程序确认收货提醒接口报错:' . json_encode($result));
return $this->success([], $result[ "errmsg" ]);
}
return $this->success($result);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 获取物流公司运力id列表get_delivery_list
* @param array $data
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function orderShippingGetDeliveryList()
{
$cache = Cache::get('orderShippingGetDeliveryList');
if ($cache) return $cache;
try {
$result = $this->app->order_shipping->getDeliveryList();
if (isset($result[ 'errcode' ]) && $result[ 'errcode' ] != 0) {
return $this->error([], $result[ "errmsg" ]);
}
$data = $this->success($result[ 'delivery_list' ]);
Cache::set('orderShippingGetDeliveryList', $data);
return $data;
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 处理订单发货物品说明
* @param $item_desc
* @return string
*/
public function handleOrderShippingItemDesc($item_desc)
{
$max_len = 90;
$item_desc = join(';',$item_desc);
$is_out_len = mb_strlen($item_desc) > $max_len;
$item_desc = mb_substr($item_desc, 0, $max_len, 'UTF-8');
if($is_out_len){
$item_desc .= '...';
}
return $item_desc;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\shop\controller;
use app\shop\controller\BaseShop;
use addon\weapp\model\Message as MessageModel;
use app\model\message\Message as MessageSyetem;
/**
* 微信小程序订阅消息
*/
class Message extends BaseShop
{
/**
* 模板消息设置
* @return array|mixed|\multitype
*/
public function config()
{
$message_model = new MessageModel();
if (request()->isJson()) {
$page = input('page', 1);
$page_size = input('page_size', PAGE_LIST_ROWS);
$condition = array (
[ "support_type", "like", '%weapp%' ],
);
$list = $message_model->getMessagePageList($condition, $this->site_id, $page, $page_size);
return $list;
} else {
return $this->fetch('message/config');
}
}
/**
* 微信模板消息状态设置
*/
public function setWeappStatus()
{
$message_model = new MessageModel();
if (request()->isJson()) {
$keywords = input("keywords", "");
$weapp_is_open = input('weapp_is_open', 0);
$res = $message_model->getWeappTemplateNo($keywords, $this->site_id, $weapp_is_open);
return $res;
}
}
/**
* 获取模板编号
*/
public function getWeappTemplateNo()
{
if (request()->isJson()) {
$keywords = input("keywords", "");
$message_model = new MessageModel();
$res = $message_model->getWeappTemplateNo($keywords, $this->site_id, -1);
return $res;
}
}
/**
* 编辑模板消息
* @return array|mixed|string
*/
public function edit()
{
$message_model = new MessageSyetem();
$keywords = input("keywords", "");
$info_result = $message_model->getMessageInfo($this->site_id, $keywords);
$info = $info_result[ "data" ];
$weapp_json_array = $info[ "weapp_json_array" ];
if (request()->isJson()) {
if (empty($info))
return error("", "不存在的模板信息!");
$weapp_is_open = input('weapp_is_open', 0);
$res = $message_model->editMessage([ 'weapp_is_open' => $weapp_is_open, 'site_id' => $this->site_id, 'keywords' => $keywords ], [
[ "keywords", "=", $keywords ],
[ 'site_id', '=', $this->site_id ],
]);
return $res;
} else {
if (empty($info)) $this->error("不存在的模板信息!");
$this->assign("keywords", $keywords);
$this->assign("info", $weapp_json_array);
$this->assign('weapp_is_open', $info[ 'weapp_is_open' ]);
$this->assign('message_title', $info[ 'title' ]);
return $this->fetch('message/edit');
}
}
}

View File

@@ -0,0 +1,104 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\shop\controller;
use addon\weapp\model\Stat as StatModel;
use app\shop\controller\BaseShop;
use think\App;
/**
* 微信小程序访问统计
*/
class Stat extends BaseShop
{
public function __construct(App $app = null)
{
$this->replace = [
'WEAPP_CSS' => __ROOT__ . '/addon/weapp/shop/view/public/css',
'WEAPP_JS' => __ROOT__ . '/addon/weapp/shop/view/public/js',
'WEAPP_IMG' => __ROOT__ . '/addon/weapp/shop/view/public/img',
'WEAPP_SVG' => __ROOT__ . '/addon/weapp/shop/view/public/svg',
];
parent::__construct($app);
}
public function stat()
{
return $this->fetch('stat/stat');
}
/**
* 统计昨日的数据
*/
public function visitData()
{
if (request()->isJson()) {
$date_type = input("date_type", "month");
$stat_model = new StatModel();
$result = $stat_model->visitData($date_type);
return $result;
}
}
/**
* 获取微信小程序 数据分析统计
*/
public function visitStatistics()
{
$stat_model = new StatModel();
$daterange = input("daterange", "");
$result = $stat_model->visitStatistics($daterange);
return $result;
}
/**
* 得到时间间隔
* @param $date_type
* @param string $daterange
* @return array
*/
public function getDaterange($date_type, $daterange = "")
{
$today_date = date('Ymd');//当前日日期
$begin_date = "";
$end_date = "";
switch ($date_type) {
case 'today':
$begin_date = $today_date;
$end_date = $today_date;
break;
case 'yesterday':
$begin_date = date('Ymd', strtotime('-1 days'));
$end_date = date('Ymd', strtotime('-1 days'));
break;
case 'week':
$begin_date = date('Ymd', strtotime('-6 days'));
$end_date = $today_date;
break;
case 'month':
$begin_date = date('Ymd', strtotime('-29 days'));
$end_date = $today_date;
break;
case 'daterange':
if (!empty($daterange)) {
$daterange_array = explode(" - ", $daterange);
$begin_date = date_format(date_create($daterange_array[0]), "Ymd");
$end_date = date_format(date_create($daterange_array[1]), "Ymd");
}
$begin_date = date('Ymd', strtotime($begin_date));//开始日期
$end_date = date('Ymd', strtotime($end_date));//结束日期
break;
}
return array("begin_date" => $begin_date, "end_date" => $end_date);
}
}

View File

@@ -0,0 +1,250 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace addon\weapp\shop\controller;
use addon\weapp\model\Config as ConfigModel;
use app\model\share\WeappShareBase as ShareModel;
use app\model\system\Upgrade;
use app\shop\controller\BaseShop;
use addon\weapp\model\Weapp as WeappModel;
use think\App;
/**
* 微信小程序功能设置
*/
class Weapp extends BaseShop
{
public function __construct(App $app = null)
{
$this->replace = [
'WEAPP_CSS' => __ROOT__ . '/addon/weapp/shop/view/public/css',
'WEAPP_JS' => __ROOT__ . '/addon/weapp/shop/view/public/js',
'WEAPP_IMG' => __ROOT__ . '/addon/weapp/shop/view/public/img',
];
parent::__construct($app);
}
/**
* 功能设置
*/
public function setting()
{
$config_model = new ConfigModel();
$is_new_version = 0;
// 获取站点小程序版本信息
$version_info = $config_model->getWeappVersion($this->site_id)[ 'data' ][ 'value' ];
$current_version_info = config('info');
if (!isset($version_info[ 'version' ]) || ( isset($version_info[ 'version' ]) && $version_info[ 'version' ] != $current_version_info[ 'version_no' ] )) {
$is_new_version = 1;
}
$this->assign('is_new_version', $is_new_version);
$weapp_menu = event('WeappMenu', [ 'site_id' => $this->site_id ]);
$this->assign('weapp_menu', $weapp_menu);
return $this->fetch('weapp/setting');
}
/**
* 公众号配置
*/
public function config()
{
$weapp_model = new ConfigModel();
if (request()->isJson()) {
$weapp_name = input('weapp_name', '');
$weapp_original = input('weapp_original', '');
$appid = input('appid', '');
$appsecret = input('appsecret', '');
$token = input('token', 'TOKEN');
$encodingaeskey = input('encodingaeskey', '');
$is_use = input('is_use', 0);
$qrcode = input('qrcode', '');
$data = array (
"appid" => $appid,
"appsecret" => $appsecret,
"token" => $token,
"weapp_name" => $weapp_name,
"weapp_original" => $weapp_original,
"encodingaeskey" => $encodingaeskey,
'qrcode' => $qrcode
);
$res = $weapp_model->setWeappConfig($data, $is_use, $this->site_id);
return $res;
} else {
$weapp_config_result = $weapp_model->getWeappConfig($this->site_id);
$config_info = $weapp_config_result[ 'data' ][ "value" ];
$this->assign("config_info", $config_info);
// 获取当前域名
$url = __ROOT__;
// 去除链接的http://头部
$url_top = str_replace("https://", "", $url);
$url_top = str_replace("http://", "", $url_top);
// 去除链接的尾部/?s=
$url_top = str_replace('/?s=', '', $url_top);
$call_back_url = addon_url("weapp://api/auth/relateweixin");
$this->assign("url", $url_top);
$this->assign("call_back_url", $call_back_url);
return $this->fetch('weapp/config');
}
}
/**
* 小程序包管理
* @return mixed
*/
public function package()
{
$config = new ConfigModel();
$weapp_config = $config->getWeappConfig($this->site_id)[ 'data' ][ 'value' ];
if (empty($weapp_config) || empty($weapp_config[ 'appid' ])) $this->error('小程序尚未配置,请先配置您的小程序!', href_url('weapp://shop/weapp/config'));
$this->assign('config', $weapp_config);
$is_new_version = 0;
// 获取站点小程序版本信息
$version_info = $config->getWeappVersion($this->site_id)[ 'data' ][ 'value' ];
$current_version_info = config('info');
if (!isset($version_info[ 'version' ]) || ( isset($version_info[ 'version' ]) && $version_info[ 'version' ] != $current_version_info[ 'version_no' ] )) {
$is_new_version = 1;
}
$this->assign('is_new_version', $is_new_version);
// 检测授权
$upgrade_model = new Upgrade();
$auth_info = $upgrade_model->authInfo();
$this->assign('is_auth', ( $auth_info[ 'code' ] == 0 ));
return $this->fetch('weapp/package');
}
/**
* 获取微信小程序部署信息
* @return array
*/
public function getDeploy()
{
if (request()->isJson()) {
$config = new ConfigModel();
$weapp_config = $config->getWeappConfig($this->site_id)[ 'data' ][ 'value' ];
$is_new_version = 0;
// 获取站点小程序版本信息
$version_info = $config->getWeappVersion($this->site_id)[ 'data' ][ 'value' ];
$current_version_info = config('info');
if (!isset($version_info[ 'version' ]) || ( isset($version_info[ 'version' ]) && $version_info[ 'version' ] != $current_version_info[ 'version_no' ] )) {
$is_new_version = 1;
}
$res = [
'config' => $weapp_config,
'is_new_version' => $is_new_version
];
return success('', '', $res);
}
}
/**
* 小程序包下载
*/
public function download()
{
if (strstr(ROOT_URL, 'niuteam.cn') === false) {
$weapp = new WeappModel();
$weapp->download($this->site_id);
$config = new ConfigModel();
$version_info = config('info');
$config->setWeappVersion([ 'version' => $version_info[ 'version_no' ] ], 1, $this->site_id);
}
}
/**
* 下载uniapp源码
*/
public function downloadUniapp()
{
if (strstr(ROOT_URL, 'niuteam.cn') === false) {
$app_info = config('info');
$upgrade_model = new Upgrade();
$res = $upgrade_model->downloadUniapp($app_info[ 'version_no' ]);
if ($res[ 'code' ] == 0) {
$filename = "upload/{$app_info['version_no']}_uniapp.zip";
$res = file_put_contents($filename, base64_decode($res[ 'data' ]));
header("Content-Type: application/zip");
header("Content-BirthdayGift-Encoding: Binary");
header("Content-Length: " . filesize($filename));
header("Content-Disposition: attachment; filename=\"" . basename($filename) . "\"");
readfile($filename);
@unlink($filename);
} else {
$this->error($res[ 'message' ]);
}
}
}
/**
* 分享
*/
public function shareBack()
{
$config_model = new ConfigModel();
if (request()->isJson()) {
$key = input('key', 'index');
$value = [
'title' => input('title', ''),
'path' => input('path', '')
];
$res = $config_model->setShareConfig($this->site_id, $this->app_module, $key, $value);
return $res;
}
$scene = [
[
'key' => 'index',
'title' => '首页'
]
];
$this->assign('scene', $scene);
$config = $config_model->getShareConfig($this->site_id, $this->app_module)[ 'data' ][ 'value' ];
$this->assign('config', $config);
$this->assign('shop_info', $this->shop_info);
return $this->fetch('weapp/share_back');
}
/**
* 分享
*/
public function share()
{
if (request()->isJson()) {
$data_json = input('data_json', '');
$data = json_decode($data_json, true);
$share_model = new ShareModel();
return $share_model->setShareConfig($this->site_id, $data);
} else {
$share_config = event('WeappShareConfig', [ 'site_id' => $this->site_id ]);
$config_list = [];
foreach ($share_config as $data) {
foreach ($data[ 'data' ] as $val) {
$config_list[] = $val;
}
}
$this->assign('config_list', $config_list);
return $this->fetch('weapp/share');
}
}
}

View File

@@ -0,0 +1,219 @@
<style>
.layui-elem-quote{color: #999;}
.table-btn{justify-content: center;}
.layui-card-header{border: 1px solid #f6f6f6;}
.layui-card-header .card-title{font-size: 14px;}
.template-content{white-space:pre;line-height: 1.5;text-align: left}
</style>
<div class="layui-collapse tips-wrap">
<div class="layui-colla-item">
<h2 class="layui-colla-title">操作提示</h2>
<ul class="layui-colla-content layui-show">
<li> 注意:请在小程序的服务类目中添加类目:一级类目:商业服务 二级类目:软件/建站/技术开发</li>
<li>小程序最多支持50个消息模板获取时请注意小程序剩余模板数量是否充足</li>
</ul>
</div>
</div>
<table id="template_list" lay-filter="template_list"></table>
<script type="text/html" id="batchOperation">
<button class="layui-btn layui-btn-primary" lay-event="open">批量开启</button>
<button class="layui-btn layui-btn-primary" lay-event="close">批量关闭</button>
<button class="layui-btn layui-btn-primary" lay-event="getAll">批量获取</button>
</script>
<script type="text/html" id="toolOperation">
<button class="layui-btn layui-btn-primary" lay-event="open">批量开启</button>
<button class="layui-btn layui-btn-primary" lay-event="close">批量关闭</button>
<button class="layui-btn layui-btn-primary" lay-event="getAll">批量获取</button>
</script>
<script type="text/html" id="operation">
<div class="table-btn">
{{# if(d.weapp_is_open == 0){ }}
<a class="layui-btn" lay-event="open">开启</a>
{{# }else{ }}
<a class="layui-btn" lay-event="close">关闭</a>
{{# } }}
{{# if(d.weapp_template_id != undefined && d.weapp_template_id != ''){ }}
<a class="layui-btn" lay-event="getTemplateNo">重新获取</a>
{{# } }}
</div>
</script>
<script type="text/html" id="message_type">
<div class="template-content">{{ d.message_info.content }}</div>
</script>
<script type="text/html" id="template_no">
{{ d.weapp_template_id ? d.weapp_template_id : '' }}
</script>
<script type="text/html" id="weapp_is_open">
{{ d.weapp_is_open == 1 ? '已启用' : '已关闭' }}
</script>
<script type="text/javascript">
var form,table;
layui.use(['form'], function(){
form = layui.form;
var repeat_flag = false;//防重复标识
table = new Table({
elem: '#template_list',
url: ns.url("weapp://shop/message/config"),
cols: [
[
{
width: "3%",
type: 'checkbox',
unresize: 'false'
},
{
field: 'title',
title: '类型',
align: 'left'
},
{
width: "25%",
field: 'message_type',
title: '回复内容',
templet: '#message_type',
align: 'left'
},
{
field: 'weapp_is_open',
title: '是否启用',
templet: '#weapp_is_open',
align: 'center'
},
{
width: "35%",
field: 'wechat_template_id',
title: '编号',
align: 'center',
templet: '#template_no'
},
{
title: '操作',
toolbar: '#operation',
align:'right'
}
]
],
toolbar: '#toolOperation',
bottomToolbar: "#batchOperation"
});
/**
* 批量操作
*/
table.bottomToolbar(function(obj) {
if (obj.data.length < 1) {
layer.msg('请选择要操作的数据');
return;
}
var keywords_array = new Array();
for (i in obj.data) keywords_array.push(obj.data[i].keywords);
switch (obj.event) {
case 'open': //开启
setStatus(keywords_array.toString(), 1);
break;
case 'close': //关闭
setStatus(keywords_array.toString(), 0);
break;
case 'getAll': //关闭
getTemplate(keywords_array.toString());
break;
}
});
table.toolbar(function(obj){
if (obj.data.length < 1) {
layer.msg('请选择要操作的数据');
return;
}
var keywords_array = new Array();
for (i in obj.data) keywords_array.push(obj.data[i].keywords);
switch (obj.event) {
case 'open': //开启
setStatus(keywords_array.toString(), 1);
break;
case 'close': //关闭
setStatus(keywords_array.toString(), 0);
break;
case 'getAll': //关闭
getTemplate(keywords_array.toString());
break;
}
});
/**
* 监听工具栏操作
*/
table.tool(function(obj) {
var data = obj.data;
switch (obj.event) {
case 'getTemplateNo': //获取模板id
getTemplate(data.keywords);
break;
case 'open': //开启
setStatus(data.keywords, 1);
break;
case 'close': //关闭
setStatus(data.keywords, 0);
break;
}
});
function setStatus(keywords, status) {
$.ajax({
type : "post",
url : '{:addon_url("weapp://shop/message/setWeappStatus")}',
data : {
"weapp_is_open":status,
'keywords' : keywords
},
dataType : "JSON",
success : function(res) {
repeat_flag = false;
layer.msg(res.message);
table.reload('template_list');
}
});
}
function getTemplate(keywords) {
var loadLayer;
layer.confirm('已存在的模板再次获取会导致模板重复存在,是否继续?', function (index) {
$.ajax({
type : "post",
url : '{:addon_url("weapp://shop/message/getWeappTemplateNo")}',
data : {
'keywords' : keywords
},
dataType : "JSON",
beforeSend: function(){
loadLayer = layer.msg("模板获取中,请耐心等待,请勿进行其他操作!",{ time : 1000 * 10000});
},
complete: function(){
layer.close(loadLayer);
},
success : function(res) {
repeat_flag = false;
layer.msg(res.message);
table.reload('template_list');
layer.close(index);
}
});
})
}
});
</script>

View File

@@ -0,0 +1,77 @@
<div class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label">是否开启:</label>
<div class="layui-input-block">
<input type="checkbox" name="weapp_is_open" value="1" {if $weapp_is_open == 1}checked{/if} lay-skin="switch">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">模板名称:</label>
<div class="layui-input-block">
{$message_title}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">模板编号:</label>
<div class="layui-input-block">
<input type="text" value="{if $info}{$info.tid}{/if}" placeholder="模板编号" autocomplete="off" class="layui-input len-long" readonly>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">模板内容:</label>
<div class="layui-input-inline">
<textarea placeholder="" class="layui-textarea len-long" readonly>{if $info}{$info.content}{/if}</textarea>
</div>
</div>
<input type="hidden" name="keywords" value="{$keywords}" />
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="save">保存</button>
<button type="reset" class="layui-btn layui-btn-primary" onclick="backMessageList()">返回</button>
</div>
</div>
<script>
layui.use(['form', 'colorpicker'], function() {
var form = layui.form,
repeat_flag = false; //防重复标识
form.render();
form.on('submit(save)', function(data) {
if (repeat_flag) return;
repeat_flag = true;
$.ajax({
url: ns.url("weapp://shop/message/edit"),
data: data.field,
dataType: 'JSON',
type: 'POST',
success: function(res) {
repeat_flag = false;
if (res.code == 0) {
layer.confirm('编辑成功', {
title:'操作提示',
btn: ['返回列表', '继续操作'],
yes: function(index, layero){
location.hash = ns.hash("shop/message/lists")
layer.close(index);
},
btn2: function(index, layero) {
layer.close(index);
}
});
}else{
layer.msg(res.message);
}
}
});
});
});
function backMessageList() {
location.hash = ns.hash("shop/message/lists");
}
</script>

View File

@@ -0,0 +1,9 @@
.access-statistics .access-api-list{display: flex;justify-content: space-between;padding: 0 15px;}
.access-statistics .access-api-item{flex-grow: 1;text-align: center;margin-right: 10px;border: 1px solid #e5e5e5;padding-top: 25px;}
.access-statistics .access-api-item:last-of-type{margin-right:0;}
.access-statistics .access-api-itme-content{height: 80px; line-height: 80px; font-size: 30px;}
.access-statistics .access-api-item-title{position: relative;}
.access-statistics .access-api-item-title h3{display: inline-block;}
.access-statistics .access-api-vice-content{font-size: 25px;}
.layui-fluid .layui-tab-title{margin-top: 0;}
.layui-tab-content-time{display: inline-block; height: 40px; margin-left: 15px; line-height: 40px;}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,228 @@
<link rel="stylesheet" href="WEAPP_CSS/wx_access_statistics.css">
<script src="SHOP_JS/echarts.min.js"></script>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">昨日分析</span>
</div>
<div class="layui-card-body access-statistics">
<ul class="access-api-list">
<li class="access-api-item">
<div class="access-api-item-title">
<h3>打开次数</h3>
</div>
<p class="access-api-itme-content" id="session_cnt">0</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>访问次数/人数</h3>
</div>
<p class="access-api-itme-content" id="visit_pv_visit_uv">0/0</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>新访问用户数</h3>
</div>
<p class="access-api-itme-content" id="visit_uv_new">0</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>人均/次均停留时长(秒)</h3>
</div>
<p class="access-api-itme-content" id="stay_time_uv_stay_time_session">0/0</p>
</li>
</ul>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">上月概况</span>
</div>
<div class="layui-card-body access-statistics">
<ul class="access-api-list ">
<li class="access-api-item">
<div class="access-api-item-title">
<h3>打开次数</h3>
</div>
<p class="access-api-itme-content" id="month_session_cnt">0</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>访问次数/人数</h3>
</div>
<p class="access-api-itme-content" id="month_visit_pv_visit_uv">0/0</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>新访问用户数</h3>
</div>
<p class="access-api-itme-content" id="month_visit_uv_new">0</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>人均/次均停留时长(秒)</h3>
</div>
<p class="access-api-itme-content" id="month_stay_time_uv_stay_time_session">0/0</p>
</li>
</ul>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-body access-statistics">
<div class="layui-tab-content-time">
<span>时间</span>
<div class="layui-input-inline daterange-input-wrap">
<input type="text" class="layui-input daterange-input" id="daterange" placeholder=" - ">
</div>
</div>
<div class="info-img">
<div id="main" style="width: 100%;height:400px;"></div>
</div>
</div>
</div>
<script>
var daterange = '{:date("Y-m-d", strtotime("-6 days"))} 至 {:date("Y-m-d")}';
layui.use('laydate', function(){
var laydate = layui.laydate;
//日期范围
laydate.render({
elem: '#daterange'
,format: 'yyyy-MM-dd'
,range: '至'
,value:daterange //必须遵循format参数设定的格式
,done: function(value, date, endDate){
daterange = value;
visitStatistics();
}
});
visitData("yesterday");
visitData("month");
visitStatistics();
});
//折线图
if($('#main').length) {
var chart = echarts.init(document.getElementById('main'));
}
//获取微信小程序访问统计数据(按日)
function visitStatistics(){
chart.showLoading();//加载视图
$.ajax({
type: "post",
url: "{:addon_url('weapp://shop/stat/visitStatistics')}",
dataType: "JSON",
data: {daterange : daterange},
success: function (result) {
var chart_data = result.data;
var option = {
legend: {
data:['打开次数','访问次数','访问人数','新用户数','人均停留时长','次均停留时长','平均访问深度'],
x: 'right',
right: '20',
},
tooltip: {
trigger: 'axis'
},
grid: {
left: '20',
right: '20',
bottom: '20',
containLabel: true
},
xAxis: {
type: 'category',
data: chart_data.date
},
yAxis: {
type: 'value'
},
series: [
{
data: chart_data.data.session_cnt_data,
type: 'line',
smooth: true,
name: "打开次数"
},
{
data: chart_data.data.visit_pv_data,
type: 'line',
smooth: true,
name: "访问次数"
},
{
data: chart_data.data.visit_uv_data,
type: 'line',
smooth: true,
name: "访问人数"
},
{
data: chart_data.data.visit_uv_new_data,
type: 'line',
smooth: true,
name: "新用户数"
},
{
data: chart_data.data.stay_time_uv_data,
type: 'line',
smooth: true,
stack: '秒',
name: "人均停留时长"
},
{
data: chart_data.data.stay_time_session_data,
type: 'line',
smooth: true,
stack: '秒',
name: "次均停留时长"
},
{
data: chart_data.data.visit_depth_data,
type: 'line',
smooth: true,
name: "平均访问深度"
},
]
};
chart.setOption(option);
chart.hideLoading();
}
});
}
/**
*统计数据
*/
function visitData(date_type){
$.ajax({
type: "post",
url: "{:addon_url('weapp://shop/stat/visitdata')}",
dataType: "JSON",
data: {date_type : date_type},
success: function (res) {
var data = res.data;
if(data.length > 0){
if(date_type == "month"){
$("#month_session_cnt").text(data.data.session_cnt);
$("#month_visit_pv_visit_uv").text(data.data.visit_pv +"/"+data.data.visit_uv);
$("#month_visit_uv_new").text(data.data.visit_uv_new);
$("#month_stay_time_uv_stay_time_session").text(data.data.stay_time_uv +"/"+data.data.stay_time_session);
}else{
$("#session_cnt").text(data.data.session_cnt);
$("#visit_pv_visit_uv").text(data.data.visit_pv +"/"+data.data.visit_uv);
$("#visit_uv_new").text(data.data.visit_uv_new);
$("#stay_time_uv_stay_time_session").text(data.data.stay_time_uv +"/"+data.data.stay_time_session);
}
}
}
});
}
</script>

View File

@@ -0,0 +1,235 @@
<div class="layui-form">
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">小程序开发者设置</span>
</div>
<div class="layui-card-body">
<div class="layui-form-item">
<label class="layui-form-label">小程序名称:</label>
<div class="layui-input-inline">
<input type="text" name="weapp_name" autocomplete="off" class="layui-input len-long" value="{$config_info.weapp_name ?? ''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">小程序原始ID</label>
<div class="layui-input-block">
<input type="text" name="weapp_original" autocomplete="off" class="layui-input len-long" value="{$config_info.weapp_original ?? ''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">小程序二维码:</label>
<div class="layui-input-inline img-upload">
<div class="upload-img-block">
<div class='upload-img-box {if condition="$config_info && $config_info.qrcode"}hover{/if}'>
<div class="upload-default" id="img">
{if condition="$config_info && $config_info.qrcode"}
<div id="preview_img" class="preview_img">
<img layer-src src="{:img($config_info.qrcode)}" class="img_prev"/>
</div>
{else/}
<div class="upload">
<i class="iconfont iconshangchuan"></i>
<p>点击上传</p>
</div>
{/if}
</div>
<div class="operation">
<div>
<i title="图片预览" class="iconfont iconreview js-preview" style="margin-right: 20px;"></i>
<i title="删除图片" class="layui-icon layui-icon-delete js-delete"></i>
</div>
<div class="replace_img js-replace">点击替换</div>
</div>
<input type="hidden" class="layui-input" name="qrcode" value="{$config_info.qrcode ?? ''}"/>
</div>
</div>
<!-- <p id="img" class=" {if condition="$config_info && $config_info.qrcode"} replace {else/} no-replace{/if}">替换</p>
<input type="hidden" class="layui-input" name="qrcode" value="{$config_info.qrcode ?? ''}"/>
<i class="del {if condition="$config_info && $config_info.qrcode"}show{/if}">x</i> -->
</div>
</div>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">开发者ID设置</span>
</div>
<div class="layui-card-body">
<div class="layui-form-item">
<label class="layui-form-label">APPID</label>
<div class="layui-input-inline ">
<input type="text" name="appid" autocomplete="off" class="layui-input len-long" value="{$config_info.appid ?? ''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">APP密钥</label>
<div class="layui-input-block ">
<input type="text" name="appsecret" autocomplete="off" class="layui-input len-long" value="{$config_info.appsecret ?? ''}">
</div>
<div class="word-aux">AppID(小程序ID)和AppSecret(小程序密钥)来自于您申请的小程序账号,使用小程序账号密码登录公众平台,在开发->开发设置中可以找到</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">业务域名校验文件:</label>
<div class="layui-input-block">
<button class="layui-btn layui-btn-primary" id="checkFile">上传文件</button>
</div>
<div class="word-aux">仅支持上传TXT格式的文件</div>
</div>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">服务器配置信息</span>
</div>
<div class="layui-card-body">
<div class="layui-form-item">
<label class="layui-form-label">request合法域名</label>
<div class="layui-input-inline ">
<input type="text" autocomplete="off" readonly id="url_request" class="layui-input len-long" value="https://{$url}">
</div>
<button class="layui-btn layui-btn-primary" onclick="ns.copy('url_request')">复制</button>
</div>
<div class="layui-form-item">
<label class="layui-form-label">socket合法域名</label>
<div class="layui-input-inline ">
<input type="text" autocomplete="off" readonly id="url_socket" class="layui-input len-long" value="wss://{$url}">
</div>
<button class="layui-btn layui-btn-primary" onclick="ns.copy('url_socket')">复制</button>
</div>
<div class="layui-form-item">
<label class="layui-form-label">uploadFile合法域名</label>
<div class="layui-input-inline ">
<input type="text" autocomplete="off" readonly id="url_upload" class="layui-input len-long" value="https://{$url}">
</div>
<button class="layui-btn layui-btn-primary" onclick="ns.copy('url_upload')">复制</button>
</div>
<div class="layui-form-item">
<label class="layui-form-label">downloadFile合法域</label>
<div class="layui-input-inline ">
<input type="text" autocomplete="off" id="url_download" readonly class="layui-input len-long" value="https://{$url}">
</div>
<button class="layui-btn layui-btn-primary" onclick="ns.copy('url_download')">复制</button>
</div>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">消息推送设置</span>
</div>
<div class="layui-card-body">
<div class="layui-form-item">
<label class="layui-form-label">URL(服务器地址)</label>
<div class="layui-input-block">
<div class="layui-input-inline">
<input type="text" name="token" readonly id="callback_url" autocomplete="off" class="layui-input len-long" value="{$call_back_url}">
</div>
<button class="layui-btn layui-btn-primary" onclick="ns.copy('callback_url')">复制</button>
</div>
<div class="word-aux">必须以http://或https://开头分别支持80端口和443端口。</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Token(令牌)</label>
<div class="layui-input-block">
<div class="layui-input-inline">
<input type="text" name="token" autocomplete="off" id="empowerToken" class="layui-input len-long" value="{$config_info.token ?? ''}">
</div>
<button class="layui-btn layui-btn-primary" onclick="ns.copy('empowerToken')">复制</button>
</div>
<div class="word-aux">Token必须为英文或数字长度为3-32字符。如不填写则默认为“TOKEN”。</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">EncodingAESKey</label>
<div class="layui-input-block">
<div class="layui-input-inline len-long">
<input class="layui-input" type="text" name="encodingaeskey" id="encodingaeskey" autocomplete="off" value="{$config_info.encodingaeskey ?? ''}">
</div>
<button class="layui-btn layui-btn-primary" onclick="ns.copy('encodingaeskey')">复制</button>
</div>
<div class="word-aux">消息加密密钥由43位字符组成字符范围为A-Z,a-z,0-9</div>
</div>
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="save">保存</button>
<button type="reset" class="layui-btn layui-btn-primary" onclick="backWeappSetting()">返回</button>
<a id="imageQrcode"></a>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var saveData = null;
var totalUploadNum = 0;
var completeUploadNum = 0;
var upload;
layui.use(['form'], function () {
var form = layui.form,
repeat_flag = false; //防重复标识
form.render();
form.on('submit(save)', function (data) {
if (repeat_flag) return;
repeat_flag = true;
saveData = data;
var obj = $("img.img_prev[data-prev='1']");
totalUploadNum = obj.length;
if(totalUploadNum > 0){
obj.each(function(){
var actionId = $(this).attr('data-action-id');
$(actionId).click();
})
}else{
saveFunc();
}
});
upload = new Upload({
elem: '#img',
auto: false,
bindAction:'#imageQrcode',
callback: function(res) {
uploadComplete('qrcode', res.data.pic_path);
}
});
function uploadComplete(field, pic_path) {
saveData.field[field] = pic_path;
completeUploadNum += 1;
if(completeUploadNum == totalUploadNum){
saveFunc();
}
}
function saveFunc(){
var data = saveData;
$.ajax({
type: "post",
url: "{:addon_url('weapp://shop/weapp/config')}",
dataType: "JSON",
data: data.field,
success: function (data) {
repeat_flag = false;
layer.msg(data.message);
}
});
}
var file_upload = new Upload({
elem: '#checkFile',
url: ns.url("shop/upload/checkfile"),
accept: 'file',
acceptMime: 'text/plain',
exts: 'txt'
});
});
function backWeappSetting() {
location.hash = ns.hash('weapp://shop/weapp/setting');
}
</script>

View File

@@ -0,0 +1,125 @@
<style type="text/css">
.package-wrap {margin-top:50px;display:flex;}
.package-wrap .wrap {flex:1;border:1px solid #f1f1f1;}
.package-wrap .wrap:nth-child(2) {margin-left:30px;}
.package-wrap .wrap .card-common {margin-top:0;}
.package-wrap .wrap .layui-card-header {padding:5px 20px;}
.weapp-info {text-align:center;font-size: 12px}
.weapp-info .qrcode {width:130px;height:130px;margin:30px auto;}
.weapp-info dl {display:flex;line-height:30px}
.weapp-info dl dt,.weapp-info dl dd {flex:1;}
.weapp-info dl dt {width:100px;text-align:right;color:#999;}
.weapp-info dl dd {text-align:left;padding-left:30px;}
.wrap .step-wrap .layui-timeline {padding-left:40px!important;}
.wrap .step-wrap .layui-timeline-title {font-size:12px;margin-bottom:5px;}
.step-wrap .layui-timeline-content p {font-size:12px;}
.step-wrap .layui-timeline-item{padding-bottom: 40px;}
.step-wrap .layui-timeline-item:before {left:4px;background-color:unset;border-left:1px dashed #ccc;}
.edition-wrap {margin-top:20px;}
.edition-wrap .header {font-size:14px;}
.edition-list .edition-item {display:inline-block;width:auto;border:1px solid #ddd;padding:8px 30px;line-height:1;margin:15px 15px 0 0;border-radius:5px;cursor:pointer;}
.edition-list .edition-item .name {color:#333;}
.edition-list .edition-item:hover,.edition-list .edition-item.active {border-color:var(--base-color);}
.edition-list .edition-item:hover .name,.edition-list .edition-item.active .name {color:var(--base-color);}
.edition-list .edition-item .version {margin-top:8px;font-size:12px;color:#999;}
.operation {margin-top:20px;display:flex;}
.operation .layui-btn {flex:1;}
.loading-layer .loading-img {margin:10px auto;display:block;}
.preview-layer .qrcode {width:100px;height:100px;margin:10px auto;display:block;}
.new-version-tips{margin-top: 10px;border:1px dashed;padding: 5px 10px;}
</style>
<div class="layui-collapse tips-wrap">
<div class="layui-colla-item">
<h2 class="layui-colla-title">操作提示</h2>
<ul class="layui-colla-content layui-show">
<li>下载之后需使用微信开发者工具上传代码,微信开发者工具下载地址: <a href="https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html" target="_blank">https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html</a></li>
<li>上传之后登录<a href="https://mp.weixin.qq.com" target="_blank">微信公众平台</a>,在版本管理中选择刚上传的版本提交审核,审核通过之后即可发布小程序。</li>
<li>UNIAPP源码包授权后可下载可很好的进行二次开发可通过<a href="https://www.dcloud.io/hbuilderx.html" target="_blank">HBuilder X</a>编译为H5、微信小程序、支付宝小程序、头条小程序等</li>
<li>小程序代码包是由UNIAPP源码包编译出来的微信小程序版下载后可直接通过微信开发者工具上传使用但是无法进行二次开发。</li>
</ul>
</div>
</div>
<div class="package-wrap">
<div class="wrap">
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">小程序信息</span>
</div>
<div class="layui-card-body layui-field-box weapp-info">
<img src="{:img($config.qrcode)}" class="qrcode">
<dl>
<dt>小程序名称</dt>
<dd>{$config.weapp_name}</dd>
</dl>
<dl>
<dt>小程序ID</dt>
<dd>{$config.appid}</dd>
</dl>
<dl>
<dt>小程序原始ID</dt>
<dd>{$config.weapp_original}</dd>
</dl>
</div>
</div>
</div>
<div class="wrap">
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">源码下载</span>
</div>
<div class="layui-card-body layui-field-box">
<div class="step-wrap">
<ul class="layui-timeline">
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis text-color">&#xe63f;</i>
<div class="layui-timeline-content layui-text">
<h3 class="layui-timeline-title">下载小程序代码包</h3>
<div style="margin-top: 10px;">
<a class="layui-btn layui-btn-primary" href="{:addon_url('weapp://shop/weapp/download',[ 'request_mode' => 'download' ])}" target="_blank">下载小程序代码包</a>
{if $is_auth}
<a class="layui-btn layui-btn-primary" href="{:addon_url('weapp://shop/weapp/downloaduniapp',[ 'request_mode' => 'download' ])}" target="_blank">下载UNIAPP源码包</a>
{else/}
<a class="layui-btn layui-btn-primary" href="javascript:;" onclick="authLayer()">下载UNIAPP源码包</a>
{/if}
</div>
{if $is_new_version}
<div class="new-version-tips text-color bg-color-light-9 border-color">
<p>小程序已更新,为了不影响您的使用请尽快下载小程序上传更新。</p>
</div>
{/if}
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis text-color">&#xe63f;</i>
<div class="layui-timeline-content layui-text">
<h3 class="layui-timeline-title">上传代码</h3>
<p>下载完成之后,使用微信开发工具进行上传</p>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis text-color">&#xe63f;</i>
<div class="layui-timeline-content layui-text">
<h3 class="layui-timeline-title">发布小程序</h3>
<p>上传之后提交审核,审核通过发布小程序</p>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
function authLayer(){
layer.confirm('当前为免费版授权后才可以下载UNIAPP源码包是否立即授权', {
btn: ['立即授权','暂不需要'] //按钮
}, function(){
window.open('https://www.niushop.com');
}, function(){
layer.closeAll();
});
}
</script>

View File

@@ -0,0 +1,86 @@
<style>
.applet-item {
padding:10px;
margin:0 10px 10px 0;
display:inline-block;
width:280px;
border: 1px solid #eee;
border-radius: 5px;
}
.applet-item .applet-img {
width:100%;
padding:50% 0;
position:relative;
overflow:hidden;
}
.applet-item .applet-img img {
position:absolute;
width:100%;
height:auto;
max-height:100%;
left:50%;
top:50%;
transform:translate(-50%,-50%);
}
.applet-item .applet-name {
font-size:14px;
line-height:1;
background:none;
padding:0;
margin-top:10px
}
.applet-item .applet-desc {
line-height:1.5;
font-size:12px;
color:#666;
margin:10px 0;
height:38px;
overflow:hidden;
text-overflow:ellipsis;
}
.empty {
text-align:center;
height:150px;
line-height:150px;
}
</style>
<div class="layui-collapse tips-wrap">
<div class="layui-colla-item">
<h2 class="layui-colla-title">操作提示</h2>
<ul class="layui-colla-content layui-show">
<li>已购买的小程序会出现在下方,购买可前往<a href="https://www.niushop.com" target="_blank">Niushop官网</a>进行购买</li>
<li>下载之后需使用HBuilderX编译成微信小程序,然后进行发布,HBuilderX下载地址: <a href="https://www.dcloud.io/hbuilderx.html" target="_blank">https://www.dcloud.io/hbuilderx.html</a></li>
</ul>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">已购小程序</span>
</div>
<div class="layui-card-body layui-field-box">
<div class="applet-list">
{notempty name="list"}
{foreach name="list" item="item"}
<div class="applet-item">
<div class="applet-img">
<img src="{$item.product_info.image}" alt="">
</div>
<h4 class="applet-name">{$item.product_info.module_name}</h4>
<p class="applet-desc">{$item.product_info.summary}</p>
<div>
<a href="{:href_url('weapp://shop/weapp/package?mark='. $item['module_mark'] )}">
<button class="layui-btn">下载小程序源码包</button>
</a>
</div>
</div>
{/foreach}
{else/}
<div class="empty">
您还未购买过小程序,<a href="https://www.niushop.com" target="_blank">前去购买</a>
</div>
{/notempty}
</div>
</div>
</div>

View File

@@ -0,0 +1,163 @@
<style>
.progress-wrap {
display: flex;
align-items: center;
text-align: center;
min-height: 120px;
}
.progress-point {
flex-grow: 1;
}
.progress-point-pic {
display: inline-block;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
margin-top: 10px;
margin-bottom: 20px;
}
.progress-point-pic img {
max-width: 100%;
max-height: 100%;
}
.item-block-wrap .new-tips{
width: 8px;
height: 8px;
background: #f00;
border-radius: 50%;
position: absolute;
right: 15px;
}
.item-content-desc{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">微信小程序使用流程</span>
</div>
<div class="layui-card-body">
<ul class="progress-wrap">
<li class="progress-point">
<div class="progress-point-pic">
<img src="WEAPP_IMG/register.png" alt="">
</div>
<p class="progress-point-text">注册微信小程序应用</p>
</li>
<li class="progress-point-arrow">
<img src="WEAPP_IMG/arrow.png" alt="">
</li>
<li class="progress-point">
<div class="progress-point-pic">
<img src="WEAPP_IMG/set_up.png" alt="">
</div>
<p class="progress-point-text">信息完善</p>
</li>
<li class="progress-point-arrow">
<img src="WEAPP_IMG/arrow.png" alt="">
</li>
<li class="progress-point">
<div class="progress-point-pic">
<img src="WEAPP_IMG/public_number.png" alt="">
</div>
<p class="progress-point-text">开发</p>
</li>
<li class="progress-point-arrow">
<img src="WEAPP_IMG/arrow.png" alt="">
</li>
<li class="progress-point">
<div class="progress-point-pic">
<img src="WEAPP_IMG/edition.png" alt="">
</div>
<p class="progress-point-text">提交审核</p>
</li>
<li class="progress-point-arrow">
<img src="WEAPP_IMG/arrow.png" alt="">
</li>
<li class="progress-point">
<div class="progress-point-pic">
<img src="WEAPP_IMG/complete.png" alt="">
</div>
<p class="progress-point-text">发布</p>
</li>
</ul>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">微信小程序入口</span>
</div>
<div class="layui-card-body">
<div class="site_list item-block-parent item-five">
<a class="item-block item-block-hover-a" href="{:href_url('weapp://shop/weapp/config')}">
<div class="item-block-wrap">
<div class="item-pic">
<img src="WEAPP_IMG/administration.png">
</div>
<div class="item-con">
<div class="item-content-title">小程序管理</div>
<p class="item-content-desc">小程序管理</p>
</div>
</div>
</a>
<!-- <a class="item-block item-block-hover-a" href="{:href_url('weapp://shop/weapp/package')}">-->
<!-- <div class="item-block-wrap">-->
<!-- <div class="item-pic">-->
<!-- <img src="WEAPP_IMG/download.png">-->
<!-- </div>-->
<!-- <div class="item-con">-->
<!-- <div class="item-content-title">小程序发布</div>-->
<!-- <p class="item-content-desc">小程序发布</p>-->
<!-- </div>-->
<!-- {if $is_new_version}<span class="new-tips"></span>{/if}-->
<!-- </div>-->
<!-- </a>-->
<a class="item-block item-block-hover-a" href="{:href_url('weapp://shop/message/config')}">
<div class="item-block-wrap">
<div class="item-pic">
<img src="WEAPP_IMG/message.png">
</div>
<div class="item-con">
<div class="item-content-title">订阅消息</div>
<p class="item-content-desc">给用户提供更好的服务闭环体验</p>
</div>
</div>
</a>
<a class="item-block item-block-hover-a" href="{:href_url('weapp://shop/weapp/share')}">
<div class="item-block-wrap">
<div class="item-pic">
<img src="WEAPP_IMG/share.png">
</div>
<div class="item-con">
<div class="item-content-title">分享设置</div>
<p class="item-content-desc">小程序分享设置</p>
</div>
</div>
</a>
{notempty name="$weapp_menu"}
{foreach name="$weapp_menu" item="vo"}
<a class="item-block item-block-hover-a" href="{:href_url($vo.url)}">
<div class="item-block-wrap">
<div class="item-pic">
<img src="{:img($vo.icon)}">
</div>
<div class="item-con">
<div class="item-content-title">{$vo.title}</div>
<p class="item-content-desc">{$vo.description}</p>
</div>
</div>
</a>
{/foreach}
{/notempty}
</div>
</div>
</div>

View File

@@ -0,0 +1,253 @@
<style>
.share-box{display: flex;align-items: center;flex-wrap: wrap;}
.share-box .share-item{margin:0 20px 20px 0;width: 300px;height: 340px;border: 1px solid #EEEEEE;border-radius: 3px;}
.share-box .share-item .share-title{width: 100%;height: 55px;display: flex;align-items: center;justify-content: space-between; padding: 0 20px;box-sizing: border-box;border-bottom: 1px solid #EEEEEE;}
.share-box .share-item .share-title{font-size: 14px;font-family: Microsoft YaHei;font-weight: 400;color: #606266;}
.share-box .share-item .share-title .edit{color: var(--base-color);cursor: pointer;}
.share-box .share-item .content-box{width: 100%;height: calc(100% - 55px);padding: 20px;box-sizing: border-box;display: flex;flex-direction: column;justify-content: space-between;}
.share-box .share-item .content-box .title{font-size: 16px;font-family: Microsoft YaHei;font-weight: 400;color: #303133;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}
.share-box .share-item .content-box .img{width: 260px;height: 208px;background: #ececec;font-size: 24px;text-align: center;line-height: 208px;color: #c0c0c0;overflow: hidden;}
.share-box .share-item .content-box .img .imgover1{width: 260px;}
.share-box .share-item .content-box .img .imgover2{height: 208px;}
.layui-form-item .layui-input-inline .layui-input{width: 248px;}
.layui-form-item .layui-input-inline .text-tips{line-height: 1;}
.layui-form-label1{height: 1px;}
</style>
<script>
function judgeImageSize(that){
let w = $(that).width();
let h = $(that).height();
let i = $(that).attr('key');
let name = 'img-box' + i;
if(w > h){
$(`div[name=${name}]`).children().addClass('imgover2')
}else{
$(`div[name=${name}]`).children().addClass('imgover1')
}
}
</script>
<div class="share-box">
{foreach $config_list as $key=>$config_item}
<div class="share-item">
<div class="share-title" data-key="{$config_item.config.config_key}" data-data='{:json_encode($config_item)}'>
<span class="title">{$config_item.config.title}</span>
<a href="javascript:void(0)" class="edit-btn text-color">编辑</a>
</div>
<div class="content-box">
<div class="title" title="{$config_item.value.title}">{$config_item.value.title}</div>
<div class="img" name="img-box{$key}">
{if isset($config_item.value.imageUrl) && !empty($config_item.value.imageUrl)}
<img loading="eager" onload="judgeImageSize(this)" key="{$key}" src="{:img($config_item.value.imageUrl)}" >
{else /}
<span>分享页面截图</span>
{/if}
</div>
</div>
</div>
{/foreach}
</div>
<script type="text/html" id="openContent">
<div class="html-open layui-form">
{{# if(d.variable.length){ }}
<div class="layui-form-item">
<label class="layui-form-label">变量替换</label>
<div class="layui-input-inline">
{{# layui.each(d.variable,function(index,item){ }}
<button type="button" class="layui-btn addBtn bg-color" data-tips="{{item.name}}">{{item.title}}</button>
{{# }) }}
</div>
</div>
{{# } }}
<div class="layui-form-item">
<label class="layui-form-label">分享标题</label>
<div class="layui-input-inline">
<input type="text" name="title" id="title" autocomplete="off" placeholder="请输入标题" value="{{d.value.title}}" class="layui-input addText" />
</div>
</div>
{{# if(d.value.imageUrl != undefined){ }}
<div class="layui-form-item">
<label class="layui-form-label">分享图片</label>
<div class="layui-input-block img-upload">
<div class="upload-img-block">
<div class="upload-img-box {{# if(d.value.imageUrl){ }}hover{{# } }}">
<div class="upload-default" id="logoUpload">
{{# if(d.value.imageUrl){ }}
<div id="preview_logoUpload" class="preview_img">
<img layer-src judge = 'true' src="{{ ns.img(d.value.imageUrl) }}" class="img_prev"/>
</div>
{{#} else { }}
<div class="upload">
<i class="iconfont iconshangchuan"></i>
<p>点击上传</p>
</div>
{{# } }}
</div>
<div class="operation">
<div>
<i title="图片预览" class="iconfont iconreview js-preview" style="margin-right: 20px;"></i>
<i title="删除图片" class="layui-icon layui-icon-delete js-delete"></i>
</div>
<div class="replace_img js-replace">点击替换</div>
</div>
<input type="hidden" name="imageUrl" value="{{d.value.imageUrl}}"/>
</div>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label layui-form-label1"></label>
<div class="layui-input-inline">
<div class="text-color text-tips">建议上传图片宽: = 5:4,不上传则使用页面截图</div>
</div>
</div>
{{# } }}
<div class="layui-form-item">
<label class="layui-form-label"></label>
<div class="layui-input-inline">
<button type="button" class="layui-btn" lay-submit lay-filter="formDemo">确认</button>
<button type="button" id="closeOpen" class="layui-btn layui-btn-primary closeOpen">取消</button>
<a id="save"></a>
</div>
</div>
</div>
</script>
<script>
var layer,laytpl,form,imageUrl,save_data = [],repeat_flag = false;
layui.use(['layer','laytpl'], function(){
layer = layui.layer;
laytpl = layui.laytpl;
form =layui.form;
form.render();
});
$(document).ready(function () {
var edit_num = 0;
$(".edit-btn").each(function(){
$(this).click(function(){
let data_key = $(this).parents('.share-title').attr('data-key');
let data_data = JSON.parse($(this).parents('.share-title').attr('data-data'));
let areaJudge = ['700px','380px'];
if(data_data.variable.length == 0){
areaJudge = ['700px','335px'];
}
let htmlOpenIndex = layer.open({
type: 1,
title:'分享设置',
area:areaJudge,
content:"<div id='openHtml'></div>" ,//这里content是一个普通的String
success:res=>{
laytpl($('#openContent').html()).render(data_data,function(html){
$('#openHtml').html(html);
});
//添加标记、用于变量替换时确定节点
$("input[name='title']").on("focus",function(){
$(this).addClass('addText');
$("textarea[name='desc']").removeClass('addText');
});
$("textarea[name='desc']").on("focus",function(){
$(this).addClass('addText');
$("input[name='title']").removeClass('addText');
});
// 变量数据追加
$('.layui-input-inline .addBtn').on('click',function(){
//向后追加所用模板数据
let addText = $(this).attr('data-tips');
// 获取需要修改的demo节点name
let name = $('.addText').attr('name');
switch(name){
case 'title':
var txtArea = $("input[name='title']")[0];
var content = txtArea.value;//文本域内容
var start = txtArea.selectionStart; //光标的初始位置selectionStart选区开始位置selectionEnd选区结束位置。
txtArea.value = content.substring(0, txtArea.selectionStart) + addText + content.substring(txtArea.selectionEnd, content.length);
var position = start + addText.length;
$("input[name='title']").focus();
txtArea.setSelectionRange(position+1, position);
break;
case 'desc':
var txtArea = $("textarea[name='desc']")[0];
var content = txtArea.value;//文本域内容
var start = txtArea.selectionStart; //光标的初始位置selectionStart选区开始位置selectionEnd选区结束位置。
txtArea.value = content.substring(0, txtArea.selectionStart) + addText + content.substring(txtArea.selectionEnd, content.length);
var position = start + addText.length;
$("textarea[name='desc']").focus();
txtArea.setSelectionRange(position+1, position);
break;
}
});
// 接口上传
form.on('submit(formDemo)',function(data){
let obj = data.field;
obj.config_key = data_data.config.config_key;
save_data = [];
save_data.push(obj);
if(data_data.value.imageUrl == undefined){
save(save_data);
}else{
let judge = $('.preview_img .img_prev').attr('judge');
if(!judge){
let imgJudge = $('.upload-default .preview_img .img_prev');
if(!imgJudge.length){
save_data[0].imageUrl = '';
save(save_data);
}else{
$('#save').click();
}
}else{
save(save_data);
}
}
});
//选择图片
var upload = new Upload({
elem: '#logoUpload',
auto: false, //选择文件后不自动上传
bindAction: '#save', //指向一个按钮触发上传
callback: function (res) {
if(res.code >= 0){
save_data[0].imageUrl = res.data.pic_path;
save(save_data);
}
}
});
//点击取消弹窗关闭
$('#closeOpen').on('click',function(){
layer.close(htmlOpenIndex)
});
form.render();
},
});
})
})
});
function save(data){
if(repeat_flag) return false;
repeat_flag = true;
$.ajax({
type: 'POST',
url: ns.url("weapp://shop/weapp/share"),
data: {
data_json : JSON.stringify(data),
},
dataType: 'JSON',
success: function (res) {
repeat_flag = false;
layer.msg(res.message);
}
});
}
</script>

View File

@@ -0,0 +1,268 @@
<style>
.word-aux{
display: flex;
}
.mini-program{
width: 42px;
height: 15px;
font-size: 14px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #666666;
}
.share {
margin-top: 10px;
padding:20px;
border: 1px solid #e5e5e5;
position: relative;
border-radius: 3px;
box-sizing: border-box;
}
.layui-input-block, .word-aux {
margin:20px auto 0;
}
textarea {
margin-top:10px;
}
.picture-introduce{
width: 293px;
height: 13px;
font-size: 12px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #B3B3B3;
margin-top: 13px;
}
.top-text{
display: flex;
align-items: center;
border-bottom: 1px solid #e5e5e5;
padding-bottom: 20px;
}
.top-text .logo{
width: 40px;
height: 40px;
color: #fff;
background-color: #e5e5e5;
font-size: 12px;
text-align: center;
line-height: 40px;
margin-right: 10px;
border-radius: 50%;
}
.company-titles{
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: 16px;
color: #333333;
}
.bottom{
display: flex;
}
.replace_img js-replace{
position: absolute;
bottom: 0;
width: 100%;
height: 24px;
color: #fff;
background: rgba(0, 0, 0, 0.5);
font-size: 12px;
line-height: 24px;
}
::-webkit-input-placeholder{
position: absolute;
top: 5px;
left: 5px;
}
.member-detail-list{
display: flex;
flex-wrap: wrap;
}
.member-detail-list .detail-item{
width: 350px;
margin-right: 20px;
margin-bottom: 20px;
}
.member-detail-list .main-header{
overflow: hidden;
display: block;
text-overflow: ellipsis;
margin: 0;
white-space: nowrap;
font-size: 14px;
color: #666;
}
.member-detail-list .share-desc{
margin-top: 20px;
}
.member-detail-list .img-upload{
margin-top: 18px;
}
.member-detail-list .upload-img-block{
border-style: solid;
border-radius: 2px;
}
.member-detail-list .bottom{
display: flex;
align-content: center;
margin-top: 18px;
}
.member-detail-list .bottom .iconfont{
color: #08BA06;
margin-right: 5px;
}
.member-detail-list .upload-img-block{
width: 310px;
height:248px;
padding: 0;
}
.member-detail-list .upload-img-block .operation i{
line-height: 246px;
}
</style>
{notempty name="$scene"}
<div class="member-detail-list">
{foreach $scene as $scene_item}
<div class="detail-item" data-key="{$scene_item['key']}">
<div class="word-aux main-header">{$scene_item['title']}</div>
<div class="share">
<div class="top-text">
<span class="logo">Logo</span>
<div class="company-titles">小程序名称</div>
</div>
<form action="" class="layui-form" lay-filter="example">
<input type="text" name="share-title" class="layui-input share-desc" placeholder="小程序分享描述" value="{$config[$scene_item['key']]['title'] ?? ''}" maxlength="50">
<div class="layui-input-block img-upload">
<div class="upload-img-block">
<div class="upload-img-box {if !empty($config[$scene_item['key']]['path'])}hover{/if}" style="position: relative;">
<div class="upload-default" id="shareUpload_{$scene_item['key']}">
{if empty($config[$scene_item['key']]['path'])}
<div class="upload">
<i class="iconfont iconshangchuan"></i>
<p>点击上传</p>
</div>
{else /}
<div id="preview_watermark_source" class="preview_img">
<img layer-src src="{:img($config[$scene_item['key']]['path'])}" class="img_prev" />
</div>
{/if}
</div>
<div class="operation">
<div>
<i title="图片预览" class="iconfont iconreview js-preview" style="margin-right: 20px;"></i>
<i title="删除图片" class="layui-icon layui-icon-delete js-delete"></i>
</div>
<div class="replace_img js-replace">点击替换</div>
</div>
<input type="hidden" name="shareImg_{$scene_item['key']}" lay-verify="required" value="{$config[$scene_item['key']]['path'] ?? ''}">
</div>
</div>
</div>
<div class="picture-introduce">支持PNG及JPG。图片长宽比是5:4不传使用默认截图</div>
<div class="bottom">
<i class="iconfont iconweixinxiaochengxu"></i>
<div class="mini-program">小程序</div>
</div>
</form>
</div>
</div>
{/foreach}
</div>
{else/}
<div class="no-data">暂无数据</div>
{/notempty}
<script>
let shareParam = {},
scene = '{:json_encode($scene)}',
config = '{:json_encode($config)}';
initData(); //初始化数据
function initData(){
scene = JSON.parse(scene);
config = JSON.parse(config);
scene.forEach((item,index) => {
var path = config.length != 0 && config[item.key].path ? config[item.key].path : '',
title = config.length != 0 && config[item.key].title ? config[item.key].title : item.title;
shareParam[item.key] = {
'key': item.key,
'path': path,
'title': title
};
//实例化图片上传
uploadImg(item.key);
});
}
function uploadImg(key){
new Upload({
elem: '#shareUpload_'+key,
callback: function(res) {
let key = this.elem.split('_')[1];
if(res.code > 0){
shareParam[key].path = res.data.pic_path;
$("input[name='shareImg_"+ key +"']").val(shareParam[key].path);
$.ajax({
type: "post",
url: ns.url("weapp://shop/weapp/share"),
data: shareParam[key],
dataType: 'JSON',
success: function(res) {
layer.msg(res.message);
},
});
}else{
layer.msg(res.message);
}
},
deleteCallback: function(res){
let key = this.elem.split('_')[1];
shareParam[key].path = '';
$("input[name='shareImg_"+ key +"']").val(shareParam[key].path);
$.ajax({
type: "post",
url: ns.url("weapp://shop/weapp/share"),
data: shareParam[key],
dataType: 'JSON',
success: function(res) {
layer.msg(res.message);
},
});
}
});
}
$('[name="share-title"]').change(function(){
var key = $(this).parents('.detail-item').attr("data-key");
shareParam[key].title = $(this).val();
$.ajax({
type: "post",
url: ns.url("weapp://shop/weapp/share"),
data: shareParam[key],
dataType: 'JSON',
success: function(res) {
layer.msg(res.message);
},
});
});
</script>

View File

@@ -0,0 +1,125 @@
<link rel="stylesheet" href="WEAPP_CSS/wx_access_statistics.css">
<script src="SHOP_JS/echarts.min.js"></script>
<div class="access-statistics">
<div>
<blockquote class="layui-quote-nm layui-elem-quote">用户分析/昨日</blockquote>
<ul class="access-api-list ">
<li class="access-api-item">
<div class="access-api-item-title">
<h3>新关注人数</h3>
</div>
<p class="access-api-itme-content">{if !empty($yesterday_user_data.new_user)}{$yesterday_user_data.new_user}{else/}0{/if}</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>取消关注人数</h3>
</div>
<p class="access-api-itme-content">{if !empty($yesterday_user_data.cancel_user)}{$yesterday_user_data.cancel_user}{else/}0{/if}</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>净增关注人数</h3>
</div>
<p class="access-api-itme-content">{if !empty($yesterday_user_data.net_growth_user)}{$yesterday_user_data.net_growth_user}{else/}0{/if}</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>累积关注人数</h3>
</div>
<p class="access-api-itme-content">{if !empty($yesterday_user_data.cumulate_user)}{$yesterday_user_data.cumulate_user}{else/}0{/if}</p>
</li>
</ul>
</div>
<div>
<blockquote class="layui-quote-nm layui-elem-quote">接口分析/昨日</blockquote>
<ul class="access-api-list">
<li class="access-api-item">
<div class="access-api-item-title">
<h3>调用次数</h3>
</div>
<p class="access-api-itme-content">{if !empty($yesterday_interface_data.callback_count)}{$yesterday_interface_data.callback_count}{else/}--{/if}</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>失败率</h3>
</div>
<p class="access-api-itme-content">{if !empty($yesterday_interface_data.fail_count)}{$yesterday_interface_data.fail_count}{else/}--{/if}</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>平均耗时(毫秒)</h3>
</div>
<p class="access-api-itme-content">{if !empty($yesterday_interface_data.callback_count) && !empty($yesterday_interface_data.total_time_cost)}{php}echo round($yesterday_interface_data['total_time_cost']/$yesterday_interface_data['callback_count'],2);{/php}{else/}--{/if}</p>
</li>
<li class="access-api-item">
<div class="access-api-item-title">
<h3>最大耗时(毫秒)</h3>
</div>
<p class="access-api-itme-content">{if !empty($yesterday_interface_data.max_time_cost)}{$yesterday_interface_data.max_time_cost}{else/}--{/if}</p>
</li>
</ul>
</div>
<div>
<blockquote class="layui-quote-nm layui-elem-quote">趋势图</blockquote>
<div class="layui-tab layui-tab-brief" lay-filter="chart_tab">
<ul class="layui-tab-title">
<li class="layui-this" lay-id="user">用户分析</li>
<li lay-id="interface">接口分析</li>
</ul>
<blockquote class="layui-elem-quote" style="margin-top:10px;" >
<span class="layui-breadcrumb" lay-separator="|" >
<a href="javascript:void(0)" class="layui-breadcrumb-item layui-breadcrumb-active" lay-util="week">最近7天</a>
<a href="javascript:void(0)" class="layui-breadcrumb-item" lay-util="month">最近30天</a>
</span>
</blockquote>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div id="user_chart" style="width: 100%;height:400px;"></div>
</div>
<div class="layui-tab-item" id="interface_main">
<div id="interface_chart" style="width: 100%;height:400px;"></div>
</div>
</div>
</div>
</div>
</div>
<script>
var is_render = true;
var date_type = "week";
layui.use(['element', 'util'], function(){
var element = layui.element,
util = layui.util;
element.on('tab(chart_tab)', function(){
if(this.getAttribute('lay-id') == "interface" && is_render){
is_render = false;
getInterfaceStatistics();
}
});
//按钮事件
util.event('lay-util', {
week: function(othis){
$(".layui-breadcrumb-item").removeClass("layui-breadcrumb-active");
$(othis).addClass("layui-breadcrumb-active");
date_type = "week";
if(is_render == false){
getInterfaceStatistics();
}
}
,month: function(othis){
$(".layui-breadcrumb-item").removeClass("layui-breadcrumb-active");
$(othis).addClass("layui-breadcrumb-active");
date_type = "month";
if(is_render == false){
getInterfaceStatistics();
}
}
});
});
</script>