初始上传

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

694
app/model/system/Addon.php Executable file
View File

@@ -0,0 +1,694 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use app\model\diy\Template;
use app\model\diy\Theme;
use app\model\system\Config as ConfigModel;
use app\model\web\DiyView as DiyViewModel;
use app\model\web\DiyViewLink;
use think\facade\Cache;
use think\facade\Db;
/**
* 插件表
*/
class Addon extends BaseModel
{
public $cache_model = 'cache_model_addon';
/**
* 获取单条插件信息
* @param array $condition
* @param string $field
*/
public function getAddonInfo($condition, $field = '*')
{
$addon_info = model('addon')->getInfo($condition, $field);
return $this->success($addon_info);
}
/**
* 获取插件列表
*
* @param array $condition
* @param string $field
* @param string $order
* @param string $limit
*/
public function getAddonList($condition = [], $field = '*', $order = '', $limit = null)
{
$addon_list = model('addon')->getList($condition, $field, $order, '', '', '', $limit);
return $this->success($addon_list);
}
/**
* 查询插件key数组
* @return array
*/
public function getAddonKeys()
{
$addon_data = $this->getAddonList([], 'name');
$addons = array_column($addon_data[ 'data' ], 'name');
return $addons;
}
/**
* 获取插件分页列表
* @param array $condition
* @param int $page
* @param int $page_size
* @param string $order
* @param string $field
* @return array
*/
public function getAddonPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = '*')
{
$list = model('addon')->pageList($condition, $field, $order, $page, $page_size);
return $this->success($list);
}
/**
* 获取所有插件
* @return array
*/
public function getAddonAllList()
{
//获取官网记录的所有数据
$upgrade_service = new Upgrade();
$data = $upgrade_service->getAuthPlugin();
if (isset($data[ 'code' ]) && $data[ 'code' ] >= 0) {
$temp_auth_addon_list = $data[ 'data' ];
} else {
$temp_auth_addon_list = [];
}
//以code为key组装正式数据
$auth_addon_list = [];
foreach ($temp_auth_addon_list as $key => $val) {
$auth_addon_list[ $val[ 'code' ] ] = $val;
}
//存在的插件
$existed_addons = array_map('basename', glob('addon/*', GLOB_ONLYDIR));
//已安装的插件
$installed_addon_array = model('addon')->getColumn([], 'name');
//初始化数据
$undownload_addons = [];
$uninstall_addons = [];
$install_addons = [];
//获取未下载插件
foreach ($auth_addon_list as $key => $val) {
$index = in_array($val['code'], $existed_addons);
if ($index === false) {
$undownload_addons[] = [
'name' => $val[ 'code' ],
'title' => $val[ 'goods_name' ],
'icon' => $val[ 'logo' ],
'description' => $val[ 'introduction' ],
'version' => $val[ 'last_online_version_name' ],
'download' => 1,
'auth' => true,
'update' => false
];
}
}
//获取已下载插件 区分已安装和为安装 是否需要升级 是否已授权
foreach ($existed_addons as $key => $val) {
$info_file_path = 'addon/' . $val . '/config/info.php';
if (file_exists($info_file_path)) {
$info = include_once $info_file_path;
$info[ 'icon' ] = 'addon/' . $val . '/icon.png';
$info[ 'download' ] = 0;
$info[ 'auth' ] = isset($auth_addon_list[ $val ]);
$info[ 'update' ] = isset($auth_addon_list[ $val ]) && $auth_addon_list[ $val ][ 'last_online_version_no' ] > $info[ 'version_no' ];
$info[ 'last_online_version_no' ] = isset($auth_addon_list[ $val ]) ? $auth_addon_list[ $val ][ 'last_online_version_no' ] : '';
if (!in_array($val, $installed_addon_array)) {
$uninstall_addons[] = $info;
} else {
$install_addons[] = $info;
}
}
}
return $this->success([
'uninstall' => array_merge($undownload_addons, $uninstall_addons),
'install' => $install_addons,
]);
}
/**
* 获取未安装的插件列表
*/
public function getUninstallAddonList()
{
$dirs = array_map('basename', glob('addon/*', GLOB_ONLYDIR));
$addon_names = model('addon')->getColumn([], 'name');
$addons = [];
foreach ($dirs as $key => $value) {
if (!in_array($value, $addon_names)) {
$info_name = 'addon/' . $value . '/config/info.php';
if (file_exists($info_name)) {
$info = include_once $info_name;
$info[ 'icon' ] = 'addon/' . $value . '/icon.png';
$addons[] = $info;
}
}
}
return $this->success($addons);
}
/*******************************************************************插件安装方法开始****************************************************/
/**
* 插件安装
*
* @param string $addon_name
*/
public function install($addon_name)
{
Db::startTrans();
try {
// 插件预安装
$res2 = $this->preInstall($addon_name);
if ($res2[ 'code' ] != 0) {
Db::rollback();
return $res2;
}
// 安装菜单
$res3 = $this->installMenu($addon_name);
if ($res3[ 'code' ] != 0) {
Db::rollback();
return $res3;
}
// 安装自定义模板
$res4 = $this->refreshDiyView($addon_name);
if ($res4[ 'code' ] != 0) {
Db::rollback();
return $res4;
}
// 添加插件入表
$addons_model = model('addon');
$addon_info = require 'addon/' . $addon_name . '/config/info.php';
$addon_info[ 'create_time' ] = time();
$addon_info[ 'icon' ] = 'addon/' . $addon_name . '/icon.png';
$data = $addons_model->add($addon_info);
if (!$data) {
Db::rollback();
return $this->error($data, 'ADDON_ADD_FAIL');
}
// 清理缓存
Cache::clear();
Db::commit();
return $this->success();
} catch (\Exception $e) {
// 清理缓存
Cache::clear();
Db::rollback();
return $this->error('', $e->getMessage());
}
}
/**
* 插件预安装
*/
private function preInstall($addon_name)
{
$class_name = "addon\\" . $addon_name . "\\event\\Install";
$install = new $class_name;
$res = $install->handle($addon_name);
if ($res[ 'code' ] != 0) {
return $res;
}
return $this->success();
}
/**
* 安装插件菜单
*/
private function installMenu($addon)
{
$menu = new Menu();
$menu->refreshMenu('shop', $addon);
return $this->success();
}
/**
* 刷新插件自定义页面配置
* @param $addon
* @param $site_id
* @return array
*/
public function refreshDiyView($addon)
{
try {
if (empty($addon)) {
$diy_view_file = 'config/diy_view.php';
} else {
$diy_view_file = 'addon/' . $addon . '/config/diy_view.php';
}
if (!file_exists($diy_view_file)) {
return $this->success();
}
$link_model = new DiyViewLink();
$diy_view_model = new DiyViewModel();
$diy_template_model = new Template();
$diy_theme_model = new Theme();
// 查询原模板组列表用于更新自定义页面的所属模板id
$diy_template_goods_list_old = $diy_template_model->getTemplateGoodsList([ [ 'addon_name', '=', $addon ] ], 'goods_id,name')[ 'data' ];
// 清空数据
$link_model->deleteLink([ [ 'addon_name', '=', $addon ] ]); // 链接
$diy_view_model->deleteUtil([ [ 'addon_name', '=', $addon ] ]); // 组件
$diy_template_model->deleteTemplate([ [ 'addon_name', '=', $addon ] ]); // 页面类型
$diy_theme_model->deleteTheme([ [ 'addon_name', '=', $addon ] ]); // 主题风格
$diy_template_model->deleteTemplateGoods([ [ 'addon_name', '=', $addon ] ]); // 模板组
$diy_template_model->deleteTemplateGoodsItem([ [ 'addon_name', '=', $addon ] ]); // 模板页面
$diy_view = require $diy_view_file;
// 自定义链接
if (isset($diy_view[ 'link' ])) {
$diy_view_link_data = $link_model->getViewLinkList($diy_view[ 'link' ], $addon);
if ($diy_view_link_data) {
model('link')->addList($diy_view_link_data);
}
}
// 自定义模板组件
if (isset($diy_view[ 'util' ])) {
$diy_view_util_data = [];
foreach ($diy_view[ 'util' ] as $k => $v) {
$util_item = [
'name' => $v[ 'name' ], // 组件标识
'title' => $v[ 'title' ], // 组件名称
'type' => $v[ 'type' ], // 组件类型SYSTEM基础组件PROMOTION营销组件EXTEND扩展组件
'value' => $v[ 'value' ], // 组件数据结构json格式
'sort' => $v[ 'sort' ],
'support_diy_view' => $v[ 'support_diy_view' ] ?? '', // 支持的自定义页面(为空表示公共组件都支持)
'addon_name' => $addon,
'max_count' => $v[ 'max_count' ] ?? 0, // 限制添加次数0表示可以无限添加该组件
'is_delete' => $v[ 'is_delete' ] ?? 0, // 组件是否可以删除0 允许1 禁用
'icon' => $v[ 'icon' ] ?? '' // 组件字体图标
];
$diy_view_util_data[] = $util_item;
}
if ($diy_view_util_data) {
$diy_view_model->addUtilList($diy_view_util_data);
}
}
// 自定义模板页面类型
if (isset($diy_view[ 'template' ]) && !empty($diy_view[ 'template' ])) {
$template_data = [];
foreach ($diy_view[ 'template' ] as $k => $v) {
// 检测防重复
$count = $diy_template_model->getTemplateCount([ [ 'name', '=', $v[ 'name' ] ] ])[ 'data' ];
if ($count == 0) {
$template_data[] = [
'title' => $v[ 'title' ], // 模板名称
'name' => $v[ 'name' ], // 模板标识
'page' => $v[ 'path' ], // 页面路径
'addon_name' => $addon,
'value' => $v[ 'value' ] ?? '',
'rule' => isset($v[ 'rule' ]) ? json_encode($v[ 'rule' ]) : '',
'sort' => $v[ 'sort' ] ?? 0
];
}
}
if (!empty($template_data)) {
$diy_template_model->addTemplateList($template_data);
}
}
// 主题风格配色
if (isset($diy_view[ 'theme' ]) && !empty($diy_view[ 'theme' ])) {
$theme_data = [];
foreach ($diy_view[ 'theme' ] as $k => $v) {
// 检测防重复
$count = $diy_theme_model->getThemeCount([ [ 'name', '=', $v[ 'name' ] ] ])[ 'data' ];
if ($count == 0) {
$theme_value = $v;
unset($theme_value[ 'title' ], $theme_value[ 'name' ], $theme_value[ 'main_color' ], $theme_value[ 'aux_color' ], $theme_value[ 'preview' ]);
$theme_data[] = [
'title' => $v[ 'title' ],
'name' => $v[ 'name' ],
'addon_name' => $addon,
'main_color' => $v[ 'main_color' ],
'aux_color' => $v[ 'aux_color' ],
'preview' => implode(',', $v[ 'preview' ]),
'color_img' => $v[ 'color_img' ],
'value' => json_encode($theme_value),
];
}
}
if (!empty($theme_data)) {
$diy_theme_model->addThemeList($theme_data);
}
}
// 模板信息
$diy_goods_id = 0;
if (isset($diy_view[ 'info' ]) && !empty($diy_view[ 'info' ])) {
$template_goods_data = [
'title' => $diy_view[ 'info' ][ 'title' ], // 模板名称
'name' => $diy_view[ 'info' ][ 'name' ], // 模板标识
'addon_name' => $addon,
'cover' => $diy_view[ 'info' ][ 'cover' ], // 模板封面图
'preview' => $diy_view[ 'info' ][ 'preview' ], // 模板预览图
'desc' => $diy_view[ 'info' ][ 'desc' ], // 模板描述
];
// 检测防重复
$count = $diy_template_model->getTemplateGoodsCount([ [ 'name', '=', $template_goods_data[ 'name' ] ] ])[ 'data' ];
if ($count == 0) {
$diy_goods_id = $diy_template_model->addTemplateGoods($template_goods_data)[ 'data' ];
}
if (!empty($diy_template_goods_list_old)) {
foreach ($diy_template_goods_list_old as $k => $v) {
// 更新自定义页面的所属模板id
// $diy_view_model->editSiteDiyView([
// 'template_id' => $diy_goods_id,
// ], [
// [ 'name', 'like', '%DIY_VIEW_RANDOM_%' ],
// [ 'template_id', '=', $v[ 'goods_id' ] ]
// ]);
// 更新店铺关联模板关系id
$diy_template_model->editSiteDiyTemplate([
'template_goods_id' => $diy_goods_id,
], [
[ 'addon_name', '=', $addon ],
[ 'name', '=', $v[ 'name' ] ],
[ 'template_goods_id', '=', $v[ 'goods_id' ] ]
]);
}
}
} else {
// 模板不存在,则清除店铺与模板之间的关系
$diy_template_model->deleteSiteDiyTemplate([ [ 'addon_name', '=', $addon ] ]); // 模板页面关联关系
}
// 自定义页面数据
if (isset($diy_view[ 'data' ]) && !empty($diy_view[ 'data' ])) {
$goods_item_id = 0;
foreach ($diy_view[ 'data' ] as $k => $v) {
$goods_item_data = [
'goods_id' => $diy_goods_id, // 模板组id
'title' => $v[ 'title' ], // 名称
'addon_name' => $addon,
'name' => $v[ 'name' ], // 所属页面(首页、分类,空为微页面)
'value' => json_encode($v[ 'value' ]), // 模板数据
'create_time' => time()
];
$item_id = $diy_template_model->addTemplateGoodsItem($goods_item_data)[ 'data' ];
// 默认装修第一个页面
if ($k == 0) {
$goods_item_id = $item_id;
}
}
$diy_template_model->editTemplateGoods([ 'goods_item_id' => $goods_item_id ], [ [ 'goods_id', '=', $diy_goods_id ] ]);
// 更新页面的所属模板id
$diy_template_goods_item_list = $diy_template_model->getTemplateGoodsItemList([ [ 'addon_name', '=', $addon ] ], 'goods_id,goods_item_id,name')[ 'data' ];
if (!empty($diy_template_goods_item_list)) {
foreach ($diy_template_goods_item_list as $k => $v) {
$diy_view_model->editSiteDiyView([
'template_id' => $v[ 'goods_id' ],
'template_item_id' => $v[ 'goods_item_id' ]
], [
[ 'name', '=', $v[ 'name' ] ],
[ 'addon_name', '=', $addon ]
]);
}
}
}
return $this->success();
} catch (\Exception $e) {
return $this->error('', $e->getMessage());
}
}
/**************************************************************插件安装结束*********************************************************/
/**************************************************************插件卸载开始*********************************************************/
public function uninstall($addon_name)
{
Db::startTrans();
try {
$addon_info = model('addon')->getInfo([ [ 'name', '=', $addon_name ] ], '*');
// 插件预卸载
$res1 = $this->preUninstall($addon_name);
if ($res1[ 'code' ] != 0) {
Db::rollback();
return $res1;
}
// 卸载菜单
$res2 = $this->uninstallMenu($addon_name);
if ($res2[ 'code' ] != 0) {
Db::rollback();
return $res2;
}
$res3 = $this->uninstallDiyView($addon_name);
if ($res3[ 'code' ] != 0) {
Db::rollback();
return $res3;
}
$delete_res = model('addon')->delete([
[ 'name', '=', $addon_name ]
]);
if ($delete_res === false) {
Db::rollback();
return $this->error();
}
//清理缓存
Cache::clear();
Db::commit();
return $this->success();
} catch (\Exception $e) {
//清理缓存
Cache::clear();
Db::rollback();
return $this->error('', $e->getMessage());
}
}
/**
* 插件预卸载
*/
private function preUninstall($addon_name)
{
$class_name = "addon\\" . $addon_name . "\\event\\UnInstall";
$install = new $class_name;
$res = $install->handle($addon_name);
return $res;
}
/**
* 卸载插件菜单
*/
private function uninstallMenu($addon_name)
{
$res = model('menu')->delete([
[ 'addon', '=', $addon_name ]
]);
return $this->success($res);
}
/**
* 卸载自定义数据(清除:自定义链接、组件、主题风格、模板页面类型、模板组、模板组页面、店铺拥有的模板组、店铺自定义模板)
* @param $addon_name
* @return array
*/
private function uninstallDiyView($addon_name)
{
model('link')->delete([ [ 'addon_name', '=', $addon_name ] ]); // 自定义链接
model('diy_view_util')->delete([ [ 'addon_name', '=', $addon_name ] ]); // 自定义组件
model('diy_theme')->delete([ [ 'addon_name', '=', $addon_name ] ]); // 主题风格
model('diy_template')->delete([ [ 'addon_name', '=', $addon_name ] ]); // 模板页面类型
model('diy_template_goods')->delete([ [ 'addon_name', '=', $addon_name ] ]); // 模板组
model('diy_template_goods_item')->delete([ [ 'addon_name', '=', $addon_name ] ]); // 模板组页面
model('site_diy_template')->delete([ [ 'addon_name', '=', $addon_name ] ]); // 店铺拥有的模板组
// model('site_diy_view')->delete([ [ 'addon_name', '=', $addon_name ] ]); // 店铺自定义模板
return $this->success();
}
/***************************************************************插件卸载结束********************************************************/
/************************************************************* 安装全部插件 start *************************************************************/
/**
* 安装全部插件
*/
public function installAllAddon()
{
$addon_list_result = $this->getUninstallAddonList();
$addon_list = $addon_list_result['data'];
foreach ($addon_list as $k => $v) {
$item_result = $this->install($v['name']);
if ($item_result['code'] < 0)
return $item_result;
}
return $this->success();
}
/************************************************************* 安装全部插件 end *************************************************************/
/**
* 刷新应用插件
* @return array
*/
public function cacheAddon()
{
//刷新插件信息
$addon_list = model('addon')->getList();
try {
foreach ($addon_list as $k => $v) {
$data = require 'addon/' . $v[ 'name' ] . '/config/info.php';
if (empty($data)) {
$data = [];
}
$data[ 'create_time' ] = time();
$data[ 'icon' ] = 'addon/' . $v[ 'name' ] . '/icon.png';
model('addon')->update($data, [ 'name' => $v[ 'name' ] ]);
}
return $this->success();
} catch (\Exception $e) {
return $this->error('', $e->getMessage());
}
}
/**
* 刷新所有插件菜单
* @return array
*/
public function cacheAddonMenu()
{
$addon_list = model('addon')->getList([], 'name');
$menu_model = new Menu();
foreach ($addon_list as $k => $v) {
$addon_menu_res = $menu_model->refreshMenu('shop', $v[ 'name' ]);
// 刷新收银端权限
$menu_model->refreshCashierAuth($v[ 'name' ]);
}
return $this->success();
}
/**
* 获取插件快捷菜单配置
* @param $site_id
* @param string $app_module
* @return array
*/
public function getAddonQuickMenuConfig($site_id, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'COMMON_ADDON' ] ]);
if (!empty($res[ 'data' ][ 'value' ])) {
if (!empty($res[ 'data' ][ 'value' ][ 'promotion' ])) {
$res[ 'data' ][ 'value' ][ 'promotion' ] = explode(',', $res[ 'data' ][ 'value' ][ 'promotion' ]);
foreach ($res[ 'data' ][ 'value' ][ 'promotion' ] as $k => $v) {
if (empty($v)) {
unset($res[ 'data' ][ 'value' ][ 'promotion' ][ $k ]);
} elseif (!empty($v) && addon_is_exit($v) == 0) {
unset($res[ 'data' ][ 'value' ][ 'promotion' ][ $k ]);
}
}
$res[ 'data' ][ 'value' ][ 'promotion' ] = array_values($res[ 'data' ][ 'value' ][ 'promotion' ]);
} else {
$res[ 'data' ][ 'value' ][ 'promotion' ] = [];
}
if (!empty($res[ 'data' ][ 'value' ][ 'tool' ])) {
$res[ 'data' ][ 'value' ][ 'tool' ] = explode(',', $res[ 'data' ][ 'value' ][ 'tool' ]);
foreach ($res[ 'data' ][ 'value' ][ 'tool' ] as $k => $v) {
if (empty($v)) {
unset($res[ 'data' ][ 'value' ][ 'tool' ][ $k ]);
} elseif (!empty($v) && addon_is_exit($v) == 0) {
unset($res[ 'data' ][ 'value' ][ 'tool' ][ $k ]);
}
}
$res[ 'data' ][ 'value' ][ 'tool' ] = array_values($res[ 'data' ][ 'value' ][ 'tool' ]);
} else {
$res[ 'data' ][ 'value' ][ 'tool' ] = [];
}
} else {
$res[ 'data' ][ 'value' ] = [
'promotion' => [],
'tool' => []
];
}
return $res;
}
/**
* 设置插件快捷菜单配置
* @param $data
* @return array
*/
public function setAddonQuickMenuConfig($data)
{
$condition = [
[ 'site_id', '=', $data[ 'site_id' ] ],
[ 'app_module', '=', $data[ 'app_module' ] ],
[ 'config_key', '=', 'COMMON_ADDON' ]
];
$config = new ConfigModel();
$value = $config->getConfig($condition)[ 'data' ][ 'value' ];
$addon_array = empty($value) ? [] : explode(',', $value[ $data[ 'type' ] ] ?? '');
if (in_array($data[ 'addon' ], $addon_array)) {
$addon_array = array_diff($addon_array, [ $data[ 'addon' ] ]);
} else {
array_push($addon_array, $data[ 'addon' ]);
}
$value[ $data[ 'type' ] ] = implode(',', $addon_array);
return $config->setConfig($value, '常用功能设置', 1, $condition);
}
/**
* 插件是否存在
* @return array
*/
public function addonIsExist()
{
$existed_addons = array_map('basename', glob('addon/*', GLOB_ONLYDIR));
$installed_addons = model('addon')->getColumn([], 'name');
$res = [];
foreach($existed_addons as $addon){
$res[$addon] = in_array($addon, $installed_addons) ? 1 : 0;
}
return $res;
}
}

157
app/model/system/AddonQuick.php Executable file
View File

@@ -0,0 +1,157 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use app\model\system\Upgrade as UpgradeModel;
class AddonQuick extends BaseModel
{
/**
* 添加快捷方式
* @param $data
* @return array
*/
public function addAddonQuickMode($data)
{
//判断是否已存在该插件
$addon_count = model('addon_quick')->getCount([ [ 'name', '=', $data[ 'name' ] ] ]);
if ($addon_count > 0) {
return $this->error('', '该插件已添加快捷方式,请不要重复添加');
}
$data[ 'create_time' ] = time();
$res = model('addon_quick')->add($data);
return $this->success($res);
}
/**
* 删除快捷方式
* @param array $condition
* @return array
*/
public function deleteAddonQuickMode($condition = [])
{
$res = model('addon_quick')->delete($condition);
return $this->success($res);
}
/**
* 获取快捷方式信息
* @param array $condition
* @param string $field
* @return array
*/
public function getAddonQuickModeInfo($condition = [], $field = '*')
{
$info = model('addon_quick')->getInfo($condition, $field);
return $this->success($info);
}
/**
* 获取快捷方式类表
* @param array $condition
* @param int $page
* @param int $page_size
* @param string $order
* @param string $field
* @return array
*/
public function getAddonQuickModeList($condition = [], $order = '', $field = '*')
{
$list = model('addon_quick')->getList($condition, $field, $order);
return $this->success($list);
}
/**
* 判断快捷方式插件是否已安装
* @param $uninstall
* @param $install
* @return array
*/
public function isInstallAddonQuick($uninstall, $install)
{
//未安装的插件
$uninstall_name_arr = array_column($uninstall, 'name');
//已安装的插件
$install_name_arr = array_column($install, 'name');
//获取快捷方式插件
$addon_quick_list = $this->getAddonQuickModeList([], '', '*');
if (empty($addon_quick_list[ 'data' ])) {
return [
'uninstall' => $uninstall,
'install' => $install
];
} else {
foreach ($addon_quick_list[ 'data' ] as $k => $v) {
//判断是否在已安装的插件中
if (!in_array($v[ 'name' ], $install_name_arr)) {
//判断是否在未安装的插件中
if (empty($uninstall_name_arr) || !in_array($v[ 'name' ], $uninstall_name_arr)) {
$v[ 'is_quick' ] = 1;
$v[ 'download' ] = 1;
$uninstall[] = $v;
}
}
}
return [
'uninstall' => $uninstall,
'install' => $install
];
}
}
/**
* 根据插件类型获取官网插件
* @param $addon_list
* @param $type
* @return array
*/
public function getAddonQuickByAddonType($addon_list, $type)
{
//获取官网所有插件
$upgrade_model = new UpgradeModel();
$website_addon_list = $upgrade_model->getPluginGoodsList();
$arr = [];
if (empty($website_addon_list)) {
return $arr;
} else {
$addon_name_arr = array_column($addon_list, 'name');
foreach ($website_addon_list as $k => $v) {
if ($v[ 'type_mark' ] == $type) {
if (empty($addon_list)) {
$arr[] = $v;
} else {
//判断是否在插件中
if (!in_array($v[ 'addon_goods_key' ], $addon_name_arr)) {
$arr[] = $v;
}
}
}
}
return $arr;
}
}
}

426
app/model/system/Address.php Executable file
View File

@@ -0,0 +1,426 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use extend\api\HttpClient;
use think\facade\Cache;
use app\model\BaseModel;
use think\facade\Db;
use think\helper\Str;
/**
* 地区表
*/
class Address extends BaseModel
{
/**
* 获取地区列表
* @param unknown $condition
* @param string $field
* @param string $order
* @param string $limit
* @return multitype:string mixed
*/
public function getAreaList($condition = [], $field = '*', $order = '', $limit = null)
{
$area_list = model('area')->getList($condition, $field, $order, $limit);
return $this->success($area_list);
}
/**
* 获取地区详情
*/
public function getAreaInfo($circle)
{
$info = model('area')->getInfo([['id', '=', $circle]]);
return $this->success($info);
}
/**
* 获取地区数量
* @param $condition
* @return array
*/
public function getAreaCount($condition)
{
$count = model('area')->getCount($condition);
return $this->success($count);
}
/**
* 获取省市子项
*/
public function getAreas($circle = 0)
{
$list = model('area')->getList([['pid', '=', $circle]]);
return $this->success($list);
}
/**
* 获取整理后的地址
*/
public function getAddressTree($level = 4)
{
$condition = [['level', '<=', $level]];
$json_condition = json_encode($condition);
$cache = Cache::get('area_getAddressTree' . $json_condition);
if (!empty($cache)) {
return $this->success($cache);
}
$area_list = $this->getAreaList($condition, 'id, pid, name, level', 'id asc')['data'];
//组装数据
$refer_list = [];
foreach ($area_list as $key => $val) {
$refer_list[$val['level']][$val['pid']]['child_list'][$val['id']] = $area_list[$key];
if (isset($refer_list[$val['level']][$val['pid']]['child_num'])) {
$refer_list[$val['level']][$val['pid']]['child_num'] += 1;
} else {
$refer_list[$val['level']][$val['pid']]['child_num'] = 1;
}
}
Cache::tag('area')->set('area_getAddressTree' . $json_condition, $refer_list);
return $this->success($refer_list);
}
/**
* 获取地址树结构
* @param $level
* @return array
*/
public function getAddressTreeList($level)
{
$condition = [['level', '<=', $level]];
$json_condition = json_encode($condition);
$cache = Cache::get('area_getAddressTreeList' . $json_condition);
if (!empty($cache)) {
return $this->success($cache);
}
$area_list = $this->getAreaList($condition, 'id, pid, name', 'id asc')['data'];
$tree = $this->toTree($area_list);
Cache::tag('area')->set('area_getAddressTreeList' . $json_condition, $tree);
return $this->success($tree);
}
/**
* 列表转树结构
* @param $array
* @param int $pid
* @return array
*/
public function toTree($array, $pid = 0)
{
$tree = array();
foreach ($array as $key => $value) {
if ($value['pid'] == $pid) {
$value['children'] = $this->toTree($array, $value['id']);
$tree[] = $value;
}
}
return $tree;
}
/**
* 获取地址
* @param array $condition
* @param string $field
* @return multitype:number unknown
*/
public function getAreasInfo(array $condition, string $field = '*')
{
$info = model('area')->getInfo($condition, $field);
if ($info) return $this->success($info);
return $this->error();
}
/**
* 通过地址查询
*/
public function getAddressByLatlng($post_data)
{
$qq_map = new \app\model\map\QqMap();
$res = $qq_map->locationToDetail([
'location' => $post_data['latlng'],
]);
if ($res['status'] == 0) {
$return_array = $res['result']['address_component'] ?? [];
$return_data = array(
'province' => $return_array['province'] ?? '',
'city' => $return_array['city'] ?? '',
'district' => $return_array['district'] ?? '',
'address' => $return_array['street'] ?? '',
'full_address' => $res['result']['address'] ?? '',
'town_info' => $res['result']['address_reference']['town'] ?? null,
);
return $this->success($return_data);
} else {
return $this->error([], $res['message']);
}
}
/**
* 通过地址查询
*/
public function getAddressByName($address)
{
$qq_map = new \app\model\map\QqMap();
$res = $qq_map->addressToDetail([
'address' => $address,
]);
if ($res['status'] == 0) {
$return_array = $res['result']['location'] ?? [];
$return_data = array(
'longitude' => $return_array['lng'] ?? '',
'latitude' => $return_array['lat'] ?? '',
);
return $this->success($return_data);
} else {
return $this->error([], $res['message']);
}
}
/**
* 编辑地区
* @param $data
* @return array
*/
public function saveArea($data)
{
$count = model('area')->getCount([['id', '=', $data['id']]]);
if ($count) {
$res = model('area')->update($data, [['id', '=', $data['id']]]);
} else {
$res = model('area')->add($data);
}
if ($res) {
Cache::clear('area');
return $this->success($res);
}
return $this->error();
}
/**
* 删除地区
* @param $id
* @param $level
* @return array
*/
public function deleteArae($id, $level)
{
switch ((int)$level) {
case 1:
$child = model('area')->getColumn([['pid', '=', $id]], 'id');
if (empty($child)) {
$condition = [['id', '=', $id], ['level', '=', $level]];
} else {
$child = implode(',', $child);
$condition = [['', 'exp', Db::raw("(id = $id AND level = $level) OR (id in ($child) AND level = 2) OR (pid in ($child) AND level = 3)")]];
}
break;
case 2:
$condition = [['', 'exp', Db::raw("(id = $id AND level = 2) OR (pid = $id AND level = 3)")]];
break;
case 3:
$condition = [['id', '=', $id], ['level', '=', $level]];
break;
}
$res = model('area')->delete($condition);
if ($res) {
Cache::clear('area');
return $this->success($res);
}
return $this->error();
}
/**
* 解析地址字符串,匹配系统地址库
* @param $address
* @return array
*/
public function analysesAddress($address): array
{
$res = $this->analysesAddressByTaobao($address); //匹配淘宝,京东地址
if($res['code'] == 0){
$address = $res['data']['address'];
}else{
$address = $this->addressReplace($address); //去除特定字符
$pdd_res = $this->analysesAddressByPdd($address); //匹配拼多多地址
$res['data'] = array_merge($pdd_res['data'],$res['data']);
if($pdd_res['code'] == 0){
$address = $res['data']['address'];
}else{
$other_res = $this->analysesAddressByThird($address); //无固定格式
$res['data'] = array_merge($other_res['data'],$res['data']);
if ($other_res['code'] == 0){
$address = $res['data']['address'];
}
}
}
$mobile = $res['data']['mobile'] ?? '';
$name = $res['data']['name'] ?? '';
$detail = $res['data']['detail'] ?? '';
$qq_map = new \app\model\map\QqMap();
if(!empty($address)){
$res = $qq_map->addressToDetail([
'address' => $address.$detail,
]);
if ($res['status'] == 0) {
$lng = $res['result']['location']['lng'] ?? '';
$lat = $res['result']['location']['lat'] ?? '';
$return_array = $res['result']['address_components'] ?? [];
$province = $return_array['province'] ?? '';
$city = $return_array['city'] ?? '';
$district = $return_array['district'] ?? '';
if (empty($mobile) && empty($name) && empty($province)) {
return $this->error([], '解析有误,请检查格式是否正确');
}
$province_id = model('area')->getValue([['name', 'like', "%" . $province . '%'], ['level', '=', 1]], 'id');
if (!empty($province_id) && !empty($city)) {
$city_id = model('area')->getValue([['name', 'like', "%" . $city . '%'], ['pid', '=', $province_id], ['level', '=', 2]], 'id');
}
if (!empty($city_id) && !empty($district)) {
$district_id = model('area')->getValue([['name', 'like', "%" . $district . '%'], ['pid', '=', $city_id], ['level', '=', 3]], 'id');
}
if(empty($detail)){
$province_temp = str_replace('省','',$province);
$city_temp = str_replace('市','',$city);
$district_temp = str_replace('区','',$district);
$address = $this->removePrefix($address, $province);
$address = $this->removePrefix($address, $province_temp);
$detail =str_replace([$province, $city,$district], ['','',''], $address);
$detail =str_replace([$province_temp, $city_temp,$district_temp], ['','',''], $detail);
}
}else{
if (empty($mobile) && empty($name) ) {
return $this->error([], '解析有误,请检查格式是否正确');
}
}
}else{
if (empty($mobile) && empty($name) ) {
return $this->error([], '解析有误,请检查格式是否正确');
}
}
return $this->success([
'name'=>$name,
'mobile'=>$mobile,
'province_id' => $province_id ?? '',
'city_id' => $city_id ?? '',
'district_id' => $district_id ?? '',
'province_name' => $province ?? '',
'city_name' => $city ?? '',
'district_name' => $district ?? '',
'detail' => $detail,
'lng' => $lng ?? '',
'lat' => $lat ?? '',
]);
}
public function analysesAddressByTaobao($address_str)
{
$pattern = [
'name' => '/ ^\s*(?:收件人|收货人|姓名)\s*[:]\s*(?<name>.*)\s*/ux',
'mobile' => '/ ^\s*手机(?:号码|号)\s*[:]\s* (?<phone>1[3-9]\d{9})\s* /ux',
'address' => '/ ^\s*所在地区\s*[:]\s* (?<region>.*)\s* /ux',
'detail' => '/ ^\s*详细地址\s*[:]\s* (?<detail>.*)\s* /ux',
];
$address_str_split = preg_split('/\r\n?|\n/', $address_str);
$res = [];
foreach($address_str_split as $val){
if(preg_match($pattern['name'], $val, $matches)){
$res['name'] = $matches['name'];
}elseif(preg_match($pattern['mobile'], $val, $matches)){
$res['mobile'] = $matches['phone'];
}elseif(preg_match($pattern['address'], $val, $matches)){
$res['address'] = $matches['region'];
}elseif(preg_match($pattern['detail'], $val, $matches)){
$res['detail'] = $matches['detail'];
}
}
if(count($res) < 4){
return $this->error($res);
}
return $this->success($res);
}
public function analysesAddressByPdd($address_str)
{
$address_str = preg_replace('/\s+/ux', ' ', $address_str);
$address_arr = explode(" ", $address_str);
if(count($address_arr) < 3){
return $this->error([]);
}
$patterns = [
'address' => '/(?<region>.*?(?:省|自治区|直辖市|市).*?(?:市|自治州|地区).*?(?:区|县|旗|市))/u',
'mobile' => '/(?<mobile>1[2-9]\d{9})/', // 11位手机号
'name' => '/^(?<name>[^\d\s]+)|[^\d\s]+$/u', // 姓名(不含数字和空格)
];
$result = [];
// 分别匹配各个部分
foreach ($patterns as $key => $pattern) {
foreach ($address_arr as $key1=> $str){
if (preg_match($pattern, $str, $matches)) {
if($key == 'address' && isset($address_arr[$key1+1])){
//如果地址中有详细地址则保存到detail中
$result['detail'] = $address_arr[$key1+1];
unset($address_arr[$key1+1]);
}
unset($address_arr[$key1]);
$result[$key] = trim($str);
}
}
}
if(isset($result['detail']) && empty($address_arr)){
return $this->success($result);
}
return $this->error($result);
}
public function analysesAddressByThird($address_str){
$patterns = [
'/ ^\s*手机(?:号码|号)\s*[:]\s* (?<phone>1[3-9]\d{9})\s* /ux',
// 规则1姓名 + 电话 + 地址
'/^(?<name>[\u4e00-\u9fa5·]+)\s+(?<mobile>\d{11}|0\d{2,3}-?\d{7,9})\s+(?<address>.+)$/u',
// 规则2地址 + 姓名 + 电话
'/^(?<address>.+省?.+区)\s+(?<name>[\u4e00-\u9fa5·]+)\s+(?<mobile>\d{11})$/u',
'/^(?<name>[^\d]+)(?<mobile>1[3-9]\d{9})(?<address>[^\n]*)(?<detail>.*)$/u',
];
foreach ($patterns as $pattern) {
if (preg_match($pattern, $address_str, $matches)) {
$res = [
'name' => $matches['name'] ?? '',
'mobile' => $matches['mobile'] ?? '',
'address' => $matches['address'] ?? '',
];
return $this->success($res);
}
}
return $this->error([]);
}
public function removePrefix($str, $delimiter = "_") {
$pos = strpos($str, $delimiter);
return ($pos !== false) ? substr($str, $pos + strlen($delimiter)) : $str;
}
public function addressReplace($address){
return str_replace(['所在地区','详细地址',':'],['','',''],trim($address,' '));
}
}

53
app/model/system/Api.php Executable file
View File

@@ -0,0 +1,53 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\system\Config as ConfigModel;
use app\model\BaseModel;
/**
* 接口api配置
*/
class Api extends BaseModel
{
/***************************************************************接口api 开始********************************************************/
/**
* 获取api配置
* @param int $site_id
* @param string $app_module
* @return array
*/
public function getApiConfig($site_id = 1, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'API_CONFIG' ] ]);
$res[ 'data' ][ 'value' ][ 'long_time' ] = $res[ 'data' ][ 'value' ][ 'long_time' ] ?? 48;
return $res;
}
/**
* 设置api配置
* @param $data
* @param $is_use
* @param int $site_id
* @param string $app_module
* @return array
*/
public function setApiConfig($data, $is_use, $site_id = 1, $app_module = 'shop')
{
$config = new ConfigModel();
$res = $config->setConfig($data, 'api配置', $is_use, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'API_CONFIG' ] ]);
return $res;
}
/***************************************************************接口api 结束********************************************************/
}

154
app/model/system/Config.php Executable file
View File

@@ -0,0 +1,154 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use think\facade\Cache;
use app\model\BaseModel;
/**
* 系统配置类
*/
class Config extends BaseModel
{
/**
* 配置系统配置项
* @param array $value
* @param string $config_desc
* @param int $is_use
* @param array $condition
*/
public function setConfig($value, $config_desc, $is_use, $condition)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$app_module = $check_condition['app_module'] ?? '';
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$config_key = $check_condition['config_key'] ?? '';
if (empty($config_key)) {
return $this->error('', 'REQUEST_CONFIG_KEY');
}
$data = $check_condition;
$data[ 'value' ] = json_encode($value);
$data[ 'config_desc' ] = $config_desc;
$data[ 'is_use' ] = $is_use;
$json_condition = json_encode($condition);
$config_model = model('config');
$info = $config_model->getInfo($condition, 'id');
Cache::tag('config')->clear();
Cache::tag('config')->set('CONFIG_' . $json_condition, '');
if (empty($info)) {
$data[ 'create_time' ] = time();
$res = $config_model->add($data);
} else {
$data[ 'modify_time' ] = time();
$res = $config_model->update($data, $condition);
}
return $this->success($res);
}
/**
* 获取系统配置信息
* @param array $condition
*/
public function getConfig($condition)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$app_module = $check_condition['app_module'] ?? '';
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$config_key = $check_condition['config_key'] ?? '';
if (empty($config_key)) {
return $this->error('', 'REQUEST_CONFIG_KEY');
}
$info = model('config')->getInfo($condition, 'site_id, app_module, config_key, value, config_desc, is_use, create_time, modify_time');
if (!empty($info)) {
$info[ 'value' ] = json_decode($info[ 'value' ], true);
} else {
$info = [
'site_id' => $site_id,
'app_module' => $app_module,
'config_key' => $config_key,
'value' => [],
'config_desc' => '',
'is_use' => 0,
'create_time' => 0,
'modify_time' => 0
];
}
return $this->success($info);
}
/**
* 修改配置项的使用状态
* @param int $is_use
* @param array $condition
*/
public function modifyConfigIsUse($is_use, $condition)
{
$json_condition = json_encode($condition);
$config = model('config')->getInfo($condition);
if (!empty($config)) {
//配置过
$res = model('config')->update([ 'is_use' => $is_use ], $condition);
Cache::tag('config')->set('CONFIG_' . $json_condition, '');
return $this->success($res);
} else {
return $this->error('', 'CONFIG_NOT_EXIST');
}
}
/**
* 获取系统信息
*/
public function getSystemConfig()
{
$system_config[ 'os' ] = php_uname(); // 服务器操作系统
$system_config[ 'server_software' ] = $_SERVER[ 'SERVER_SOFTWARE' ]; // 服务器环境
$system_config[ 'upload_max_filesize' ] = @ini_get('file_uploads') ? ini_get('upload_max_filesize') : 'unknow'; // 文件上传限制
$system_config[ 'gd_version' ] = gd_info()[ 'GD Version' ]; // GD图形处理版本
$system_config[ 'max_execution_time' ] = ini_get('max_execution_time') . '秒'; // 最大执行时间
$system_config[ 'port' ] = $_SERVER[ 'SERVER_PORT' ]; // 端口
$system_config[ 'dns' ] = $_SERVER[ 'HTTP_HOST' ]; // 服务器域名
$system_config[ 'php_version' ] = PHP_VERSION; // php版本
$system_config[ 'sockets' ] = extension_loaded('sockets'); //是否支付sockets
$system_config[ 'openssl' ] = extension_loaded('openssl'); //是否支付openssl
$system_config[ 'curl' ] = function_exists('curl_init'); // 是否支持curl功能
$system_config[ 'upload_dir_jurisdiction' ] = check_dir_iswritable(realpath('./upload') . DIRECTORY_SEPARATOR); // upload目录读写权限
$system_config[ 'runtime_dir_jurisdiction' ] = check_dir_iswritable(realpath('./runtime') . DIRECTORY_SEPARATOR); // runtime目录读写权限
$system_config[ 'fileinfo' ] = extension_loaded('fileinfo'); //是否支付fileinfo
return $this->success($system_config);
}
/**
* 删除配置
* @param $condition
*/
public function deleteConfig($condition)
{
$res = model('config')->delete($condition);
$this->success($res);
}
}

316
app/model/system/Cron.php Executable file
View File

@@ -0,0 +1,316 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\dict\system\ScheduleDict;
use app\model\BaseModel;
use think\facade\Cache;
use think\facade\Log;
use think\facade\Queue;
use think\facade\Db;
/**
* 计划任务管理
* @author Administrator
*
*/
class Cron extends BaseModel
{
//任务类型
const TYPE_FIXED = 1;//定时
const TYPE_LOOP = 2;//循环
//最大错误次数
protected $max_error_num = 3;
public $time_diff = 60;//默认半个小时检测一次
/**
* 添加计划任务
* @param int $type 任务类型 1.固定任务 2.循环任务
* @param int $period 执行周期
* @param string $name 任务名称
* @param string $event 执行事件
* @param int $execute_time 待执行时间
* @param int $relate_id 关联id
* @param int $period_type 周期类型
*/
public function addCron($type, $period, $name, $event, $execute_time, $relate_id, $period_type = 0)
{
$data = [
'type' => $type,
'period' => $period,
'period_type' => $period_type,
'name' => $name,
'event' => $event,
'execute_time' => $execute_time,
'relate_id' => $relate_id,
'create_time' => time()
];
$res = model('cron')->add($data);
return $this->success($res);
}
/**
* 删除计划任务
* @param $condition
* @return array
*/
public function deleteCron($condition)
{
$res = model('cron')->delete($condition);
return $this->success($res);
}
/**
* 执行任务
*/
public function execute($type = 'default')
{
if(config('cron.default') != $type) return true;
Log::write('计划任务方式:'.$type);
$this->writeSchedule();//写入计划任务标记运行
$system_config_model = new SystemConfig();
$config = $system_config_model->getSystemConfig()[ 'data' ] ?? [];
$is_open_queue = $config[ 'is_open_queue' ] ?? 0;
$query_execute_time = $is_open_queue == 1 ? time() + 60 : time();
$type_fixed = self::TYPE_FIXED;
$type_loop = self::TYPE_LOOP;
$list = model('cron')->getList([
['execute_time', '<=', $query_execute_time],
['', 'exp', Db::raw("(type = {$type_fixed} and error_num < {$this->max_error_num}) or type = {$type_loop}")],
], '*', '', '', [], '', 150);
$now_time = time();
if (!empty($list)) {
foreach ($list as $k => $v) {
Log::write('任务信息');
Log::write($v);
$event_res = checkQueue($v, function($params) {
//加入消息队列
$job_handler_classname = 'Cronexecute';
try {
if ($params[ 'execute_time' ] <= time()) {
Queue::push($job_handler_classname, $params);
} else {
Queue::later($params[ 'execute_time' ] - time(), $job_handler_classname, $params);
}
} catch (\Exception $e) {
$res = $this->error($e->getMessage(), $e->getMessage());
}
return $res ?? $this->success();
}, function($params) {
try {
$res = $this->success();
$res_list = event($params[ 'event' ], [ 'relate_id' => $params[ 'relate_id' ] ]);
foreach($res_list as $val){
if(isset($val['code']) && $val['code'] < 0){
$res = $val;
break;
}
}
} catch (\Exception $e) {
$res = $this->error([
'file' => $e->getFile(),
'line' => $e->getLine(),
'message' => $e->getMessage(),
], '定时任务执行捕获异常');
}
$data_log = [
'name' => $params[ 'name' ],
'event' => $params[ 'event' ],
'relate_id' => $params[ 'relate_id' ],
'message' => json_encode($res)
];
$this->addCronLog($data_log);
return $res;
});
Log::write('任务结果');
Log::write($event_res);
//有错误更新错误次数,下次决定是否继续执行
$event_code = $event_res[ 'code' ] ?? 0;
if ($event_code < 0) {
model('cron')->update([
'error_num' => Db::raw("error_num + 1"),
], [ [ 'id', '=', $v[ 'id' ] ] ]);
continue;
}
if ($v[ 'type' ] == self::TYPE_LOOP) {
//循环任务更新下次执行时间
$period = $v[ 'period' ] == 0 ? 1 : $v[ 'period' ];
switch ( $v[ 'period_type' ] ) {
case 0://
$execute_time = $now_time + $period * 60;
break;
case 1://
$execute_time = strtotime('+' . $period . 'day', $v[ 'execute_time' ]);
break;
case 2://
$execute_time = strtotime('+' . $period . 'week', $v[ 'execute_time' ]);
break;
case 3://
$execute_time = strtotime('+' . $period . 'month', $v[ 'execute_time' ]);
break;
}
if(!empty($execute_time)){
model('cron')->update([
'execute_time' => $execute_time,
], [ [ 'id', '=', $v[ 'id' ] ] ]);
}
} else {
//固定任务删除
model('cron')->delete([ [ 'id', '=', $v[ 'id' ] ] ]);
}
}
}
return true;
}
/**
* 添加自动任务日志
* @param $data
* @return array
*/
public function addCronLog($data)
{
// 日常不需要添加,调试使用
// $data[ 'execute_time' ] = time();
// model('cron_log')->add($data);
return $this->success();
}
/**
* 检测自动任务标识缓存是否已过期
*/
public function checkCron()
{
$diff = $this->time_diff;
$now_time = time();
$cron_cache = Cache::get('cron_cache');
if (empty($cron_cache)) {
//todo 不存在缓存标识,并不视为任务停止
//创建缓存标识,当前时间填充
Cache::set('cron_cache', [ 'time' => $now_time, 'error' => '' ]);
} else {
$time = $cron_cache[ 'time' ];
$error = $cron_cache[ 'error' ] ?? '';
$attempts = $cron_cache[ 'attempts' ] ?? 0;//尝试次数
if (!empty($error) || ( $now_time - $time ) > $diff) {
$message = '自动任务已停止';
if (!empty($error)) {
$message .= ',停止原因:' . $error;
} else {
$system_config_model = new \app\model\system\SystemConfig();
$config = $system_config_model->getSystemConfig()[ 'data' ] ?? [];
$is_open_queue = $config[ 'is_open_queue' ] ?? 0;
if (!$is_open_queue) {//如果不是消息队列的话,可以尝试异步调用一下
if ($attempts < 1) {
Cache::set('cron_cache', [ 'time' => $now_time, 'error' => '', 'attempts' => 1 ]);
$url = url('cron/task/execute');
http($url, 1);
return $this->success();
}
} else {
//消息队列无法启动,应该在前端引导跳转到官方的手册
}
}
//判断任务是 消息队列自动任务,还是默认睡眠sleep自动任务
return $this->error([], $message);
}
}
return $this->success();
}
/**
* 设置自动任务
* @param array $params
* @return array
*/
public function setCron($params = [])
{
$cron_cache = Cache::get('cron_cache');
if (empty($cron_cache)) {
$cron_cache = [];
}
// $code = $params['code'] ?? 0;
// if($code < 0){
// $error = $params['message'] ?? '位置的错误';
// $cron_cache['error'] = $error;
// }
$cron_cache[ 'time' ] = time();
$cron_cache[ 'attempts' ] = 0;
Cache::set('cron_cache', $cron_cache);
return $this->success();
}
/**
* 校验计划任务是否正常运行
* @return bool
*/
public function checkSchedule()
{
$file = root_path('runtime') . '.schedule';
if (file_exists($file)) {
$time = file_get_contents($file);
if (!empty($time) && abs($time - time()) < 90) {
return $this->success();
}
}
$remark = '计划任务已停止!当前启动的任务方式:'.ScheduleDict::getType(config('cron.default')).'。 <a href="https://www.kancloud.cn/niucloud/niushop_b2c_v5/3212243" target="_blank" style="margin-left: 0px">查看文档</a>';
$error = self::getError(config('cron.default'));
if(!empty($error)){
$remark .= $error;
}
return $this->error([], $remark);
}
/**
* 写入校验计划任务
* @return true
*/
public function writeSchedule(){
$file = root_path('runtime').'.schedule';
file_put_contents($file, time());
return true;
}
/**
* 保存自动任务的错误
* @param $type
* @param $error
* @return true
*/
public static function setError($type, $error = ''){
Cache::set('cron_error', [$type => $error]);
return true;
}
/**
* 获取错误
* @param $type
* @return mixed
*/
public static function getError($type = ''){
$error = Cache::get('cron_error');
if(!empty($type))
return $error;
return $error[$type];
}
}

235
app/model/system/Database.php Executable file
View File

@@ -0,0 +1,235 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use think\facade\Db;
use app\model\BaseModel;
/**
* 数据库操作
*/
class Database extends BaseModel
{
public $backup_path = __UPLOAD__ . '/dbsql';
/***********************************************************SQL开始*********************************************************/
/**
* 修复表
*/
public function repair($tables)
{
if ($tables) {
Db::startTrans();
try {
if (is_array($tables)) {
$tables = implode('`,`', $tables);
Db::query("REPAIR TABLE `{$tables}`");
} else {
Db::query("REPAIR TABLE `{$tables}`");
}
Db::commit();
return $this->success(1);
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
return $this->error('', "DABASE_REPAIR_FAIL");
}
} else {
return $this->error('', "DABASE_REPAIR_FAIL");
}
}
/**
* 优化表
*/
public function optimize($tables)
{
if ($tables) {
if (is_array($tables)) {
$tables = implode('`,`', $tables);
$list = Db::query("OPTIMIZE TABLE `{$tables}`");
if ($list) {
return $this->success(1);
} else {
return $this->error('', "DATABASE_OPTIMIZE_FAIL");
}
} else {
$list = Db::query("OPTIMIZE TABLE `{$tables}`");
if ($list) {
return $this->success(1);
} else {
return $this->error('', "DATABASE_OPTIMIZE_FAIL");
}
}
} else {
return $this->error('', "REQUEST_DATABASE_TABLE");
}
}
private function sql_execute($sql, $is_debug)
{
if (trim($sql) != '') {
$sql = str_replace("\r\n", "\n", $sql);
$sql = str_replace("\r", "\n", $sql);
$sql_array = explode(";\n", $sql);
if (!$is_debug) {
Db::startTrans();
}
try {
foreach ($sql_array as $item) {
if ($is_debug) {
Db::startTrans();
}
$querySql = trim($item);
if ($querySql != '') {
@Db::execute($querySql . ";");
if ($is_debug) {
Db::rollback();
}
}
}
if (!$is_debug) {
Db::commit();
}
return $this->success(1);
} catch (\Exception $e) {
Db::rollback();
return $this->error($e->getMessage());
}
} else {
return $this->error('');
}
}
/**
* 执行sql
*/
public function sqlQuery($sql)
{
$result = $this->sql_execute($sql, false);
return $result;
}
public function yujjia($sql)
{
Db::startTrans();
try {
Db::query($sql);
Db::rollback();
return "1";
} catch (\Exception $e) {
Db::rollback();
return $this->error($e->getMessage());
}
}
/**
* 查询所有表
*/
public function getDatabaseList()
{
$databaseList = Db::query("SHOW TABLE STATUS");
return $databaseList;
}
/**备份数据库语句
* @return string
*/
public function backupSql($tables, $id, $start)
{
}
public function getTableSchemas($table)
{
$mysql = "DROP TABLE IF EXISTS `$table`;\r\n";
$temp_create_table_result = Db::query("show create table `$table`");
$create_table = $temp_create_table_result[0]['Create Table'];
$mysql .= $create_table . ";\r\n";
return $mysql;
}
public function getTableInsertSql($tablename, $start, $size)
{
$data = '';
$tmp = '';
$sql = "SELECT * FROM `{$tablename}` LIMIT {$start}, {$size}";
$result = Db::query($sql);
if (!empty($result)) {
foreach ($result as $row) {
$tmp .= '(';
foreach ($row as $k => $v) {
$value = str_replace(array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $v);
$tmp .= "'" . $value . "',";
}
$tmp = rtrim($tmp, ',');
$tmp .= "),\n";
}
$tmp = rtrim($tmp, ",\n");
$data .= "INSERT INTO `{$tablename}` VALUES \n{$tmp};\n";
$datas = array(
'data' => $data,
'result' => $result,
);
return $datas;
} else {
return false;
}
}
/**
* 格式化字节大小
*
* @param number $size
* 字节数
* @param string $delimiter
* 数字和单位分隔符
* @return string 格式化后的带单位的大小
* @author
*
*/
public function format_bytes($size, $delimiter = '')
{
$units = array(
'B',
'KB',
'MB',
'GB',
'TB',
'PB'
);
for ($i = 0; $size >= 1024 && $i < 5; $i++)
$size /= 1024;
return round($size, 2) . $delimiter . $units[$i];
}
/**
* 多维数组排序
*/
public function my_array_multisort($data, $sort_order_field, $sort_order = SORT_DESC, $sort_type = SORT_NUMERIC)
{
foreach ($data as $val) {
$key_arrays[] = $val[$sort_order_field];
}
array_multisort($key_arrays, $sort_order, $sort_type, $data);
return $data;
}
/***********************************************************SQL结束*********************************************************/
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
class DiyTemplate extends BaseModel
{
/**
* 刷新自定义模板
*/
public function refresh()
{
return $this->success();
}
}

98
app/model/system/Document.php Executable file
View File

@@ -0,0 +1,98 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use think\facade\Cache;
use app\model\BaseModel;
/**
* 系统文章
*/
class Document extends BaseModel
{
/**
* 设置文章内容
* @param $title
* @param $content
* @param $condition
* @return array
*/
public function setDocument($title, $content, $condition)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$app_module = $check_condition['app_module'] ?? '';
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$document_key = $check_condition['document_key'] ?? '';
if (empty($document_key)) {
return $this->error('', 'REQUEST_DOCUMENT_KEY');
}
$data = $check_condition;
$data['title'] = $title;
$data['content'] = $content;
$json_condition = json_encode($condition);
$document_model = model('document');
$info = $document_model->getInfo($condition, 'id');
Cache::tag("document")->set("document_" . $json_condition, "");
if (empty($info)) {
$data['create_time'] = time();
$res = $document_model->add($data);
} else {
$data['modify_time'] = time();
$res = $document_model->update($data, $condition);
}
return $this->success($res);
}
/**
* 获取系统文章
* @param array $condition
*/
public function getDocument($condition)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$app_module = $check_condition['app_module'] ?? '';
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$document_key = $check_condition['document_key'] ?? '';
if (empty($document_key)) {
return $this->error('', 'REQUEST_DOCUMENT_KEY');
}
$info = model('document')->getInfo($condition, 'site_id, app_module, document_key, title, content, create_time, modify_time');
if (empty($info)) {
//默认初始值
$info = [
'site_id' => $site_id,
'app_module' => $app_module,
'document_key' => $document_key,
'title' => '',
'content' => '',
'create_time' => 0,
'modify_time' => 0
];
}
return $this->success($info);
}
}

340
app/model/system/Export.php Executable file
View File

@@ -0,0 +1,340 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use think\facade\Db;
class Export extends BaseModel
{
const STATUS_IN_PROCESS = 0;
const STATUS_SUCCESS = 1;
const STATUS_FAIL = 2;
static public function getStatus($key = null)
{
$arr = [
[
'id' => self::STATUS_IN_PROCESS,
'name' => '导出中',
],
[
'id' => self::STATUS_SUCCESS,
'name' => '导出成功',
],
[
'id' => self::STATUS_FAIL,
'name' => '导出失败',
],
];
if(isset($arr[0][$key])){
$arr = array_column($arr, null, $key);
}
return $arr;
}
protected $data_num = 0;
/**
* 导出
* @param $param
* @return array
*/
public function export($param)
{
//传参说明
/*$param = [
'site_id' => $site_id,
'store_id' => $export_store_id,
'from_type' => 'store_account',
'from_type_name' => '门店账户',
'condition_desc' => $condition_desc,
'export_field' => [
['field' => 'store_name', 'name' => '门店名称'],
['field' => 'type_name', 'name' => '来源方式'],
['field' => 'account_data', 'name' => '记录金额'],
['field' => 'create_time', 'name' => '发生时间'],
['field' => 'remark', 'name' => '备注'],
['field' => 'related_no', 'name' => '关联编号'],
],
//数据库查询相关参数
'query' => [
'table' => 'store_account',
'alias' => 'sa',
'join' => [
['store s', 'sa.store_id = s.store_id', 'inner'],
],
'condition' => $condition,
'field' => 'sa.*,s.store_name',
'chunk_field' => 'sa.id',
'chunk_order' => 'asc',
],
//数据库查询结果处理 这个其实应该放在query中
'handle' => function($item_list){
return $item_list;
},
//直接传递导出的数据
'data' => [],
];*/
set_time_limit(0);
$site_id = $param['site_id'];
$store_id = $param['store_id'] ?? 0;
$from_type = $param['from_type'];
$from_type_name = $param['from_type_name'];
$condition_desc= $param['condition_desc'];
$export_field = $param['export_field'];
$query = $param['query'] ?? null;//table alias join condition field order
$handle = $param['handle'] ?? null;//数据处理
try {
//预先创建导出的记录
$data = array(
'condition' => json_encode($condition_desc, JSON_UNESCAPED_UNICODE),
'create_time' => time(),
'from_type' => $from_type,
'from_type_name' => $from_type_name,
'status' => self::STATUS_IN_PROCESS,
'site_id' => $site_id,
'store_id' => $store_id,
);
$records_result = $this->addExport($data);
$export_id = $records_result['data'];
if (empty($export_id)) return $this->error(null, '创建导出记录失败');
$this->data_num = 0;
//创建目录
$file_path = 'upload/export/'.$from_type.'/';
if (!dir_mkdir($file_path)) return $this->error(null, '导出目录创建失败');
//创建并打开文件
$file_name = $from_type_name.date('YmdHis');//csv文件名
$file_path = $file_path . $file_name . '.csv';
$fp = fopen($file_path, 'w');
fwrite($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
//写入第一行表头
fwrite($fp, join(',', array_column($export_field, 'name'))."\n");
//导出数据
if(isset($param['query'])){
$export_table = Db::name($query['table'])->where($query['condition']);
if(!empty($query['alias'])) $export_table = $export_table->alias($query['alias']);
if(!empty($query['join'])) $export_table = $this->parseJoin($export_table, $query['join']);
if(!empty($query['group'])) $export_table = $export_table->group($query['group']);
$export_table->field($query['field'])->chunk(1000, function ($item_list) use ($fp, $export_field, $handle) {
$item_list = $item_list->toArray();
if(!empty($handle)){
$item_list = $handle($item_list);
}
$this->data_num += count($item_list);
$this->itemExport($item_list, $export_field, $fp);
unset($item_list);
}, $query['chunk_field'], $query['chunk_order']);
$export_table->removeOption();
}else if(isset($param['data'])){
$this->itemExport($param['data'], $export_field, $fp);
}else{
throw new \Exception('query参数和data参数至少要传一个');
}
fclose($fp); //每生成一个文件关闭
unset($export_table);
//更新导出记录
$this->editExport([
'path' => $file_path,
'status' => self::STATUS_SUCCESS,
'data_num' => $this->data_num,
], [['export_id', '=', $export_id]]);
//返回导出信息
$export_info = $this->getExportInfo([['export_id', '=', $export_id]])['data'];
return $this->success($export_info);
} catch (\Exception $e ) {
$error = [
'file' => $e->getFile(),
'line' => $e->getLine(),
'message' => $e->getMessage(),
];
if(isset($export_id)){
//更新导出记录
$this->editExport([
'status' => self::STATUS_FAIL,
'fail_log' => json_encode($error, JSON_UNESCAPED_UNICODE),
], [['export_id', '=', $export_id]]);
}
return $this->error($error, '导出失败');
}
}
/**
* 给csv写入新的数据
* @param $item_list
* @param $field_key
* @param $temp_line
* @param $fp
*/
protected function itemExport($item_list, $export_field, $fp)
{
if(method_exists($item_list, 'toArray')){
$item_list = $item_list->toArray();
}
foreach ($item_list as $item_info) {
$values = [];
foreach($export_field as $field_info){
if(isset($item_info[$field_info['field']])){
$value = $item_info[$field_info['field']];
$value = trim($value);
$value = str_replace(',', '', $value . "\t");
$value = str_replace("\n", '', $value);
$value = str_replace("\r", '', $value);
$values[] = $value;
}
}
//写入数据
fwrite($fp, join(',', $values)."\n");
//销毁变量, 防止内存溢出
unset($new_line_value);
}
}
/**
* 解析关联
* @param $db_obj
* @param $join
* @return mixed
*/
protected function parseJoin($db_obj, $join)
{
foreach ($join as $item) {
list($table, $on, $type) = $item;
$type = strtolower($type);
switch ($type) {
case 'left':
$db_obj = $db_obj->leftJoin($table, $on);
break;
case 'inner':
$db_obj = $db_obj->join($table, $on);
break;
case 'right':
$db_obj = $db_obj->rightjoin($table, $on);
break;
case 'full':
$db_obj = $db_obj->fulljoin($table, $on);
break;
default:
break;
}
}
return $db_obj;
}
/**
* 添加导出记录
* @param $data
* @return array
*/
public function addExport($data)
{
$res = model('export')->add($data);
return $this->success($res);
}
/**
* 更新导出记录
* @param $data
* @param $condition
* @return array
*/
public function editExport($data, $condition)
{
$res = model('export')->update($data, $condition);
return $this->success($res);
}
/**
* 删除导出记录
* @param $condition
* @return array
*/
public function deleteExport($condition)
{
//先查询数据
$list = model('export')->getList($condition, '*');
if (!empty($list)) {
foreach ($list as $k => $v) {
if (file_exists($v['path'])) {
//删除物理文件路径
if (!unlink($v['path'])) {
//失败
} else {
//成功
}
}
}
$res = model('export')->delete($condition);
}
return $this->success($res ?? '');
}
public function getExportInfo($condition, $field = '*')
{
$info = model('export')->getInfo($condition, $field);
$info = $this->handleData($info);
return $this->success($info);
}
/**
* 获取导出记录
* @param $condition
* @param string $field
* @param string $order
* @return array
*/
public function getExportList($condition, $field = '*', $order = '')
{
$list = model('export')->getList($condition, $field, $order);
foreach($list as &$val){
$val = $this->handleData($val);
}
return $this->success($list);
}
/**
* 导出记录
* @param array $condition
* @param int $page
* @param int $page_size
* @param string $order
* @param string $field
* @return array
*/
public function getExportPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = '*')
{
$list = model('export')->pageList($condition, $field, $order, $page, $page_size);
foreach($list['list'] as &$val){
$val = $this->handleData($val);
}
return $this->success($list);
}
protected function handleData($data)
{
if(isset($data['status'])){
$status_list = self::getStatus('id');
$data['status_name'] = $status_list[$data['status']]['name'] ?? '';
}
return $data;
}
}

246
app/model/system/Group.php Executable file
View File

@@ -0,0 +1,246 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use think\facade\Cache;
use app\model\BaseModel;
/**
* 用户组
* @author Administrator
*
*/
class Group extends BaseModel
{
public $cache_model = "cache_model_group";
/*****************************************用户组管理开始******************************************************************************/
/**
* 添加用户组
* @param $data
* @return array
*/
public function addGroup($data)
{
$site_id = $data['site_id'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$app_module = $data['app_module'] ?? '';
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
//创建者数据
if(isset($data['create_uid'])){
$user_info = model('user')->getInfo([['uid', '=', $data['create_uid']]], 'uid,username,create_user_data');
$create_user_data = json_decode($user_info['create_user_data'], true);
$create_user_data[] = ['id' => (string)$user_info['uid'], 'name' => $user_info['username']];
$data['create_user_data'] = json_encode($create_user_data, JSON_UNESCAPED_UNICODE);
}
//预留验证
$res = model('group')->add($data);
Cache::tag($this->cache_model)->clear();
if ($res === false) {
return $this->error('', 'UNKNOW_ERROR');
}
return $this->success($res);
}
/**
* 修改用户组
* @param $data
* @param $condition
* @return array
*/
public function editGroup($data, $condition)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$app_module = $check_condition['app_module'] ?? '';
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$condition[] = [ "is_system", "=", 0 ];//只能删除非系统用户组
$res = model('group')->update($data, $condition);
Cache::tag($this->cache_model)->clear();
if ($res === false) {
return $this->error('', 'UNKNOW_ERROR');
}
return $this->success($res);
}
/**
* 删除用户组(不能批量)
* @param $condition
* @return array
*/
public function deleteGroup($condition)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$app_module = $check_condition['app_module'] ?? '';
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$group_id = $check_condition['group_id'] ?? 0;
if (!is_int($group_id) && $group_id <= 0) {
return $this->error('', 'USER_GROUP_NOT_ALL_DELETE');
}
$temp_count = model('user')->getCount([ [ "group_id", "=", $group_id ], [ "app_module", "=", $app_module ], [ "site_id", "=", $site_id ] ], "uid");
if ($temp_count > 0)
return $this->error('', 'USER_GROUP_USED');
$condition[] = [ "is_system", "=", 0 ];//只能删除非系统用户组
$res = model('group')->delete($condition);
Cache::tag($this->cache_model)->clear();
if ($res === false) {
return $this->error('', 'UNKNOW_ERROR');
}
return $this->success($res);
}
/**
* 修改用户组状态
* @param $group_status
* @param $condition
* @return array
*/
public function modifyGroupStatus($group_status, $condition)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$app_module = $check_condition['app_module'] ?? '';
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$condition[ "is_system" ] = 0;//只能删除非系统用户组
$res = model('group')->update([ 'group_status' => $group_status ], $condition);
Cache::tag($this->cache_model)->clear();
if ($res === false) {
return $this->error('', 'UNKNOW_ERROR');
}
return $this->success($res);
}
/**
* 获取门店分组列信息
* @param array $condition
* @param string $field
* @return array
*/
public function getStoreGroupColumn($condition = [], $field = '')
{
$res = model('group')->getColumn($condition, $field);
return $this->success($res);
}
/**
* 获取用户组详情
* @param $condition
* @param string $field
* @return array
*/
public function getGroupInfo($condition, $field = '*')
{
$check_condition = array_column($condition, 2, 0);
$app_module = $check_condition['app_module'] ?? '';
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$info = model('group')->getInfo($condition, $field);
return $this->success($info);
}
/**
* 通过groupid获取相应用户组数据应用在门店供应商等不创建站点
* @param $group_id
* @param $site_id
* @param $app_module
* @param string $field
* @return array
*/
public function getGroupInfoById($group_id, $site_id, $app_module, $field = '*')
{
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$info = model('group')->getInfo([ [ 'group_id', '=', $group_id ], [ 'app_module', '=', $app_module ] ], $field);
return $this->success($info);
}
/**
* 获取用户组列表
* @param array $condition
* @param bool $field
* @param string $order
* @param null $limit
* @return array
*/
public function getGroupList($condition = [], $field = true, $order = 'create_time desc, group_id desc', $limit = null)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
$app_module = $check_condition['app_module'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$list = model('group')->getList($condition, $field, $order, '', '', '', $limit);
return $this->success($list);
}
/**
* 获取管理组分页列表
* @param array $condition
* @param int $page
* @param int $page_size
* @param string $order
* @param string $field
* @return array
*/
public function getGroupPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = 'create_time desc, group_id desc', $field = '*')
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition['site_id'] ?? '';
$app_module = $check_condition['app_module'] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$list = model('group')->pageList($condition, $field, $order, $page, $page_size);
return $this->success($list);
}
/*****************************************用户组管理结束****************************************************************************/
}

159
app/model/system/H5.php Executable file
View File

@@ -0,0 +1,159 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use app\model\web\Config;
class H5 extends BaseModel
{
private $h5_domain = __ROOT__ . '/h5';
public function refresh()
{
try {
$h5_template_path = 'public/h5/default'; // h5模板文件目录
$h5_path = 'h5'; // h5端生成目录
if (!is_dir($h5_template_path) || count(scandir($h5_template_path)) <= 2) {
return $this->error('', '未查找到h5模板');
}
if (is_dir($h5_path)) {
// 先将之前的文件删除
if (count(scandir($h5_path)) > 2) deleteDir($h5_path);
} else {
// 创建H5目录
mkdir($h5_path, intval('0777', 8), true);
}
$this->copyFile($h5_template_path, $h5_path);
file_put_contents($h5_path . '/refresh.log', time());
return $this->success();
} catch ( \Exception $e ) {
return $this->error('', $e->getMessage());
}
}
/**
* 独立部署下载
* @return array
*/
function downloadH5Separate($domain_name)
{
$this->h5_domain = $domain_name;
$h5_template_path = 'public/h5/separate'; // h5模板文件目录
if (!is_dir($h5_template_path) || count(scandir($h5_template_path)) <= 2) {
return $this->error('', '未查找到h5模板');
}
$source_file_path = 'upload/temp/h5';
if (is_dir($source_file_path)) {
// 先将之前的文件删除
if (count(scandir($source_file_path)) > 2) deleteDir($source_file_path);
} else {
// 创建H5目录
mkdir($source_file_path, intval('0777', 8), true);
}
$this->copyFile($h5_template_path, $source_file_path);
$file_arr = getFileMap($source_file_path);
if (!empty($file_arr)) {
$zipname = 'h5_' . 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);
}
}
}
private function copyFile($source_path, $to_path = '')
{
$files = scandir($source_path);
foreach ($files as $path) {
if ($path != '.' && $path != '..') {
$temp_path = $source_path . '/' . $path;
if (is_dir($temp_path)) {
mkdir($to_path . '/' . $path, intval('0777', 8), true);
$this->copyFile($temp_path, $to_path . '/' . $path);
} else {
if (file_exists($temp_path)) {
if (preg_match("/(index.)(\w{8})(.js)$/", $temp_path)) {
$content = file_get_contents($temp_path);
$content = $this->paramReplace($content);
file_put_contents($to_path . '/' . $path, $content);
} else {
copy($temp_path, $to_path . '/' . $path);
}
}
}
}
}
}
/**
* 参数替换
* @param $site_id
* @param $string
* @return null|string|string[]
*/
private function paramReplace($string)
{
$api_model = new Api();
$api_config = $api_model->getApiConfig()['data'];
$web_config_model = new Config();
$web_config = $web_config_model->getMapConfig();
$web_config = $web_config['data']['value'];
$socket_url = (strstr(__ROOT__, 'https://') === false ? str_replace('http', 'ws', __ROOT__) : str_replace('https', 'wss', __ROOT__)) . '/wss';
$patterns = [
'/\{\{\$baseUrl\}\}/',
'/\{\{\$imgDomain\}\}/',
'/\{\{\$h5Domain\}\}/',
'/\{\{\$mpKey\}\}/',
'/\{\{\$apiSecurity\}\}/',
'/\{\{\$publicKey\}\}/',
'/\{\{\$webSocket\}\}/'
];
$replacements = [
__ROOT__,
__ROOT__,
$this->h5_domain,
$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;
}
}

375
app/model/system/Menu.php Executable file
View File

@@ -0,0 +1,375 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use think\facade\Cache;
use app\model\BaseModel;
/**
* 菜单表
* @author Administrator
*
*/
class Menu extends BaseModel
{
public $list = [];
/***************************************** 系统菜单开始*****************************************************************************/
/**
* 获取菜单列表
* @param array $condition
* @param string $field
* @param string $order
* @param null $limit
* @return array
*/
public function getMenuList($condition = [], $field = 'id, app_module, title, name, parent, level, url, is_show, sort, is_icon, picture, picture_select, is_control, type', $order = '', $limit = null)
{
$list = model('menu')->getList($condition, $field, $order, '', '', '', $limit);
return $this->success($list);
}
/**
* 获取菜单数量
* @param $condition
* @return array
*/
public function getMenuCount($condition)
{
$count = model('menu')->getCount($condition);
return $this->success($count);
}
/**
* 获取菜单树
* @param int $level
* @return array
*/
public function menuTree($level = 0)
{
$condition = [];
if ($level > 0) {
$condition = [
[ 'level', 'elt', $level ]
];
}
$list = $this->getMenuList($condition, 'id, app_module, title, name, parent, level, url, is_show, sort, is_icon, picture, picture_select, is_control, type', 'sort asc');
$tree = list_to_tree($list[ 'data' ], 'menu_id', 'parent', 'child_list');
return $this->success($tree);
}
/**
* 通过主键获取菜单信息
* @param $condition
* @param string $field
* @return array
*/
public function getMenuInfo($condition, $field = 'id, app_module, name, title, parent, level, url, is_show, sort, `desc`, picture, is_icon, picture_select, is_control, addon, type')
{
$menu_info = model('menu')->getInfo($condition, $field);
return $this->success($menu_info);
}
/**
* 获取第一个菜单信息
* @param $condition
* @param string $field
* @return array
*/
public function getFirstMenuInfo($condition, $field = 'id, app_module, name, title, parent, level, url, is_show, sort, `desc`, picture, is_icon, picture_select, is_control, addon, type')
{
$info = model('menu')->getFirstData($condition, $field, 'sort asc');
return $this->success($info);
}
/**
* 通过url和端口查询对应菜单信息
* @param $url
* @param $app_module
* @param string $addon
* @return array
*/
public function getMenuInfoByUrl($url, $app_module, $addon = '')
{
$info = model('menu')->getFirstData([ [ 'url', "=", $url ], [ 'app_module', "=", $app_module ] ], 'id, app_module, name, title, parent, level, url, is_show, sort, `desc`, picture, is_icon, picture_select, is_control, addon, type', 'level desc');
return $this->success($info);
}
/**
* 刷新菜单
* @param $app_module
* @param $addon
* @return array
*/
public function refreshMenu($app_module, $addon)
{
try {
if (empty($addon)) {
$tree_name = 'config/menu_' . $app_module . '.php';
} else {
$tree_name = 'addon/' . $addon . '/config/menu_' . $app_module . '.php';
}
model('menu')->delete([ [ 'app_module', "=", $app_module ], [ 'addon', "=", $addon ] ]);
if(!is_file(root_path().'/'.$tree_name)){
return $this->success();
}
$tree = require $tree_name;
$list = $this->getAddonMenuList($tree, $app_module, $addon);
if (!empty($list)) {
$res = model('menu')->addList($list);
return $this->success($res);
} else {
return $this->success();
}
} catch (\Exception $e) {
return $this->error(['file' => $e->getFile(), 'line' => $e->getLine(), 'message' => $e->getMessage()], $e->getMessage());
// halt($list);
}
}
/**
* 刷新收银端权限
* @param $addon
* @return array
*/
public function refreshCashierAuth($addon)
{
$tree_name = 'addon/' . $addon . '/config/cashier_auth.php';
if (!file_exists($tree_name)) return $this->error();
$tree = require $tree_name;
if (!$tree) return $this->error();
model('cashier_auth')->delete([ [ 'addon', '=', $addon ] ]);
$list = [];
$this->getCashierAuthList($tree, $addon, '', $list);
$res = model('cashier_auth')->addList($list);
// 清除缓存
Cache::clear('cashier_menu');
return $this->success();
}
/**
* 获取收银端权限集
* @param $tree
* @param $addon
* @param string $parent
* @param array $list
*/
private function getCashierAuthList($tree, $addon, $parent = '', &$list = [])
{
foreach ($tree as $item) {
$children = $item[ 'children' ] ?? [];
if (isset($item[ 'children' ])) unset($item[ 'children' ]);
$item = array_merge($item, [ 'addon' => $addon, 'parent' => $item[ 'parent' ] ?? $parent ]);
ksort($item);
array_push($list, $item);
if (!empty($children)) $this->getCashierAuthList($children, $addon, $item[ 'name' ], $list);
}
}
/**
* 刷新全部菜单
*/
public function refreshAllMenu()
{
$res = [];
$shop_menu_res = $this->refreshMenu("shop", '');
if($shop_menu_res['code'] < 0) $res['shop'] = $shop_menu_res;
$addon_model = new Addon();
$addon_list = $addon_model->getAddonList([], 'name');
$addon_list = $addon_list[ 'data' ];
foreach ($addon_list as $k_addon => $v_addon) {
$addon_menu_res = $this->refreshMenu('shop', $v_addon[ 'name' ]);
if($addon_menu_res['code'] < 0) $res[$v_addon['name']] = $addon_menu_res;
}
return $this->success($res);
}
/**
* 刷新店铺端菜单
* @param $addon
* @param string $app_module
* @return array|int
*/
public function cacheMenu($addon, $app_module = 'shop')
{
if (!empty($addon)) {
$tree_name = 'addon/' . $addon . '/config/menu_' . $app_module . '.php';
} else {
$tree_name = $addon . '/config/menu_' . $app_module . '.php';
}
if (file_exists($tree_name)) {
model('menu')->delete([ [ 'app_module', "=", $app_module ], [ 'addon', "=", $addon ] ]);
$tree = require $tree_name;
$list = $this->getAddonMenuList($tree, $app_module, $addon);
if (!empty($list)) {
$res = model('menu')->addList($list);
return $res;
} else {
return $this->success();
}
} else {
return $this->success();
}
}
/**
* 获取菜单
* @param $tree
* @param $app_module
* @param $addon
* @return array|\think\response\Json
*/
public function getAddonMenuList($tree, $app_module, $addon)
{
try {
$list = [];
if (!$tree) {
return [];
}
foreach ($tree as $k => $v) {
$parent = '';
if (isset($v[ 'parent' ])) {
if ($v[ 'parent' ] == '') {
$parent = '';
$level = 1;
} else {
$parent_menu_info = model('menu')->getInfo([
[ 'name', "=", $v[ 'parent' ] ]
]);
if ($parent_menu_info) {
$parent = $parent_menu_info[ 'name' ];
$level = $parent_menu_info[ 'level' ] + 1;
} else {
$level = 1;
}
}
} else {
$parent = '';
$level = 1;
}
$item = [
'app_module' => $app_module,
'addon' => $addon,
'title' => $v[ 'title' ],
'name' => $v[ 'name' ],
'parent' => $parent,
'level' => $level,
'url' => $v[ 'url' ],
'is_show' => $v['is_show'] ?? 1,
'sort' => $v['sort'] ?? 100,
'is_icon' => $v['is_icon'] ?? 0,
'picture' => $v['picture'] ?? '',
'picture_select' => $v['picture_selected'] ?? '',
'is_control' => $v['is_control'] ?? 1,
'desc' => $v['desc'] ?? '',
'type' => $v['type'] ?? 'page',//页面page 按钮button
];
array_push($list, $item);
if (isset($v[ 'child_list' ])) {
$this->list = [];
$this->menuTreeToList($v[ 'child_list' ], $app_module, $addon, $v[ 'name' ], $level + 1);
$list = array_merge($list, $this->list);
}
}
return $list;
} catch (\Exception $e) {
return $this->error(-1, $e->getMessage() . ",File" . $e->getFile() . "line" . $e->getLine());
}
}
/**
* 菜单树转化为列表
* @param $tree
* @param $app_module
* @param string $addon
* @param string $parent
* @param int $level
*/
private function menuTreeToList($tree, $app_module, $addon = '', $parent = '', $level = 1)
{
if (is_array($tree)) {
foreach ($tree as $key => $value) {
$item = [
'app_module' => $app_module,
'addon' => $addon,
'title' => $value[ 'title' ],
'name' => $value[ 'name' ],
'parent' => $parent,
'level' => $level,
'url' => $value[ 'url' ],
'is_show' => $value['is_show'] ?? 1,
'sort' => $value['sort'] ?? 100,
'is_icon' => $value['is_icon'] ?? 0,
'picture' => $value['picture'] ?? '',
'picture_select' => $value['picture_selected'] ?? '',
'is_control' => $value['is_control'] ?? 1,
'desc' => $value['desc'] ?? '',
'type' => $value['type'] ?? 'page',
];
$refer = $value;
if (isset($refer[ 'child_list' ])) {
unset($refer[ 'child_list' ]);
array_push($this->list, $item);
$p_name = $refer[ 'name' ];
$this->menuTreeToList($value[ 'child_list' ], $app_module, $addon, $p_name, $level + 1);
} else {
array_push($this->list, $item);
}
}
}
}
/**
* 清空菜单表防止自增ID越来越大
*/
public function truncateMenu()
{
$prefix = config("database")[ "connections" ][ "mysql" ][ "prefix" ];
model('menu')->execute("TRUNCATE TABLE {$prefix}menu");
}
/**
* 清空收银台菜单表防止自增ID越来越大
*/
public function truncateCashierAuth()
{
$prefix = config("database")[ "connections" ][ "mysql" ][ "prefix" ];
model('menu')->execute("TRUNCATE TABLE {$prefix}cashier_auth");
}
/**
* 清空组件、链接表防止自增ID越来越大
*/
public function truncateDiyView()
{
$prefix = config("database")[ "connections" ][ "mysql" ][ "prefix" ];
model('menu')->execute("TRUNCATE TABLE {$prefix}diy_view_util");
model('menu')->execute("TRUNCATE TABLE {$prefix}link");
}
}

659
app/model/system/Pay.php Executable file
View File

@@ -0,0 +1,659 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use app\model\member\Member;
use app\model\order\Config as OrderConfig;
use app\model\order\OrderPay;
use think\facade\Cache;
use think\facade\Log;
/**
* 系统配置类
*/
class Pay extends BaseModel
{
//支付状态
const PAY_STATUS_NOT = 0;
const PAY_STATUS_IN_PROCESS = 1;
const PAY_STATUS_SUCCESS = 2;
const PAY_STATUS_CANCEL = -1;
const PAY_STATUS_CLOSE = -2;
public $refund_pay_type = array (
'offline_refund_pay' => '线下退款',
'online_refund_pay' => '原路退款'
);
static function getPayStatus($key = null)
{
$arr = [
[
'id' => self::PAY_STATUS_NOT,
'name' => '待支付',
],
[
'id' => self::PAY_STATUS_IN_PROCESS,
'name' => '支付中',
],
[
'id' => self::PAY_STATUS_SUCCESS,
'name' => '支付成功',
],
[
'id' => self::PAY_STATUS_CANCEL,
'name' => '已取消',
],
[
'id' => self::PAY_STATUS_CLOSE,
'name' => '已关闭',
],
];
if(isset($arr[0][$key])){
$arr = array_column($arr, null, $key);
}
return $arr;
}
/********************************************************************支付**********************************************************/
/**
* 支付
* @param string $pay_type 支付方式
* @param string $out_trade_no 交易号
* @param string $app_type 请求来源类型
* @param int $member_id 会员id
* @param string $return_url 同步回调地址
* @param int $is_balance 是否使用余额
* @param int $scene 场景值
* @return mixed|void
*/
public function pay($pay_type, $out_trade_no, $app_type, $member_id, $return_url = null, $is_balance = 0, $scene = 0)
{
$data = $this->getPayInfo($out_trade_no)[ 'data' ];
if (empty($data)) return $this->error('', '未获取到支付信息');
if ($data[ 'pay_status' ] == self::PAY_STATUS_SUCCESS) return $this->success(['pay_success' => 1]);
if ($data['pay_status'] == self::PAY_STATUS_CLOSE) return $this->error(null, '支付单已关闭');
$notify_url = addon_url('pay/pay/notify');
if (empty($return_url)) {
$return_url = addon_url('pay/pay/payreturn');
}
// 是否使用余额
if ($is_balance) {
$data[ 'member_id' ] = $member_id;
$use_res = $this->useBalance($data)[ 'data' ];
if (isset($use_res[ 'pay_success' ])) return $this->success($use_res);
$data = $this->getPayInfo($out_trade_no)[ 'data' ];
}
$data[ 'app_type' ] = $app_type;
$data[ 'notify_url' ] = $notify_url;
$data[ 'return_url' ] = $return_url;
$data[ 'pay_type' ] = $pay_type;
$data[ 'member_id' ] = $member_id;
$data[ 'scene' ] = $scene;
$res = event('Pay', $data, true);
if (empty($res)) return $this->error('', '没有可用的支付方式');
return $res;
}
/**
* 创建支付流水号
* @param int $member_id
* @return string
*/
public function createOutTradeNo($member_id = 0)
{
$cache = Cache::get('pay_out_trade_no' . $member_id . time());
if (empty($cache)) {
Cache::set('pay_out_trade_no' . $member_id . time(), 1000);
$cache = Cache::get('pay_out_trade_no' . $member_id . time());
} else {
$cache = $cache + 1;
Cache::set('pay_out_trade_no' . $member_id . time(), $cache);
}
$no = time() . rand(1000, 9999) . $member_id . $cache;
return $no;
}
/**
* 添加支付信息
* @param int $site_id //站点id 默认平台配置为0
* @param string $out_trade_no 交易流水号
* @param string $app_type 支付端口类型
* @param int $pay_type 支付方式,默认为空
* @param string $pay_body 支付主体
* @param string $pay_detail 支付细节
* @param double $pay_money 支付金额
* @param string $pay_no 支付账号
* @param string $notify_url 要求的异步回调网址,实际支付后会进行执行或者回调,可以是事件或者域名
* @param string $return_url 同步回调网址,知己支付后会进行同步回调
*/
public function addPay($site_id, $out_trade_no, $pay_type, $pay_body, $pay_detail, $pay_money, $pay_no, $notify_url, $return_url, $relate_id = '', $member_id = 0)
{
$data = array (
'site_id' => $site_id,
'out_trade_no' => $out_trade_no,
'pay_body' => $pay_body,
'pay_detail' => $pay_detail,
'pay_money' => $pay_money,
'pay_no' => $pay_no,
'event' => $notify_url,
'return_url' => $return_url,
'pay_status' => 0,
'create_time' => time(),
'relate_id' => $relate_id,
'member_id' => $member_id,
);
model('pay')->add($data);
$result = $this->success();
if ($pay_money == 0) {
$result = $this->onlinePay($out_trade_no, $pay_type, '', '');
}
return $result;
}
/**
* 在线支付
* @param $out_trade_no
* @param $pay_type
* @param $trade_no
* @param $pay_addon
* @param array $log_data
* @return array|mixed|void
* @throws \Exception
*/
public function onlinePay($out_trade_no, $pay_type, $trade_no, $pay_addon, $log_data = [])
{
Log::write("在线支付_onlinePay_" . $out_trade_no);
$pay_type = empty($pay_type) ? 'ONLINE_PAY' : $pay_type;
$pay_info = $this->getPayInfo($out_trade_no)['data'];
if(empty($pay_info)) return $this->error(null, '支付信息缺失');
//根据不同的状态执行不同的业务
switch($pay_info[ 'pay_status' ]){
case self::PAY_STATUS_NOT:
case self::PAY_STATUS_IN_PROCESS:
case self::PAY_STATUS_CANCEL:
$data = array (
'trade_no' => $trade_no,
'pay_type' => $pay_type,
'pay_addon' => $pay_addon,
'pay_time' => time(),
'pay_status' => self::PAY_STATUS_SUCCESS
);
$res = model('pay')->update($data, [['out_trade_no', '=', $out_trade_no]]);
if(!$res){
Log::write("在线支付更新pay失败_" . $out_trade_no);
return $this->error(null, '支付单据更新失败');
}
return $this->onlinePayEvent($pay_info['id'], $log_data, 1);
break;
case self::PAY_STATUS_SUCCESS:
return $this->success();
break;
case self::PAY_STATUS_CLOSE:
//退款
$refund_no = $this->createRefundNo();
return $this->refund($refund_no, $pay_info['pay_money'], $pay_info['out_trade_no'], '重复支付退款', $pay_info['pay_money'], $pay_info['site_id'], 1, 0, 0);
break;
default:
return $this->error(null, '支付状态有误');
}
}
/**
* @param $id
* @param array $log_data
* @return array|mixed
* @throws \Exception
*/
public function onlinePayEvent($id, $log_data = [], $execute_num = 1)
{
$pay_info = model('pay')->getInfo([['id', '=', $id]]);
$return_data = [
'out_trade_no' => $pay_info['out_trade_no'],
'trade_no' => $pay_info['trade_no'],
'pay_type' => $pay_info['pay_type'],
'log_data' => $log_data,
];
$res = $this->success();
if (strpos($pay_info[ 'event' ], 'http://') !== 0 || strpos($pay_info[ 'event' ], 'https://') !== 0) {
$event_res_arr = event($pay_info[ 'event' ], $return_data);
foreach($event_res_arr as $event_res){
if(isset($event_res['code']) && $event_res['code'] < 0){
$pay_json = json_encode($pay_info['pay_json'], true);
if(!is_array($pay_json)) $pay_json = [];
$pay_json['event_res'] = $event_res;
model('pay')->update(['pay_json' => json_encode($pay_json, JSON_UNESCAPED_UNICODE)], [['out_trade_no', '=', $pay_info['out_trade_no']]]);
Log::write("支付回调event失败");
Log::write(['pay_info' => $pay_info, 'return_data' => $return_data, 'event_res' => $event_res]);
$res = $event_res;
break;
}
}
} else {
http($pay_info[ 'event' ], 1);
}
if(in_array($pay_info['pay_type'], ['wechatpay','alipay']) && $res['code'] < 0){
if($execute_num < 3){
sleep(3);
return $this->onlinePayEvent($pay_info, $return_data, $execute_num+1);
}else if($execute_num == 3){
//如果执行3次以后还是失败那就定时任务1分钟后再执行如果依然失败就不再继续
(new Cron())->addCron(1, 0, "支付回调", "OnlinePayEvent", time() + 60, $id);
}
}
return $res;
}
/**
* 关闭支付
* @param $out_trade_no
* @return array|mixed
* @throws \think\db\exception\DbException
*/
public function closePay($out_trade_no)
{
$pay_info = $this->getPayInfo($out_trade_no)['data'];
if(empty($pay_info)) return $this->error(null, '支付信息不存在');
if($pay_info['pay_status'] == self::PAY_STATUS_CLOSE) return $this->success();
if($pay_info['pay_status'] == self::PAY_STATUS_SUCCESS) return $this->error(null, '已支付单据不可关闭');
$event_res = event('PayClose', $pay_info);
foreach ($event_res as $v) {
if (isset($v[ 'code' ]) && $v[ 'code' ] < 0) {
return $v;
}
}
model('pay')->startTrans();
try{
// 冻结中的余额返还
if ($pay_info[ 'member_id' ]) {
if ($pay_info[ 'balance' ]) model('member')->setDec([['site_id', '=', $pay_info[ 'site_id' ]], ['member_id', '=', $pay_info[ 'member_id' ]]], 'balance_lock', $pay_info[ 'balance' ]);
if ($pay_info[ 'balance_money' ]) model('member')->setDec([['site_id', '=', $pay_info[ 'site_id' ]], ['member_id', '=', $pay_info[ 'member_id' ]]], 'balance_money_lock', $pay_info[ 'balance_money' ]);
}
$res = model('pay')->update(['pay_status' => self::PAY_STATUS_CLOSE], [['out_trade_no', '=', $out_trade_no]]);
if ($res === false) {
model('pay')->rollback();
return $this->error(null, '数据修改失败');
}
model('pay')->commit();
return $this->success();
}catch(\Exception $e){
model('pay')->rollback();
return $this->error(null, $e->getMessage());
}
}
/**
* 重新生成新的pay支付记录
* @param $out_trade_no
* @param $pay_money
* @return array|mixed|void
*/
public function rewritePay($out_trade_no, $pay_money)
{
$pay_info_result = $this->getPayInfo($out_trade_no);
$pay_info = $pay_info_result[ 'data' ];
//支付状态 (未支付 未取消)
if ($pay_info[ 'pay_status' ] == self::PAY_STATUS_NOT) {
// if (!empty($pay_info[ 'pay_type' ])) {
$close_result = event('payClose', $pay_info, true);
if (!empty($close_result[ 'code' ]) && $close_result[ 'code' ] < 0) {
return $close_result;
}
// }
$new_out_trade_no = $this->createOutTradeNo();
$data = array (
'out_trade_no' => $new_out_trade_no,
'pay_money' => $pay_money
);
$res = model('pay')->update($data, [['out_trade_no', '=', $out_trade_no]]);
if ($res === false) {
return $this->error('', 'UNKNOW_ERROR');
} else {
return $this->success($new_out_trade_no);
}
} else if ($pay_info[ 'pay_status' ] == self::PAY_STATUS_CANCEL) {
$new_out_trade_no = $this->createOutTradeNo();
$data = array (
'out_trade_no' => $new_out_trade_no,
'pay_money' => $pay_money,
'pay_status' => self::PAY_STATUS_NOT
);
$res = model('pay')->update($data, [['out_trade_no', '=', $out_trade_no]]);
return $this->success($new_out_trade_no);
} else {
return $this->error([], '当前支付已完成');
}
}
/**
* 支付绑定商户信息
* @param $out_trade_no
* @param $json_data
*/
public function clearMchPay($out_trade_no, $curr_pay_type)
{
//如果当前方式与之前发起的支付方式不同则要关闭旧的支付,防止一个支付单不同的支付方式都支付成功
$pay_info = $this->getPayInfo($out_trade_no)['data'];
$mch_info = json_decode($pay_info['mch_info'], true);
$bind_pay_type = $mch_info['pay_type'] ?? '';
if(!empty($bind_pay_type) && $bind_pay_type != $curr_pay_type){
$event_res = event('PayClose', $pay_info);
foreach ($event_res as $v) {
if (isset($v[ 'code' ]) && $v[ 'code' ] < 0) {
return $this->error($v, '有其他方式正在支付中,请稍后再试');
}
}
}
model('pay')->update(['mch_info' => ''], [['out_trade_no', '=', $out_trade_no]]);
return $this->success();
}
/**
* 支付绑定商户信息
* @param $out_trade_no
* @param $json_data
*/
public function bindMchPay($out_trade_no, $json_data)
{
$res = model('pay')->update([
'mch_info' => json_encode($json_data, JSON_UNESCAPED_UNICODE),
], [['out_trade_no', '=', $out_trade_no]]);
return $this->success($res);
}
/**
* 获取支付方式
* @param array $params 'pay_scene' => ['wap', 'wechat', 'app', 'pc', 'wechat_applet']
* @return array
*/
public function getPayType($params = [])
{
$res = event('PayType', $params);
return $this->success($res);
}
/**
* 获取支付信息详情
* @param $out_trade_no
* @return array
*/
public function getPayInfo($out_trade_no)
{
$condition = [['out_trade_no', '=', $out_trade_no]];
return $this->getInfo($condition, '*');
}
/**
* 获取支付信息
* @param $condition
* @param string $field
* @return array
*/
public function getInfo($condition, $field = '*')
{
$info = model('pay')->setIsCache(0)->getInfo($condition, $field);
return $this->success($info);
}
/**
* 支付记录
* @param array $condition
* @param int $page
* @param int $page_size
* @param string $order
* @param string $field
* @return array
*/
public function getPayPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = '*')
{
$list = model('pay')->pageList($condition, $field, $order, $page, $page_size);
return $this->success($list);
}
/**
* 支付统计
* @param $condition
* @return array
*/
public function getPayStatistics($condition)
{
$statistics_array = array (
'count' => model('pay')->getCount($condition),
'sum_money' => model('pay')->getSum($condition, 'pay_money')
);
return $statistics_array;
}
/****************************************************************退款**************************************************************/
/**
* 创建退款流水号
*/
public function createRefundNo()
{
$cache = Cache::get('pay_refund_out_trade_no' . time());
if (empty($cache)) {
Cache::set('niutk' . time(), 1000);
$cache = Cache::get('pay_refund_out_trade_no' . time());
} else {
$cache = $cache + 1;
Cache::set('pay_refund_out_trade_no' . time(), $cache);
}
$no = date('Ymdhis', time()) . rand(1000, 9999) . $cache;
return $no;
}
/**
* 原路退款
* @param $refund_no
* @param $refund_fee
* @param $out_trade_no
* @param $refund_desc
* @param number $total_fee 实际支付金额
* @param $site_id
* @param int $refund_type 退款方式 1 原路退款 2 线下支付
* @param int $order_goods_id
* @param int $is_video_number
* @return array|mixed|void
*/
public function refund($refund_no, $refund_fee, $out_trade_no, $refund_desc, $total_fee, $site_id, $refund_type, $order_goods_id = 0, $is_video_number = 0)
{
//是否是原理退款方式退款
if ($refund_type == 1) {
$pay_info_result = $this->getPayInfo($out_trade_no);
$pay_info = $pay_info_result[ 'data' ];
if (empty($pay_info))
return $this->error('', '付款记录不存在!');
$data = array (
'refund_no' => $refund_no,
'refund_fee' => $refund_fee,
'refund_desc' => $refund_desc,
'pay_info' => $pay_info,
'total_fee' => $total_fee,
'site_id' => $site_id,
'order_goods_id' => $order_goods_id,
'is_video_number' => $is_video_number,
'out_aftersale_id' => 0
);
if (!empty($order_goods_id)) {
$order_goods_info = model('order_goods')->getInfo([['order_goods_id', '=', $order_goods_id]]);
if (!empty($order_goods_info)) {
$data[ 'out_aftersale_id' ] = $order_goods_info[ 'out_aftersale_id' ];
}
}
//退款金额许大于0
if ($refund_fee > 0 && !in_array($pay_info[ 'pay_type' ], ['offlinepay', 'BALANCE', 'ONLINE_PAY'])) {
$result = event('PayRefund', $data, true);
if (empty($result))
return $this->error('', '找不到可用的退款方式!');
if ($result[ 'code' ] < 0)
return $result;
}
}
$refund_data = array (
'refund_no' => $refund_no,
'refund_fee' => $refund_fee,
'total_money' => $total_fee,
'refund_type' => $refund_type,
'site_id' => $site_id,
'out_trade_no' => $out_trade_no,
);
$this->addRefundPay($refund_data);
return $this->success();
}
/**
* 添加退款记录
* @param $data
* @return array
*/
public function addRefundPay($data)
{
$data[ 'create_time' ] = time();
$data[ 'refund_detail' ] = '支付交易号:' . $data[ 'out_trade_no' ] . ',退款金额:' . $data[ 'refund_fee' ] . '元';
$res = model('pay_refund')->add($data);
if ($res == false) {
return $this->error($res);
}
return $this->success($res);
}
/**
* 查询转账方式
* @param $site_id
* @return array
*/
public function getTransferType($site_id)
{
$data = array (
'bank' => '银行卡'
);
$temp_array = event('TransferType', ['site_id' => $site_id]);
if (!empty($temp_array)) {
foreach ($temp_array as $k => $v) {
$data[ $v[ 'type' ] ] = $v[ 'type_name' ];
}
}
return $data;
}
/**
* 使用余额
* @param $pay_info
* @return array|mixed|void
*/
public function useBalance($pay_info)
{
// 查询是否可使用余额
$balance_config = (new OrderConfig())->getBalanceConfig($pay_info[ 'site_id' ])[ 'data' ][ 'value' ];
if (!$balance_config[ 'balance_show' ]) return $this->success();
// 查询会员当前可用余额
$balance_data = (new Member())->getMemberUsableBalance($pay_info[ 'site_id' ], $pay_info[ 'member_id' ]);
if ($balance_data[ 'code' ] != 0) return $balance_data;
$balance_data = $balance_data[ 'data' ];
if ($balance_data[ 'usable_balance' ] <= 0) return $this->success();
$data = [
'pay_money' => $pay_info[ 'pay_money' ],
'member_id' => $pay_info[ 'member_id' ]
];
if ($balance_data[ 'balance' ] > 0) {
$data[ 'balance' ] = bccomp($balance_data[ 'balance' ], $data[ 'pay_money' ], 2) == 1 ? $data[ 'pay_money' ] : $balance_data[ 'balance' ];
$data[ 'pay_money' ] -= $data[ 'balance' ];
}
if ($balance_data[ 'balance_money' ] > 0 && $data[ 'pay_money' ] > 0) {
$data[ 'balance_money' ] = bccomp($balance_data[ 'balance_money' ], $data[ 'pay_money' ], 2) == 1 ? $data[ 'pay_money' ] : $balance_data[ 'balance_money' ];
$data[ 'pay_money' ] -= $data[ 'balance_money' ];
}
model('pay')->startTrans();
try {
model('pay')->update($data, [['out_trade_no', '=', $pay_info[ 'out_trade_no' ]]]);
if (isset($data[ 'balance' ]) && $data[ 'balance' ] > 0) model('member')->setInc([['site_id', '=', $pay_info[ 'site_id' ]], ['member_id', '=', $pay_info[ 'member_id' ]]], 'balance_lock', $data[ 'balance' ]);
if (isset($data[ 'balance_money' ]) && $data[ 'balance_money' ] > 0) model('member')->setInc([['site_id', '=', $pay_info[ 'site_id' ]], ['member_id', '=', $pay_info[ 'member_id' ]]], 'balance_money_lock', $data[ 'balance_money' ]);
if ($data[ 'pay_money' ] == 0) {
$res = $this->onlinePay($pay_info[ 'out_trade_no' ], 'BALANCE', '', '');
if ($res[ 'code' ] != 0) {
model('pay')->rollback();
return $res;
}
model('pay')->commit();
return $this->success(['pay_success' => 1]);
}
model('pay')->commit();
return $this->success();
} catch (\Exception $e) {
model('pay')->rollback();
return $this->error('', '支付冻结余额错误');
}
}
/**
* 重置支付
* @param $params
* @return array|mixed|void
*/
public function resetPay($params)
{
$out_trade_no = $params[ 'out_trade_no' ];
$pay_info = $this->getPayInfo($out_trade_no)[ 'data' ] ?? [];
if (empty($pay_info))
return $this->error();
$result = event('PayReset', $pay_info, true);//各种插件自己实现
if (empty($result)) {
switch ($pay_info[ 'event' ]) {
case 'OrderPayNotify':
$order_pay_model = new OrderPay();
$result = $order_pay_model->resetOrderTradeNo(['out_trade_no' => $out_trade_no]);
break;
}
}
if ($result[ 'code' ] < 0)
return $result;
return $result;
}
/**
* 支付编辑(切勿调用,收银业务专用)
* @param $data
* @param $condition
* @return array
*/
public function edit($data, $condition)
{
model('pay')->update($data, $condition);
return $this->success();
}
}

179
app/model/system/PayBalance.php Executable file
View File

@@ -0,0 +1,179 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use addon\cashier\model\order\CashierOrderPay;
use app\model\BaseModel;
use think\facade\Log;
/**
* 会员付款码
* Class PayBalance
* @package app\model\system
*/
class PayBalance extends BaseModel
{
/**
* 创建会员码生成记录
* @param $param
* @return array
*/
public function create($param)
{
model('pay_balance')->startTrans();
try {
$data = [
'auth_code' => $this->createAuthCode($param[ 'member_id' ]),
'site_id' => $param[ 'site_id' ],
'member_id' => $param[ 'member_id' ],
'create_time' => time(),
'expire_time' => time() + 120,
'dynamic_code' => rand(1000, 9999)
];
// 生成前将其他的失效
model('pay_balance')->delete([ [ 'site_id', '=', $param[ 'site_id' ] ], [ 'member_id', '=', $param[ 'member_id' ] ] ]);
$res = model('pay_balance')->add($data);
// 提交事务
model('pay_balance')->commit();
$barcode = getBarcode($data[ 'auth_code' ], '', 3);
$qrcode = qrcode($data[ 'auth_code' ], 'upload/qrcode/pay/', $data[ 'auth_code' ], 16);
$return = [
'auth_code' => $data[ 'auth_code' ],
'barcode' => 'data:image/png;base64,' . base64_encode(file_get_contents($barcode)),
'qrcode' => 'data:image/png;base64,' . base64_encode(file_get_contents($qrcode)),
'expire_time' => $data[ 'expire_time' ],
'dynamic_code' => $data[ 'dynamic_code' ]
];
// 删除
@unlink($barcode);
@unlink($qrcode);
return $this->success($return);
} catch (\Exception $e) {
model('pay_balance')->rollback();
Log::write('付款码生成失败:' . $e->getMessage() . $e->getFile() . $e->getLine());
return $this->error('', '付款码生成失败');
}
}
/**
* 付款码支付
* @param $auth_code
* @param $out_trade_no
* @return array
*/
public function pay($auth_code, $out_trade_no)
{
$pay_info = model('pay')->getInfo([ [ 'out_trade_no', '=', $out_trade_no ] ]);
if (empty($pay_info)) return $this->error('', '未获取到支付单据');
if ($pay_info[ 'pay_status' ] != 0) return $this->error('', '支付单据状态异常');
$pay_info[ 'pay_json' ] = !empty($pay_info[ 'pay_json' ]) ? json_decode($pay_info[ 'pay_json' ], true) : [];
$member_id = $pay_info[ 'pay_json' ][ 'member_id' ] ?? 0;
$site_id = $pay_info[ 'site_id' ];
$code_info = model('pay_balance')->getInfo([ [ 'auth_code', '=', $auth_code ] ]);
if (empty($code_info)) return $this->error('', '付款码已失效');
if ($code_info[ 'member_id' ] != $member_id) return $this->error('', '不是当前会员的付款码');
if ($code_info[ 'status' ] != 0) return $this->error('', '付款码状态异常');
if ($code_info[ 'expire_time' ] < time()) return $this->error('', '付款码已失效');
$member_info = model('member')->getInfo([ [ 'member_id', '=', $member_id ], [ 'site_id', '=', $site_id ], [ 'is_delete', '=', 0 ] ], 'balance,balance_money');
if (empty($member_info)) return $this->error('', '未查找到会员信息');
if (bccomp($pay_info[ 'pay_money' ], ( $member_info[ 'balance' ] + $member_info[ 'balance_money' ] ), 2) == 1) return $this->error('', '余额不足');
model('pay_balance')->startTrans();
try {
$cashier_order_pay = new CashierOrderPay();
$cache = $cashier_order_pay->getCache($out_trade_no)[ 'data' ];
$promotion = $cache[ 'promotion' ] ?? [];
$promotion[ 'is_use_balance' ] = 1;
$cache[ 'promotion' ] = $promotion;
$cashier_order_pay->setCache($out_trade_no, $cache);
$pay_data = [
'site_id' => $site_id,//站点id
'out_trade_no' => $out_trade_no,
'store_id' => 0,
'online_type' => 'online',
'pay_type' => 'BALANCE',
'member_id' => $member_id,
];
$res = ( new CashierOrderPay() )->doPay($pay_data);
if ($res[ 'code' ] != 0) {
model('pay_balance')->rollback();
return $res;
}
model('pay_balance')->update([ 'status' => 1, 'out_trade_no' => $pay_info[ 'out_trade_no' ], 'pay_time' => time() ], [ [ 'auth_code', '=', $auth_code ] ]);
model('pay_balance')->commit();
return $this->success([ 'out_trade_no' => $out_trade_no ]);
} catch (\Exception $e) {
model('pay_balance')->rollback();
Log::write('付款码支付扣款失败:' . $e->getMessage() . $e->getFile() . $e->getLine());
return $this->error('', '付款码支付扣款失败');
}
}
/**
* 查询信息
* @param $condition
* @param string $field
* @return array
*/
public function getInfo($condition, $field = '*')
{
$data = model('pay_balance')->getInfo($condition, $field);
return $this->success($data);
}
/**
* 创建会员支付码
*/
private function createAuthCode($member_id)
{
$code = [
rand(1000, 9999),
$member_id,
(int) date('dis')
];
$tmp = implode('', $code);
for ($i = 0; $i < ( 18 - strlen($tmp) ); $i++) {
$code[] = rand(0, 9);
}
shuffle($code);
return implode('', $code);
}
/**
* 检验付款码
* @param $code
* @param $member_id
* @return array
*/
public function checkPaymentCode($code, $member_id)
{
$condition = [
[ 'auth_code|dynamic_code', '=', $code ]
];
if (!empty($member_id)) {
$condition[] = [ 'member_id', '=', $member_id ];
}
$info = model('pay_balance')->getInfo($condition, 'id,member_id,expire_time');
if (empty($info)) return $this->error('', '无效付款码');
if ($info['expire_time'] < time()) return $this->error('', '付款码已失效');
model('pay_balance')->delete([ ['id', '=', $info['id'] ] ]);
return $this->success($info);
}
}

174
app/model/system/PayTransfer.php Executable file
View File

@@ -0,0 +1,174 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use think\facade\Cache;
use app\model\BaseModel;
/**
* 系统转账业务
*/
class PayTransfer extends BaseModel
{
const STATUS_WAIT = 0;
const STATUS_IN_PROCESS = 1;
const STATUS_SUCCESS = 2;
const STATUS_FAIL = 3;
/**
* 添加
* @param $param
* @return array|mixed|string|void
*/
public function add($param)
{
$data = [
'out_trade_no' => $this->createOutTradeNo(),
'real_name' => $param[ 'real_name' ],
'amount' => $param[ 'amount' ],
'desc' => $param['desc'],
'transfer_type' => $param['transfer_type'],
'account_number' => $param['account_number'],
'site_id' => $param['site_id'],
'is_weapp' => $param['is_weapp'],
'member_id' => $param['member_id'],
'from_type' => $param['from_type'],
'status' => self::STATUS_WAIT,
'create_time' => time(),
'relate_tag' => $param['relate_tag'] ?? ''
];
$id = model('pay_transfer')->add($data);
return $this->success($id);
}
/**
* 发起转账
* @param $from_type
* @param $relate_tag
* @return array|mixed|string|void
*/
public function transfer($from_type, $relate_tag,$transfer_check=false)
{
$info = model('pay_transfer')->getInfo([['from_type', '=', $from_type], ['relate_tag', '=', $relate_tag]]);
if(empty($info)){
return $this->error($info, '转账记录不存在');
}
//各自业务检测
if($transfer_check){
$check_res = event('PayTransferCheck', $info, true);
if(isset($check_res['code']) && $check_res['code'] < 0){
return $check_res;
}
}
$result = event('PayTransfer', $info, true);
if($result['code'] < 0){
return $result;
}
$result = $this->updateStatus($result['data'], $info['id']);
return $result;
}
/**
* 更新状态
* @param $result
* @param $id
* @return array|mixed|string|void
*/
public function updateStatus($data, $id)
{
$status = $data['status'] ?? self::STATUS_SUCCESS;
model('pay_transfer')->update([
'status' => $status,
'resp_data' => json_encode($data, JSON_UNESCAPED_UNICODE),
'update_time' => time(),
], [['id', '=', $id],['status', 'in', [self::STATUS_WAIT, self::STATUS_IN_PROCESS]]]);
if($status == self::STATUS_WAIT){
return $this->success($data);
}
if($status == self::STATUS_IN_PROCESS){
(new Cron())->addCron(1, 0, "查询转账结果", "CronPayTransferResult", time() + 10, $id);
}
$info = model('pay_transfer')->getInfo([['id', '=', $id]]);
$res = event('PayTransferNotify', $info, true);
return $res;
}
/**
* 创建支付流水号
*/
public function createOutTradeNo($member_id = 0)
{
$cache = Cache::get('pay_transfer_out_trade_no' . $member_id . time());
if (empty($cache)) {
Cache::set('pay_transfer_out_trade_no' . $member_id . time(), 1000);
$cache = Cache::get('pay_transfer_out_trade_no' . $member_id . time());
} else {
$cache = $cache + 1;
Cache::set('pay_transfer_out_trade_no' . $member_id . time(), $cache);
}
$no = time() . rand(1000, 9999) . $member_id . $cache;
return $no;
}
/**
* 查询支付结果
* @param $id
* @return array|mixed|string|void
*/
public function result($id)
{
$info = model('pay_transfer')->getInfo([['id', '=', $id]]);
if(empty($info)){
return $this->error($info, '转账信息有误');
}
if($info['status'] != self::STATUS_IN_PROCESS){
return $this->error($info, '非转账中单据无需处理');
}
$result = event('PayTransferResult', $info, true);
if(!isset($result['code']) || $result['code'] < 0){
return $result;
}
return $this->updateStatus($result['data'], $id);
}
/**
* 修改
* @param $data
* @param $where
* @return array
*/
public function editTransfer($data,$where)
{
$result = model("pay_transfer")->update($data,$where);
return $this->success($result);
}
/**
* 获取单条结果集
* @param $condition
* @param string $field
* @return array
*/
public function getTransferInfo($condition,$field="*")
{
$result = model("pay_transfer")->getInfo($condition,$field);
return $this->success($result);
}
}

594
app/model/system/Poster.php Executable file
View File

@@ -0,0 +1,594 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use addon\postertemplate\model\PosterTemplate as PosterTemplateModel;
use addon\store\model\Config as StoreConfig;
use app\model\BaseModel;
use app\model\upload\Upload;
use app\model\web\Config;
use extend\multitype;
use extend\Poster as PosterExtend;
/**
* 海报生成类
*/
class Poster extends BaseModel
{
/**
* 商品海报
*/
public function goods($app_type, $page, $qrcode_param, $promotion_type, $site_id, $store_id = 0)
{
try {
$goods_info = $this->getGoodsInfo($qrcode_param[ 'goods_id' ], $site_id, $store_id);
if (empty($goods_info)) return $this->error('未获取到商品信息');
$qrcode_info = $this->getGoodsQrcode($app_type, $page, $qrcode_param, $promotion_type, $site_id);
if ($qrcode_info[ 'code' ] < 0) return $qrcode_info;
//判断海报是否存在或停用
$template_info = $this->getTemplateInfo($goods_info[ 'template_id' ]);
$site_model = new Site();
$condition = array (
[ "site_id", "=", $site_id ]
);
$site_info = $site_model->getSiteInfo($condition);
if (!empty($qrcode_param[ 'source_member' ])) {
$member_info = $this->getMemberInfo($qrcode_param[ 'source_member' ]);
}
$upload_config_model = new Config();
$upload_config_result = $upload_config_model->getDefaultImg($site_id);
if (empty($goods_info[ 'template_id' ]) || empty($template_info) || $template_info[ 'template_status' ] == 0) {
$poster_width = 720;
$poster_height = 1150;
$poster = new PosterExtend($poster_width, $poster_height);
$option = [
[
'action' => 'setBackground', // 设背景色
'data' => [ 255, 255, 255 ]
],
[
'action' => 'imageCopy', // 写入商品图
'data' => [
img($goods_info['sku_image'], 'big'),
50,
165,
620,
620,
'square',
true,
1
]
],
[
'action' => 'imageText', // 写入商品名称
'data' => [
$goods_info[ 'goods_name' ],
22,
[ 35, 35, 35 ],
50,
915,
360,
2,
true,
1
]
],
[
'action' => 'imageCopy', // 写入商品二维码
'data' => [
$qrcode_info[ 'data' ][ 'path' ],
435,
825,
240,
240,
'square',
0,
1
]
],
[
'action' => 'imageText', // 写入提示
'data' => [
'长按识别二维码',
19,
[ 102, 102, 102 ],
465,
1110,
490,
1,
1,
1
]
],
[
'action' => 'imageText', // 写入商品价格单位
'data' => [
'¥',
27,
[ 255, 0, 0 ],
50,
860,
490,
2,
true,
1
]
],
[
'action' => 'imageText', // 写入商品价格
'data' => [
$goods_info[ 'discount_price' ],
30,
[ 255, 0, 0 ],
78,
862,
490,
2,
true,
1
]
],
];
if (!empty($member_info)) {
$member_option = [
[
'action' => 'imageCircularCopy', // 写入用户头像
'data' => [
!empty($member_info[ 'headimg' ]) ? $member_info[ 'headimg' ] : $upload_config_result[ 'data' ][ 'value' ][ 'head' ],
50,
30,
100,
100
]
],
[
'action' => 'imageText', // 写入分享人昵称
'data' => [
$member_info[ 'nickname' ],
22,
[ 10, 10, 10 ],
170,
80,
580,
1,
1,
1
]
],
[
'action' => 'imageText', // 写入分享人昵称
'data' => [
'分享给你一个商品',
18,
[ 102, 102, 102 ],
170,
115,
580,
1,
1,
1
]
]
];
$option = array_merge($option, $member_option);
}
} else {
$condition = [
[ 'template_id', '=', $goods_info[ 'template_id' ] ],
[ 'site_id', '=', $site_id ]
];
$poster_template_model = new PosterTemplateModel();
$poster_data = $poster_template_model->getPosterTemplateInfo($condition);
$poster_data[ 'data' ][ 'template_json' ] = json_decode($poster_data[ 'data' ][ 'template_json' ], true);
$poster_width = 720;
$poster_height = 1280;
$poster = new PosterExtend($poster_width, $poster_height);
$fontRate = 0.725; // 20px 等于 14.5磅,换算比率 1px = 0.725磅
if ($goods_info[ 'price' ] == 0) {
$line = '一一一';
} else {
$line = '一一一一';
}
if (!empty($poster_data[ 'data' ][ 'background' ])) {
$background = str_replace(" ", "", img($poster_data[ 'data' ][ 'background' ]));
list($width, $height, $type, $attr) = getimagesize($background);
$height = 720 * $height / $width;
$back_ground = [
'action' => 'imageCopy', // 写入背景图
'data' => [
img($poster_data[ 'data' ][ 'background' ]),
0,
0,
$poster_width,
$poster_height,
'square',
true,
1
]
];
} else {
$back_ground = [
'action' => 'setBackground', // 设背景色
'data' => [ 255, 255, 255 ]
];
}
$ground = [ [
'action' => 'setBackground', // 设背景色
'data' => [ 255, 255, 255 ]
] ];
$option = [
$back_ground,
[
'action' => 'imageText', // 写入店铺名称
'data' => [
$site_info[ 'data' ][ 'site_name' ],
$poster_data[ 'data' ][ 'template_json' ][ 'store_name_font_size' ] * $fontRate * 2,
hex2rgb($poster_data[ 'data' ][ 'template_json' ][ 'store_name_color' ]),
$poster_data[ 'data' ][ 'template_json' ][ 'store_name_left' ] * 2,
( $poster_data[ 'data' ][ 'template_json' ][ 'store_name_top' ] + $poster_data[ 'data' ][ 'template_json' ][ 'store_name_font_size' ] ) * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'store_name_width' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'store_name_height' ] * 2,
true,
$poster_data[ 'data' ][ 'template_json' ][ 'store_name_is_show' ]
]
],
[
'action' => 'imageCopy', // 店铺logo
'data' => [
!empty($site_info[ 'data' ][ 'logo_square' ]) ? $site_info[ 'data' ][ 'logo_square' ] : getUrl() . '/app/shop/view/public/img/shop_logo.png',
$poster_data[ 'data' ][ 'template_json' ][ 'store_logo_left' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'store_logo_top' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'store_logo_width' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'store_logo_height' ] * 2,
'square',
true,
$poster_data[ 'data' ][ 'template_json' ][ 'store_logo_is_show' ]
]
],
[
'action' => 'imageCopy', // 写入商品图
'data' => [
img($goods_info[ 'sku_image' ], 'big'),
$poster_data[ 'data' ][ 'template_json' ][ 'goods_img_left' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_img_top' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_img_width' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_img_height' ] * 2,
!empty($poster_data[ 'data' ][ 'template_json' ][ 'goods_img_shape' ]) ? $poster_data[ 'data' ][ 'template_json' ][ 'goods_img_shape' ] : 'square',
0,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_img_is_show' ]
]
],
[
'action' => 'imageText', // 写入商品名称
'data' => [
$goods_info[ 'goods_name' ],
$poster_data[ 'data' ][ 'template_json' ][ 'goods_name_font_size' ] * $fontRate * 2,
hex2rgb($poster_data[ 'data' ][ 'template_json' ][ 'goods_name_color' ]),
$poster_data[ 'data' ][ 'template_json' ][ 'goods_name_left' ] * 2,
( $poster_data[ 'data' ][ 'template_json' ][ 'goods_name_top' ] + $poster_data[ 'data' ][ 'template_json' ][ 'goods_name_font_size' ] ) * 2 + 10,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_name_width' ] * 2,
1,//文本行数 $poster_data['data']['template_json']['goods_name_height']*2,
true,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_name_is_show' ]
]
],
[
'action' => 'imageCopy', // 写入商品二维码
'data' => [
$qrcode_info[ 'data' ][ 'path' ],
$poster_data[ 'data' ][ 'qrcode_left' ] * 2,
$poster_data[ 'data' ][ 'qrcode_top' ] * 2,
$poster_data[ 'data' ][ 'qrcode_width' ] * 2,
$poster_data[ 'data' ][ 'qrcode_height' ] * 2,
'square',
0,
1
]
],
[
'action' => 'imageText', // 写入商品价格
'data' => [
'¥' . $goods_info[ 'discount_price' ],
$poster_data[ 'data' ][ 'template_json' ][ 'goods_price_font_size' ] * $fontRate * 2,
hex2rgb($poster_data[ 'data' ][ 'template_json' ][ 'goods_price_color' ]),
$poster_data[ 'data' ][ 'template_json' ][ 'goods_price_left' ] * 2,
( $poster_data[ 'data' ][ 'template_json' ][ 'goods_price_top' ] + $poster_data[ 'data' ][ 'template_json' ][ 'goods_price_font_size' ] ) * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_price_width' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_price_height' ] * 2,
true,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_price_is_show' ]
]
],
];
if ($goods_info[ 'market_price' ] > 0) {
$market_price = [
[
'action' => 'imageText', // 写入商品划线价格
'data' => [
'¥' . $goods_info[ 'market_price' ],
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_font_size' ] * $fontRate * 2,
hex2rgb($poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_color' ]),
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_left' ] * 2,
( $poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_top' ] + $poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_font_size' ] ) * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_width' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_height' ] * 2,
true,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_is_show' ]
]
],
[
'action' => 'imageText', // 写入线
'data' => [
$line,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_font_size' ] * $fontRate * 2,
hex2rgb($poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_color' ]),
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_left' ] * 2 - 5,
( $poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_top' ] + $poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_font_size' ] ) * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_width' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_height' ] * 2,
true,
$poster_data[ 'data' ][ 'template_json' ][ 'goods_market_price_is_show' ]
]
],
];
$option = array_merge($option, $market_price);
}
if (!empty($member_info)) {
$member_option = [
[
'action' => 'imageCopy', // 写入用户头像
'data' => [
!empty($member_info[ 'headimg' ]) ? $member_info[ 'headimg' ] : $upload_config_result[ 'data' ][ 'value' ][ 'head' ],
$poster_data[ 'data' ][ 'template_json' ][ 'headimg_left' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'headimg_top' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'headimg_width' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'headimg_height' ] * 2,
!empty($poster_data[ 'data' ][ 'template_json' ][ 'headimg_shape' ]) ? $poster_data[ 'data' ][ 'template_json' ][ 'headimg_shape' ] : 'square',
0,
$poster_data[ 'data' ][ 'template_json' ][ 'headimg_is_show' ]
]
],
[
'action' => 'imageText', // 写入分享人昵称
'data' => [
$member_info[ 'nickname' ],
$poster_data[ 'data' ][ 'template_json' ][ 'nickname_font_size' ] * $fontRate * 2,
hex2rgb($poster_data[ 'data' ][ 'template_json' ][ 'nickname_color' ]),
$poster_data[ 'data' ][ 'template_json' ][ 'nickname_left' ] * 2,
( $poster_data[ 'data' ][ 'template_json' ][ 'nickname_top' ] + $poster_data[ 'data' ][ 'template_json' ][ 'nickname_font_size' ] ) * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'nickname_width' ] * 2,
$poster_data[ 'data' ][ 'template_json' ][ 'nickname_height' ] * 2,
0,
$poster_data[ 'data' ][ 'template_json' ][ 'nickname_is_show' ]
]
],
];
$option = array_merge($ground, $option, $member_option);
}
}
$option_res = $poster->create($option);
if (is_array($option_res)) return $option_res;
$res = $option_res->jpeg('upload/poster/goods', 'goods_' . $promotion_type . '_' . $qrcode_param[ 'goods_id' ] . '_' . $qrcode_param[ 'source_member' ] . '_' . time() . '_' . $app_type);
if ($res[ 'code' ] == 0) {
$upload = new Upload($site_id);
$cloud_res = $upload->fileCloud($res[ 'data' ][ 'path' ]);
if ($cloud_res[ 'code' ] >= 0) {
return $this->success([ "path" => $cloud_res[ 'data' ] ]);
} else {
return $this->error();
}
}
return $res;
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* 获取用户信息
* @param unknown $member_id
*/
private function getMemberInfo($member_id)
{
$info = model('member')->getInfo([ 'member_id' => $member_id ], 'nickname,headimg');
return $info;
}
/**
* 获取商品信息
* @param $goods_id
* @param $site_id
* @param $store_id
* @return mixed
*/
private function getGoodsInfo($goods_id, $site_id, $store_id)
{
$field = 'g.goods_id,g.goods_name,g.introduction,gs.price,gs.discount_price,g.goods_image,g.sku_id,gs.collect_num,g.template_id,g.market_price,gs.sku_image';
$join = [
[ 'goods_sku gs', 'gs.sku_id=g.sku_id', 'left' ]
];
if (!empty($store_id)) {
$store_config = ( new StoreConfig() )->getStoreBusinessConfig($site_id)[ 'data' ][ 'value' ];
if ($store_config[ 'store_business' ] == 'store') {
$join[] = [ 'store_goods_sku sgs', 'gs.sku_id = sgs.sku_id and sgs.store_id=' . $store_id, 'left' ];
$field = str_replace('gs.price', 'IFNULL(IF(g.is_unify_price = 1,gs.price,sgs.price), gs.price) as price', $field);
$field = str_replace('gs.discount_price', 'IFNULL(IF(g.is_unify_price = 1,gs.discount_price,sgs.price), gs.discount_price) as discount_price', $field);
}
}
$info = model('goods')->getInfo([ 'g.goods_id' => $goods_id ], $field, 'g', $join);
return $info;
}
/**
* 获取商品二维码
* @param unknown $app_type 请求类型
* @param unknown $page uniapp页面路径
* @param unknown $qrcode_param 二维码携带参数
* @param string $promotion_type 活动类型 null为无活动
*/
private function getGoodsQrcode($app_type, $page, $qrcode_param, $promotion_type, $site_id)
{
$res = event('Qrcode', [
'site_id' => $site_id,
'app_type' => $app_type,
'type' => 'create',
'data' => $qrcode_param,
'page' => $page,
'qrcode_path' => 'upload/qrcode/goods',
'qrcode_name' => 'goods_' . $promotion_type . '_' . $qrcode_param[ 'goods_id' ] . '_' . $qrcode_param[ 'source_member' ] . '_' . $site_id,
], true);
return $res;
}
/**
* 获取海报信息
* @param unknown $template_id
*/
private function getTemplateInfo($template_id)
{
$info = model('poster_template')->getInfo([ 'template_id' => $template_id ], 'template_id,template_status');
return $info;
}
/**
* 分享图片
* @param $page
* @param $qrcode_param
* @param $site_id
* @param int $store_id
* @return array|multitype|PosterExtend|string|string[]
*/
public function shareImg($page, $qrcode_param, $site_id, $store_id = 0)
{
try {
$goods_info = $this->getGoodsInfo($qrcode_param[ 'goods_id' ], $site_id, $store_id);
if (empty($goods_info)) return $this->error('未获取到商品信息');
// $file_path = 'upload/share_img/goods_'.$goods_info['goods_id'] .'/sku_'.$goods_info['sku_id'] .'.jpg';
// if (file_exists($file_path)) return $this->success(['path' => $file_path]);
$poster_width = 600;
$poster_height = 480;
$poster = new PosterExtend($poster_width, $poster_height);
$option = [
[
'action' => 'setBackground', // 设背景色
'data' => [ 255, 255, 255 ]
],
[
'action' => 'imageCopy', // 商品图
'data' => [
img($goods_info[ 'sku_image' ], 'big'),
30,
50,
200,
200,
'square',
50,
1
]
],
[
'action' => 'imageText', // 写入商品名称
'data' => [
$goods_info[ 'goods_name' ],
25,
[ 51, 51, 51 ],
250,
100,
330,
2,
false,
1
]
],
[
'action' => 'imageText', // 写入商品价格
'data' => [
'¥',
15,
[ 255, 0, 0 ],
250,
230,
300,
2,
false,
1,
PUBLIC_PATH . 'static/font/custom.ttf'
]
],
[
'action' => 'imageText', // 写入商品价格
'data' => [
$goods_info[ 'discount_price' ],
32,
[ 255, 0, 0 ],
265,
230,
300,
2,
false,
1,
PUBLIC_PATH . 'static/font/custom.ttf'
]
],
[
'action' => 'imageCopy', // 背景图
'data' => [
'upload/share_img/bg/goods_1.png',
0,
0,
600,
480,
'square',
0,
1
]
],
];
$option_res = $poster->create($option);
if (is_array($option_res)) {
return $option_res;
}
$res = $option_res->jpeg('upload/share_img/goods_' . $goods_info[ 'goods_id' ],
'sku_' . $goods_info[ 'sku_id' ]);
return $res;
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* 删除分享图片
* @param int $goods_id
*/
public function clearShareImg(int $goods_id)
{
$dir = 'upload/share_img/goods_' . $goods_id;
@deleteDir($dir);
}
}

298
app/model/system/Promotion.php Executable file
View File

@@ -0,0 +1,298 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use app\model\order\Order;
use app\model\system\Config as ConfigModel;
/**
* 活动整体管理
*/
class Promotion extends BaseModel
{
/**
* 获取营销活动展示
*/
public function getPromotions($addons = [])
{
$show = event("ShowPromotion", []);
$shop_promotion = [];
foreach ($show as $k => $v) {
if (!empty($v[ 'shop' ])) {
if(empty($addons) || in_array($v['shop'][0]['name'], $addons)){
$shop_promotion = array_merge($shop_promotion, $v[ 'shop' ]);
}
}
}
return [
'shop' => $shop_promotion
];
}
/**
* 获取站点营销活动展示
* @param $site_id
* @return array
*/
public function getSitePromotions($site_id, $addons = [])
{
$show = event("ShowPromotion", []);
$promotion = [];
foreach ($show as $k => $v) {
if (!empty($v[ 'shop' ])) {
if(empty($addons) || in_array($v['shop'][0]['name'], $addons)){
$promotion = array_merge($promotion, $v[ 'shop' ]);
}
}
}
return $promotion;
}
/**
* 获取营销类型
*/
public function getPromotionType()
{
$promotion_type = event("PromotionType");
$promotion_type[] = [ "type" => "empty", "name" => "无营销活动" ];
return $promotion_type;
}
/**
* 获取营销活动总数
*/
public function getPromotionCount($site_id)
{
$show = event("ShowPromotion", [ 'count' => 1, 'site_id' => $site_id ]);
$count = 0;
foreach ($show as $k => $v) {
if (!empty($v[ 'shop' ])) {
$summary = $v[ 'shop' ][ 'summary' ] ?? [];
if (!empty($summary)) {
$count += $summary[ 'count' ];
}
}
if (!empty($v[ 'member' ])) {
$summary = $v[ 'member' ][ 'summary' ] ?? [];
if (!empty($summary)) {
$count += $summary[ 'count' ];
}
}
}
return $count;
}
/**
* 输入时间查看活动营销概况
* @param $start_time
* @param $end_time
* @param $site_id
* @return array
*/
public function getPromotionSummary($start_time, $end_time, $site_id, $addons = [])
{
$summary = event("ShowPromotion", [ 'summary' => 1, 'start_time' => $start_time, 'end_time' => $end_time, 'site_id' => $site_id, 'promotion_tyye' => 'time_limit' ]);
$promotion = [
'time_limit' => [], // 限时类活动
];
foreach ($summary as $k => $v) {
$shop = $v[ 'shop' ][ 0 ] ?? [];
if (empty($shop)) continue;
if(empty($addons) || in_array($shop['name'], $addons)) {
$summary_v = $shop['summary'] ?? [];
if (isset($summary_v['time_limit'])) {
unset($shop['summary']);
array_push($promotion['time_limit'], array_merge($shop, $summary_v['time_limit']));
}
}
}
return $this->success($promotion);
}
/**
* 设置活动专区页面配置
* @param $data
* @param $site_id
* @param $app_module
* @return array
*/
public function setPromotionZoneConfig($data, $site_id, $app_module = 'shop')
{
$config = new ConfigModel();
$config_key = strtoupper($data[ 'name' ]) . '_ZONE_CONFIG';
$res = $config->setConfig($data, $data[ 'title' ] . '活动专区页面配置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', $config_key ] ]);
return $res;
}
/**
* 获取活动专区页面配置
* @param $name
* @param $config_key
* @param $site_id
* @param $app_module
* @return array
*/
public function getPromotionZoneConfig($name, $site_id, $app_module = 'shop')
{
$config = new ConfigModel();
$config_key = strtoupper($name) . '_ZONE_CONFIG';
$res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', $config_key ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$promotion_zone_config = event('PromotionZoneConfig', [ 'name' => $name ], true);
$res[ 'data' ][ 'value' ] = $promotion_zone_config[ 'value' ] ?? '';
}
return $res;
}
/**
* 获取营销配置
* @param $start_time
* @param $end_time
* @param $site_id
* @return array
*/
public function getPromotionConfig($start_time, $end_time, $site_id, $addons = [])
{
$promotion = event("ShowPromotion", [
'summary' => 1,
'start_time' => $start_time,
'end_time' => $end_time,
'site_id' => $site_id,
'promotion_type' => 'unlimited_time'
]);
$promotion_data = [];
foreach ($promotion as $key => $val){
if(!empty($val[ 'shop' ][ 0 ])){
if(empty($addons) || in_array($val['shop'][0]['name'], $addons)){
$shop = $val[ 'shop' ][0] ?? [];
if(empty($shop['summary'])){
unset($promotion[$key]);
}else{
array_push($promotion_data, array_merge($shop, $shop['summary']['unlimited_time']));
}
}
}
}
return $this->success($promotion_data);
}
/**
* 获取营销数据统计
* @param $start_time
* @param $end_time
* @param $site_id
* @return array
*/
public function getPromotionStat($start_time, $end_time, $site_id)
{
$promotion = event("ShowPromotion", [
'summary' => 1,
'start_time' => $start_time,
'end_time' => $end_time,
'site_id' => $site_id
]);
$promotion_data = [
'promotion_num' => 0, // 活动数量
'in_progress_num' => 0, // 进行中活动数量,
'order_num' => 0
];
foreach ($promotion as $k => $v) {
$shop = $v[ 'shop' ][ 0 ] ?? [];
if (empty($shop)) continue;
$promotion_data[ 'promotion_num' ] += 1;
$summary_v = $shop[ 'summary' ] ?? [];
if (isset($summary_v[ 'time_limit' ])) {
$promotion_data[ 'in_progress_num' ] += $summary_v[ 'time_limit' ][ 'count' ];
}
}
$promotion_data['order_num'] = ( new Order() )->getOrderCount([ [ 'site_id', '=', $site_id ], [ 'promotion_type', '<>', '' ], [ 'pay_status', '=', 1 ] ], 'order_id')[ 'data' ];
return $this->success($promotion_data);
}
public function getUnlimitedTimePromotion()
{
// 不限时类的活动
}
/**
* 获取推广二维码
* @param $param
* @return array
*/
public function getPromotionQrcode($param)
{
try{
$page_name = $param['page_name'];
$option = $param['option'];
$app_type = $param['app_type'];
$site_id = $param['site_id'];
//找到页面配置
$event_res = event('PromotionPage');
$page_info = null;
foreach($event_res as $list){
foreach ($list as $info){
if($page_name == $info['name']){
$page_info = $info;
break 2;
}
}
}
if(empty($page_info)){
return $this->error(null, '页数数据有误');
}
//二维码名称
$qrcode_name_arr = [];
foreach ($option as $key=>$val){
$qrcode_name_arr[] = $key.'_'.$val;
}
$qrcode_name = join('_', $qrcode_name_arr);
//路径数据
$wap_url = $page_info['wap_url'];
$url_data = parse_url($wap_url);
parse_str($url_data['query'], $query_data);
foreach ($query_data as $key=>$val){
if(!isset($option[$key])) return $this->error(null, 'option缺少'.$key.'参数');
$query_data[$key] = $option[$key];
}
$params = [
'site_id' => $site_id,
'data' => $query_data,
'page' => $url_data['path'],
'app_type' => $app_type,
'qrcode_path' => 'upload/qrcode/'.strtolower($page_name),
'qrcode_name' => $qrcode_name,
];
$res = event('PromotionQrcode', $params, true);
return $this->success($res);
}catch(\Exception $e){
return $this->error([
'file' => $e->getFile(),
'line' => $e->getLine(),
'message' => $e->getMessage(),
], '生成二维码失败');
}
}
}

84
app/model/system/Qrcode.php Executable file
View File

@@ -0,0 +1,84 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use app\model\web\Config as ConfigModel;
use extend\QRcode as QRcodeExtend;
/**
* 二维码生成类
*/
class Qrcode extends BaseModel
{
public function createQrcode(array $param)
{
try {
$checkpath_result = $this->checkPath($param[ 'qrcode_path' ]);
if ($checkpath_result[ "code" ] != 0) return $checkpath_result;
$urlParam = '';
if (!empty($param[ 'data' ])) {
foreach ($param[ 'data' ] as $key => $value) {
if ($urlParam == '') $urlParam .= '?' . $key . '=' . $value;
else $urlParam .= '&' . $key . '=' . $value;
}
}
$domain = getH5Domain();
if ($param[ 'app_type' ] == 'pc') {
$config_model = new ConfigModel();
$domain = $config_model->getPcDomainName()[ 'data' ][ 'value' ][ 'domain_name_pc' ];
}
$url = $domain . $param[ 'page' ] . $urlParam;
$filename = $param[ 'qrcode_path' ] . '/' . $param[ 'qrcode_name' ] . '_' . $param[ 'app_type' ] . '.png';
if ($param[ 'type' ] == 'create') {
delFile($filename);
}
QRcodeExtend::png($url, $filename, 'L', $param[ 'qrcode_size' ] ?? 16, 1);
return $this->success([ 'type' => 'h5', 'path' => $filename, 'url' => $url ]);
} catch (\Exception $e) {
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");
}
/**
* 生成base64格式二维码
* @param $text
* @return array
*/
public function createBase64Qrcode($text)
{
ob_start();
QRcodeExtend::png($text, false, 'L', 4, 1);
$image_string = base64_encode(ob_get_contents());
ob_end_clean();
$base_64 = "data:image/png;base64,".$image_string;
return $this->success($base_64);
}
}

63
app/model/system/Servicer.php Executable file
View File

@@ -0,0 +1,63 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 山西牛酷信息科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use app\model\system\Config as ConfigModel;
/**
* 客服配置
*/
class Servicer extends BaseModel
{
/**
* 设置客服配置
* @param $data
* @return array
*/
public function setServicerConfig($data)
{
$config_model = new ConfigModel();
$res = $config_model->setConfig($data, '客服配置', 1, [ [ 'site_id', '=', 1 ], [ 'app_module', '=', 'shop' ], [ 'config_key', '=', 'SRRVICER_ROOT_CONFIG' ] ]);
return $res;
}
/**
* 获取客服配置
*/
public function getServicerConfig()
{
$config_model = new ConfigModel();
$res = $config_model->getConfig([ [ 'site_id', '=', 1 ], [ 'app_module', '=', 'shop' ], [ 'config_key', '=', 'SRRVICER_ROOT_CONFIG' ] ]);
if (empty($res[ 'data' ][ 'value' ])) {
$res[ 'data' ][ 'value' ] = [
'h5' => [
'type' => 'none'
],
'weapp' => [
'type' => 'none'
],
'pc' => [
'type' => 'none'
],
'aliapp' => [
'type' => 'none'
],
];
}
$res[ 'data' ][ 'value' ][ 'h5' ][ 'type' ] = $res[ 'data' ][ 'value' ][ 'h5' ][ 'type' ] ?? 'none';
$res[ 'data' ][ 'value' ][ 'weapp' ][ 'type' ] = $res[ 'data' ][ 'value' ][ 'weapp' ][ 'type' ] ?? 'none';
$res[ 'data' ][ 'value' ][ 'pc' ][ 'type' ] = $res[ 'data' ][ 'value' ][ 'pc' ][ 'type' ] ?? 'none';
$res[ 'data' ][ 'value' ][ 'aliapp' ][ 'type' ] = $res[ 'data' ][ 'value' ][ 'aliapp' ][ 'type' ] ?? 'none';
return $res;
}
}

78
app/model/system/Site.php Executable file
View File

@@ -0,0 +1,78 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use app\model\upload\Upload;
use think\facade\Cache;
/**
* 站点管理
* @author Administrator
*
*/
class Site extends BaseModel
{
public $cache_model = 'cache_model_site';
/**
* 添加站点
* @param $data
* @return array
*/
public function addSite($data)
{
$res = model('site')->add($data);
return $this->success($res);
}
/**
* getSiteInfo 获取站点详情
* @param $condition
* @param string $fields
* @return array
*/
public function getSiteInfo($condition, $fields = '*')
{
$res = model('site')->getInfo($condition, $fields);
return $this->success($res);
}
/**
* 修改商城站点信息
* @param $site_data
* @param $condition
* @return int
*/
public function editSite($site_data, $condition)
{
$site_info = $this->getSiteInfo($condition);
if($site_info['data'] && $site_data['logo'] && $site_info['data']['logo'] != $site_data['logo']){
$upload_model = new Upload();
$upload_model->deletePic($site_info['data']['logo'], $site_info['data']['site_id']);
}
if($site_info['data'] && !empty($site_data['logo_square']) && $site_info['data']['logo_square'] != $site_data['logo_square']){
$upload_model = new Upload();
$upload_model->deletePic($site_info['data']['logo_square'], $site_info['data']['site_id']);
}
$res = model('site')->update($site_data, $condition);
if($res && $site_data['logo']){
if(file_exists($site_data['logo']))
{
copy($site_data['logo'],"public/static/img/default_img/login.png");
}
}
Cache::tag($this->cache_model )->clear();
return $this->success($res);
}
}

60
app/model/system/SplitWord.php Executable file
View File

@@ -0,0 +1,60 @@
<?php
namespace app\model\system;
use app\model\BaseModel;
use extend\BaiDuApi;
use think\facade\Log;
class SplitWord extends BaseModel
{
protected $table = 'split_word';
/**
* 获取拆词
* @param $keyword
* @return array
*/
public function getSplitWord($keyword): array
{
$result = $this->getInfo([['keyword','=',$keyword]]);
if($result['code'] == 0 && !empty($result['data']['result'])){
return $this->success(json_decode($result['data']['result']));
}
$config_model = new \app\model\web\Config();
$config = $config_model->getSplitWordConfig()['data']['value'];
if($config['is_open'] == 0){
return $this->success([$keyword]);
}
$result = (new BaiduApi($config))->splitWords($keyword);
if (!empty($result)){
$this->addSplitWord($keyword,$result);
return $this->success($result);
}
return $this->success([$keyword]);
}
public function getInfo($condition,$field = '*'): array
{
$result = model($this->table)->getInfo($condition,$field);
if(empty($result)){
return $this->error('暂无数据');
}
return $this->success($result);
}
public function addSplitWord($keyword,$result): array
{
$result = model($this->table)->add([
'keyword' => $keyword,
'result' => json_encode($result,JSON_UNESCAPED_UNICODE),
'add_time'=>date('Y-m-d H:i:s')
]);
if(empty($result)){
return $this->error('添加失败');
}
return $this->success($result);
}
}

537
app/model/system/Stat.php Executable file
View File

@@ -0,0 +1,537 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\dict\order_refund\OrderRefundDict;
use app\model\BaseModel;
use app\model\order\OrderCommon;
use app\model\order\OrderRefund;
use app\model\stat\GoodsCartStat;
use app\model\stat\GoodsStat;
use app\model\stat\MemberStat;
use app\model\stat\MemberWithdrawStat;
use app\model\stat\OrderStat;
use app\model\stat\RechargeStat;
use app\model\stat\StatShop;
use app\model\stat\VisitStat;
use Carbon\Carbon;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Log;
/**
* 统计
* @author Administrator
*
*/
class Stat extends BaseModel
{
/**
* 添加店铺统计(按照天统计)
* @param array $data
*/
public function addShopStat($data)
{
$data = $this->getStatData($data);
return (new StatShop())->addShopStat($data);
}
/**
* 增加当日的时统计记录
* @param $data
* @param $carbon
* @return array
* @throws DbException
*/
public function addShopHourStat($data, $carbon)
{
$site_id = $data[ 'site_id' ];
// $carbon = Carbon::now();
$condition = [
'site_id' => $site_id,
'year' => $carbon->year,
'month' => $carbon->month,
'day' => $carbon->day,
'hour' => $carbon->hour
];
$info = model('stat_shop_hour')->getInfo($condition, 'id');
//在这里会整体处理总支出 总收入 总预计收入
$stat_data = $this->getStatData($data);
if (empty($info)) {
$insert_data = [
'site_id' => $site_id,
'year' => $carbon->year,
'month' => $carbon->month,
'day' => $carbon->day,
'day_time' => time(),
'create_time' => time(),
'hour' => $carbon->hour
];
$insert_data = array_merge($insert_data, $stat_data);
$res = model('stat_shop_hour')->add(
$insert_data
);
} else {
$update_data = array ();
if (!empty($stat_data)) {
foreach ($stat_data as $k => $v) {
if ($v > 0) {
$update_data[ $k ] = Db::raw($k . '+' . $v);
} else if ($v < 0) {
$update_data[ $k ] = Db::raw($k . '-' . abs($v));
}
}
}
if (!empty($update_data)) {
$res = Db::name('stat_shop_hour')->where($condition)
->update($update_data);
Cache::tag("cache_table" . "stat_shop_hour")->clear();
}
}
return $this->success($res ?? 0);
}
/**
* 整理数据
* @param $data
* @return mixed
*/
public function getStatData($data)
{
unset($data[ 'site_id' ]);
$order_pay_money = $data[ 'order_pay_money' ] ?? 0;//订单总额
$member_recharge_total_money = $data[ 'member_recharge_total_money' ] ?? 0;//会员充值总额
$member_level_total_money = $data[ 'member_level_total_money' ] ?? 0;//超级会员卡销售额
$member_giftcard_total_money = $data[ 'member_giftcard_total_money' ] ?? 0;//礼品卡订单总额
$earnings_total_money = $order_pay_money + $member_recharge_total_money + $member_level_total_money + $member_giftcard_total_money;//预计总收入
$order_refund_total_money = $data[ 'refund_total' ] ?? 0;//订单退款总额
$member_withdraw_total_money = $data[ 'member_withdraw_total_money' ] ?? 0;//会员提现总额
$expenditure_total_money = $order_refund_total_money + $member_withdraw_total_money;//总支出
$expected_earnings_total_money = $earnings_total_money - $expenditure_total_money;
Log::write('getStatData' . json_encode([ $earnings_total_money, $expenditure_total_money, $expected_earnings_total_money ]));
$data[ 'earnings_total_money' ] = $earnings_total_money;
$data[ 'expenditure_total_money' ] = $expenditure_total_money;
$data[ 'expected_earnings_total_money' ] = $expected_earnings_total_money;
$data = array_filter($data);
return $data;
}
/**
* 获取店铺统计(按照天查询)
* @param unknown $site_id 0表示平台
* @param unknown $year
* @param unknown $month
* @param unknown $day
*/
public function getStatShop($site_id, $year, $month, $day)
{
$condition = [
'site_id' => $site_id,
'year' => $year,
'month' => $month,
'day' => $day
];
$info = model('stat_shop')->setIsCache(0)->getInfo($condition, '*');
if (empty($info)) {
$condition[ 'day_time' ] = strtotime(date("{$year}-{$month}-{$day}"));
model('stat_shop')->add($condition);
$info = model('stat_shop')->getInfo($condition, '*');
}
$info[ 'goods_order_count' ] = numberFormat($info[ 'goods_order_count' ]);
return $this->success($info);
}
/**
* 获取店铺统计信息
* @param $site_id
* @param int $start_time
* @param int $end_time
* @return array
*/
public function getShopStatSum($site_id, $start_time = 0, $end_time = 0)
{
$condition = [
[ 'site_id', '=', $site_id ]
];
if (!empty($start_time)) {
$condition[] = [ 'day_time', '>=', $start_time ];
}
if (!empty($end_time)) {
$condition[] = [ 'day_time', '<=', $end_time ];
}
$field = array_map(function($field) {
switch ( $field ) {
case 'earnings_total_money':
return "sum(earnings_total_money) + sum(cashier_billing_money) + sum(cashier_buycard_money) as earnings_total_money";
break;
case 'expenditure_total_money':
return "sum(expenditure_total_money) as expenditure_total_money";
break;
case 'cashier_billing_money':
return "sum(cashier_billing_money) + sum(cashier_buycard_money) as cashier_order_pay_money";
break;
case 'refund_total':
return "sum(refund_total) as refund_total";
break;
case 'expected_earnings_total_money':
return "sum(expected_earnings_total_money) + sum(cashier_billing_money) + sum(cashier_buycard_money) as expected_earnings_total_money";
break;
case 'order_pay_count':
return "sum(order_pay_count) + sum(cashier_billing_count) + sum(cashier_buycard_count) as order_pay_count";
break;
default:
return "sum($field) as $field";
}
}, $this->getStatField());
$info = model('stat_shop')->getInfo($condition, $field);
if (isset($info[ 'goods_order_count' ])) {
$info[ 'goods_order_count' ] = numberFormat($info[ 'goods_order_count' ]);
}
return $this->success($info);
}
/**
* 获取店铺统计列表
* @param unknown $site_id
* @param unknown $start_time
*/
public function getShopStatList($site_id, $start_time, $end_time)
{
$condition = [
[ 'site_id', '=', $site_id ],
[ 'day_time', '>=', $start_time ],
[ 'day_time', '<=', $end_time ],
];
$list = model('stat_shop')->getList($condition, $this->handleStatField());
foreach ($list as $k => $v) {
$list[ $k ][ 'goods_order_count' ] = numberFormat($list[ $k ][ 'goods_order_count' ]);
}
return $this->success($list);
}
/**
* 处理查询字段
*/
private function handleStatField()
{
$fields = Db::name('stat_shop')->getTableFields('');
foreach ($fields as $k => $field) {
switch ( $field ) {
case 'earnings_total_money':
$fields[ $k ] = "earnings_total_money + cashier_billing_money + cashier_buycard_money as earnings_total_money";
break;
case 'expenditure_total_money':
$fields[ $k ] = "expenditure_total_money + cashier_refund_money as expenditure_total_money";
break;
case 'cashier_billing_money':
$fields[ $k ] = "cashier_billing_money + cashier_buycard_money as cashier_order_pay_money";
break;
case 'expected_earnings_total_money':
$fields[ $k ] = "expected_earnings_total_money + cashier_billing_money + cashier_buycard_money - cashier_refund_money as expected_earnings_total_money";
break;
case 'order_pay_count':
$fields[ $k ] = "order_pay_count + cashier_billing_count + cashier_buycard_count as order_pay_count";
break;
}
}
return implode(',', $fields);
}
/**
* 获取小时统计数据
* @param $site_id
* @param $year
* @param $month
* @param $day
* @return array
*/
public function getShopStatHourList($site_id, $year, $month, $day)
{
$condition = [
[ 'site_id', '=', $site_id ],
[ 'year', '=', $year ],
[ 'month', '=', $month ],
[ 'day', '=', $day ],
];
$list = model('stat_shop_hour')->getList($condition, $this->handleStatHourField(), 'id desc');
foreach ($list as $k => $v) {
$list[ $k ][ 'goods_order_count' ] = numberFormat($list[ $k ][ 'goods_order_count' ]);
}
return $this->success($list);
}
/**
* 处理查询字段
*/
private function handleStatHourField()
{
$fields = Db::name('stat_shop_hour')->getTableFields('');
foreach ($fields as $k => $field) {
switch ( $field ) {
case 'earnings_total_money':
$fields[ $k ] = "earnings_total_money + cashier_billing_money + cashier_buycard_money as earnings_total_money";
break;
case 'expenditure_total_money':
// $fields[ $k ] = "expenditure_total_money + cashier_refund_money as expenditure_total_money";
break;
case 'expected_earnings_total_money':
$fields[ $k ] = "expected_earnings_total_money + cashier_billing_money + cashier_buycard_money - cashier_refund_money as expected_earnings_total_money";
break;
case 'order_pay_count':
$fields[ $k ] = "order_pay_count + cashier_billing_count + cashier_buycard_count as order_pay_count";
break;
}
}
$fields[] = 'cashier_billing_money + cashier_buycard_money as cashier_order_pay_money';
return implode(',', $fields);
}
/**
* 获取天统计表统计字段
* @return array
*/
public function getStatField()
{
$fields = Db::name('stat_shop')->getTableFields('');
$fields = array_values(array_diff($fields, [ 'id', 'site_id', 'year', 'month', 'day', 'day_time' ]));
return $fields;
}
/**
* 获取时统计表统计字段
* @return array
*/
public function getStatHourField()
{
$fields = Db::name('stat_shop_hour')->getTableFields('');
$fields = array_values(array_diff($fields, [ 'id', 'site_id', 'year', 'month', 'day', 'hour', 'day_time' ]));
return $fields;
}
/**
* 获取商品销量排行榜
* @param $site_id
* @param string $start_time
* @param string $end_time
* @param $page_index
* @param $page_size
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getGoodsSaleNumRankingList($site_id, $start_time, $end_time, $page_index, $page_size)
{
$condition = [
[ 'o.site_id', '=', $site_id ],
[ 'o.pay_status', '=', 1 ],
[ 'g.is_delete', '=', 0 ],
[ 'o.order_status', '<>', OrderCommon::ORDER_CLOSE ],
[ 'og.refund_status', '<>', OrderRefundDict::REFUND_COMPLETE ]
];
if (!empty($start_time) && empty($end_time)) {
$condition[] = [ 'o.create_time', '>=', date_to_time($start_time) ];
} elseif (empty($start_time) && !empty($end_time)) {
$condition[] = [ 'o.create_time', '<=', date_to_time($end_time) ];
} elseif (!empty($start_time) && !empty($end_time)) {
$condition[] = [ 'o.create_time', 'between', [ date_to_time($start_time), date_to_time($end_time) ] ];
}
$join = [
[ 'order o', 'og.order_id = o.order_id', 'left' ],
[ 'goods g', 'og.goods_id = g.goods_id', 'right' ]
];
$list = model('order_goods')->pageList($condition, 'og.goods_id,g.goods_name,g.goods_state,SUM(og.num) AS sale_num', 'sale_num desc', $page_index, $page_size, 'og', $join, 'og.goods_id');
return $this->success($list);
}
/**
* 获取商品销量排行榜
* @param $site_id
* @param string $start_time
* @param string $end_time
* @param $page_index
* @param $page_size
* @return array
*/
public function getGoodsSaleMoneyRankingList($site_id, $start_time, $end_time, $page_index, $page_size)
{
$condition = [
[ 'o.site_id', '=', $site_id ],
[ 'o.pay_status', '=', 1 ],
[ 'g.is_delete', '=', 0 ],
[ 'o.order_status', '<>', OrderCommon::ORDER_CLOSE ],
[ 'og.refund_status', '<>', OrderRefundDict::REFUND_COMPLETE ]
];
if (!empty($start_time) && empty($end_time)) {
$condition[] = [ 'o.create_time', '>=', date_to_time($start_time) ];
} elseif (empty($start_time) && !empty($end_time)) {
$condition[] = [ 'o.create_time', '<=', date_to_time($end_time) ];
} elseif (!empty($start_time) && !empty($end_time)) {
$condition[] = [ 'o.create_time', 'between', [ date_to_time($start_time), date_to_time($end_time) ] ];
}
$join = [
[ 'order o', 'og.order_id = o.order_id', 'left' ],
[ 'goods g', 'og.goods_id = g.goods_id', 'right' ]
];
$list = model('order_goods')->pageList($condition, 'og.goods_id,g.goods_name,g.goods_state,SUM(o.order_money) AS order_money', 'order_money desc', $page_index, $page_size, 'og', $join, 'og.goods_id');
return $this->success($list);
}
public function switchStat($params)
{
$async = $params['async'] ?? true;//是否异步处理,默认异步
$type = $params[ 'type' ];
$temp_params = $params[ 'data' ];
if($async){
$stat_shop_cron_id = model('stat_shop_cron')->add(['type'=>$type,'data'=>json_encode($temp_params),'create_time'=>date('Y-m-d H:i:s')]);
$cron_model = new Cron();
return $cron_model->addCron(1, 0, '统计任务处理', 'CronStatCron', time()+60, $stat_shop_cron_id);
}
$result = event('AddStat', $params, true);
if (empty($result)) {
switch ( $type ) {
case 'order_create'://订单创建
$order_stat_model = new OrderStat();
$result = $order_stat_model->addOrderCreateStat($temp_params);
break;
case 'order_pay'://订单支付
$order_stat_model = new OrderStat();
$result = $order_stat_model->addOrderPayStat($temp_params);
break;
case 'order_refund'://退款
$order_stat_model = new OrderStat();
$result = $order_stat_model->addOrderRefundStat($temp_params);
break;
case 'add_goods'://添加商品
$goods_stat_model = new GoodsStat();
$result = $goods_stat_model->addGoodsStat($temp_params);
break;
case 'collect_goods':
$goods_stat_model = new GoodsStat();
$result = $goods_stat_model->addGoodsCollectStat($temp_params);
break;
case 'recharge':
$recharge_model = new RechargeStat();
$result = $recharge_model->addRechargeStat($temp_params);
break;
case 'visit':
$visit_model = new VisitStat();
$result = $visit_model->addVisitStat($temp_params);
break;
case 'member_withdraw':
$withdraw_model = new MemberWithdrawStat();
$result = $withdraw_model->addMemberWithdrawStat($temp_params);
break;
case 'add_member':
$member_model = new MemberStat();
$result = $member_model->addMemberStat($temp_params);
break;
case 'goods_cart'://购物车加购
$goods_cart_stat_model = new GoodsCartStat();
$result = $goods_cart_stat_model->addGoodsCartStat($temp_params);
break;
case 'goods_visit':
$goods_stat_model = new GoodsStat();
$result = $goods_stat_model->addGoodsVisit($temp_params);
break;
case 'goods_on'://上下架
$goods_stat_model = new GoodsStat();
$result = $goods_stat_model->addGoodsOnStat($temp_params);
break;
}
}
return $result;
}
/**
* 统计入库(按天)
* @param $data
*/
public function addStatShopModel($data)
{
$condition = [
'site_id' => $data['site_id'],
'year' => $data['year'],
'month' => $data['month'],
'day' => $data['day']
];
$info = model('stat_shop')->getInfo($condition, 'id');
if(empty($info)){
model('stat_shop')->add($data);
}else{
$update_data = [];
if(isset($data['site_id'])) unset($data['site_id']);
if(isset($data['year'])) unset($data['year']);
if(isset($data['month'])) unset($data['month']);
if(isset($data['day'])) unset($data['day']);
if(isset($data['day_time'])) unset($data['day_time']);
foreach ($data as $k => $v) {
if ($v > 0) {
$update_data[ $k ] = Db::raw($k . '+' . $v);
} else if ($v < 0) {
$update_data[ $k ] = Db::raw($k . '-' . abs($v));
}
}
model('stat_shop')->update($update_data, $condition);
}
}
/**
* 统计入库(按时)
* @param $data
*/
public function addStatShopHourModel($data)
{
$condition = [
'site_id' => $data['site_id'],
'year' => $data['year'],
'month' => $data['month'],
'day' => $data['day'],
'hour' => $data['hour']
];
$info = model('stat_shop_hour')->getInfo($condition, 'id');
if(empty($info)){
model('stat_shop_hour')->add($data);
}else{
$update_data = [];
if(isset($data['site_id'])) unset($data['site_id']);
if(isset($data['year'])) unset($data['year']);
if(isset($data['month'])) unset($data['month']);
if(isset($data['day'])) unset($data['day']);
if(isset($data['hour'])) unset($data['hour']);
if(isset($data['day_time'])) unset($data['day_time']);
foreach ($data as $k => $v) {
if ($v > 0) {
$update_data[ $k ] = Db::raw($k . '+' . $v);
} else if ($v < 0) {
$update_data[ $k ] = Db::raw($k . '-' . abs($v));
}
}
model('stat_shop_hour')->update($update_data, $condition);
}
}
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use think\facade\Queue;
/**
* 系统配置
*/
class SystemConfig extends BaseModel
{
/**
* 系统配置
* @param int $site_id
* @return array
*/
public function getSystemConfig($site_id = 0)
{
return $this->success([ 'is_open_queue' => 0 ]);
}
/**
* 校验消息队列是否正常运行
* @return bool
*/
public function checkJob()
{
$queue_default = config('queue.default');
if($queue_default != 'sync'){
$secret = uniqid('', true);
$file = root_path('runtime') . $secret . '.job';
try {
Queue::push('app\job\system\CheckJob', [ 'file' => $file ]);
} catch ( \Exception $e) {
return false;
}
sleep(3);
if (file_exists($file)) {
@unlink($file);
return true;
}
return false;
}else{
return true;
}
}
}

496
app/model/system/Upgrade.php Executable file
View File

@@ -0,0 +1,496 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use extend\api\HttpClient;
use think\facade\Cache;
use think\facade\Db;
class Upgrade extends BaseModel
{
private $url;
private $code = '';
private $cert = '';
public function __construct($code = '')
{
$this->code = defined('NIUSHOP_AUTH_CODE') ? NIUSHOP_AUTH_CODE : '';
$this->cert = file_exists('cert.key') ? file_get_contents('cert.key') : '';
$this->url = 'https://api.niushop.com';
}
/**
* post 服务器请求
*/
private function doPost($post_url, $post_data)
{
$post_data[ 'code' ] = $this->code;
$post_data[ 'cert' ] = $this->cert;
$httpClient = new HttpClient();
$res = $httpClient->post($this->url . $post_url . "?url=" . request()->domain(), $post_data);
return $res;
}
/**
* 在线下载文件
* @return bool|string
*/
public function test()
{
$result = $this->doPost('/upgrade/upgrade/test', []);//授权
return $result;
}
/**
* 获取可升级的版本信息
*/
public function getSystemUpgradeInfo()
{
$app_info = config('info');
$addon_array = array_map('basename', glob('addon/*', GLOB_ONLYDIR));
$plugin_info = [];
foreach ($addon_array as $addon) {
$addon_info_path = "addon/{$addon}/config/info.php";
if (file_exists($addon_info_path)) {
$info = include_once $addon_info_path;
$plugin_info[] = [
'code' => $info[ 'name' ],
'version_no' => $info[ 'version_no' ],
'version_name' => $info[ 'version' ],
];
}
}
$post_data = [
'app_info' => [
'code' => $app_info[ 'name' ],
'version_no' => $app_info[ 'version_no' ],
'version_name' => $app_info[ 'version' ],
],
'plugin_info' => $plugin_info
];
$res = $this->doPost('/upgrade/upgrade/updateinfo', $post_data);
$res = json_decode($res, true);
//处理返回数据
if (!empty($res) && $res[ 'code' ] == 0) {
//整合系统和插件数据
$app_data = $res[ 'data' ][ 'app_data' ];
$client_data = $res[ 'data' ][ 'client_data' ];
$plugin_data = $res[ 'data' ][ 'plugin_data' ];
$install_data = $res[ 'data' ][ 'install_data' ];
$data = [];
if ($app_data[ 'code' ] == 0) {
$app_data[ 'data' ][ 'action' ] = 'upgrade';
$app_data[ 'data' ][ 'action_name' ] = '升级';
$app_data[ 'data' ][ 'type' ] = 'system';
$app_data[ 'data' ][ 'type_name' ] = '系统';
$data[] = $app_data[ 'data' ];
}
foreach ($client_data as $key => $val) {
if ($val[ 'code' ] == 0) {
$val[ 'data' ][ 'action' ] = 'download';
$val[ 'data' ][ 'action_name' ] = '下载';
$val[ 'data' ][ 'type' ] = 'client';
$val[ 'data' ][ 'type_name' ] = '客户端';
$data[] = $val[ 'data' ];
}
}
foreach ($plugin_data as $key => $val) {
if ($val[ 'code' ] == 0) {
$val[ 'data' ][ 'action' ] = 'upgrade';
$val[ 'data' ][ 'action_name' ] = '升级';
$val[ 'data' ][ 'type' ] = 'addon';
$val[ 'data' ][ 'type_name' ] = '插件';
$data[] = $val[ 'data' ];
}
}
foreach ($install_data as $key => $val) {
if ($val[ 'code' ] == 0) {
$val[ 'data' ][ 'action' ] = 'install';
$val[ 'data' ][ 'action_name' ] = '安装';
$val[ 'data' ][ 'type' ] = 'addon';
$val[ 'data' ][ 'type_name' ] = '插件';
$data[] = $val[ 'data' ];
}
}
//处理更新说明的换行
foreach ($data as $key => $val) {
foreach ($val[ 'scripts' ] as $k => $v) {
$val[ 'scripts' ][ $k ][ 'description' ] = str_replace("\n", '<br/>', $v[ 'description' ]);
}
$data[ $key ] = $val;
}
$res[ 'data' ] = $data;
}
return $res;
}
/**
* 在线下载文件
* @param $param
* @return array|mixed
*/
public function download($param)
{
$data = array (
"file_token" => $param[ "token" ]
);
$result = $this->doPost('/upgrade/upgrade/download', $data);//授权
if (empty($result)) {
return $this->error();
}
$result = json_decode($result, true);
return $result;
}
/**
* 获取授权信息
* @return bool|mixed|string
*/
public function authInfo()
{
$app_info = config('info');
$data = array (
"product_key" => $app_info[ 'name' ],
);
$re = $this->doPost('/upgrade/auth/info', $data);
$re = json_decode($re, true);
return $re;
}
/**
* 获取所有插件
* @return array|mixed
*/
public function getAuthPlugin()
{
$result = $this->doPost('/upgrade/auth/plugin', []);//授权
if (empty($result))
return $this->error();
$result = json_decode($result, true);
return $result;
}
/**
* 查询所有表
*/
public function getDatabaseList()
{
$databaseList = Db::query("SHOW TABLE STATUS");
return $databaseList;
}
/******************************* 升级日志相关 start *****************************/
/**
* 添加升级日志
* @param $data
* upgrade_time 升级时间
* version_info 升级的版本信息
* backup_root 备份文件和sql的根目录
* download_root 下载文件和sql的根目录
* @return array
*/
public function addUpgradeLog($data)
{
$res = model('sys_upgrade_log')->add($data);
if ($res == false) {
return $this->error('', 'UNKNOW_ERROR');
} else {
return $this->success();
}
}
/**
* 修改日志
* @return array
*/
public function editUpgradeLog($data, $condition)
{
$res = model('sys_upgrade_log')->update($data, $condition);
if ($res == false) {
return $this->error('', 'UNKNOW_ERROR');
} else {
return $this->success();
}
}
/**
* 获取升级日志信息
* @param $condition
* @param string $field
* @return array
*/
public function getUpgradeLogInfo($condition, $field = '*')
{
$info = model('sys_upgrade_log')->getInfo($condition, $field);
if (!empty($info)) {
$info[ 'version_info' ] = json_decode($info[ 'version_info' ], true);
}
return $info;
}
/**
* 获取升级分页列表
* @param array $condition
* @param int $page
* @param int $page_size
* @param string $order
* @param string $field
* @return array
*/
public function getUpgradeLogPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = '*')
{
$list = model('sys_upgrade_log')->pageList($condition, $field, $order, $page, $page_size);
return $this->success($list);
}
/**
* 获取升级日志列表
* @param array $condition
* @param string $field
* @param string $order
* @param null $limit
* @return array
*/
public function getUpgradeLogList($condition = [], $field = '*', $order = '', $limit = null)
{
$list = model('sys_upgrade_log')->getList($condition, $field, $order, '', '', '', $limit);
return $this->success($list);
}
/**
* 删除升级日志
* @param $condition
* @return array
*/
public function deleteUpgradeLog($condition)
{
$log_list = model('sys_upgrade_log')->getList($condition, '*', 'upgrade_time asc');
try {
foreach ($log_list as $log) {
$backup_root = $log[ 'backup_root' ];
if (is_dir($backup_root)) {
unlink($backup_root);
}
}
model('sys_upgrade_log')->delete($condition);
return $this->success();
} catch (\Exception $e) {
return $this->error('', $e->getMessage());
}
}
/******************************* 升级日志相关 end *****************************/
public function getVersionLog($page, $page_size)
{
$app_info = config('info');
$post_data = [
'page_index' => $page,
'page_size' => $page_size,
'product_key' => $app_info[ 'name' ]
];
$re = $this->doPost('/upgrade/upgrade/versionPage', $post_data);
$re = json_decode($re, true);
if (!empty($re[ 'data' ])) {
//处理返回数据
$return_data = [];
foreach ($re[ 'data' ][ 'list' ] as $key => $val) {
$val[ 'version_desc' ] = str_replace("\n", '<br/>', $val[ 'version_desc' ]);
$day = date('Y-m-d', $val[ 'create_time' ]);
$day_time = strtotime($day);
$return_data[ $day_time ][] = $val;
}
$temp_arr = [];
foreach ($return_data as $key => $value) {
$temp_arr[] = [ 'list' => $value, 'time' => $key, 'format_time' => date('Y-m-d', $key) ];
}
$re[ 'data' ][ 'list' ] = $temp_arr;
} else {
$re[ 'data' ][ 'list' ] = [];
}
return $re;
}
/**
* 获取所有插件
* @return array|mixed
*/
public function getPluginGoodsList()
{
$addon_list = Cache::get('website_addon_list');
if (empty($addon_list)) {
$app_info = config('info');
$data = array (
"product_key" => $app_info[ 'name' ],
);
$result = $this->doPost('/upgrade/auth/allplugin', $data);//授权
if (empty($result))
return $this->error();
$result = json_decode($result, true);
Cache::set('website_addon_list', $result[ 'data' ], 3 * 24 * 60 * 60);
return $result[ 'data' ];
} else {
return $addon_list;
}
}
/**
* 下载uniapp
* @param $version
* @return array|mixed
*/
public function downloadUniapp($version)
{
$data = array (
"version" => $version
);
$result = $this->doPost('/upgrade/upgrade/downloaduniapp', $data);//授权
if (empty($result))
return $this->error();
$result = json_decode($result, true);
return $result;
}
/**
* 获取应用更新日志
* @return mixed
*/
public function getUpdateLog()
{
$app_info = config('info');
$post_data = [
'product_key' => $app_info[ 'name' ]
];
$re = $this->doPost('/upgrade/upgrade/updateLog', $post_data);
$re = json_decode($re, true);
return $re;
}
/**
* 获取补丁列表
* @param array $param
* @return mixed
*/
public function getPatchLists($param = [])
{
$app_info = config('info');
$existed_addons = array_map('basename', glob('addon/*', GLOB_ONLYDIR));
$post_data = [
'product_key' => $app_info[ 'name' ],
'version_name' => $app_info[ 'version' ],
'page' => $param[ 'page' ] ?? 1,
'page_size' => $param[ 'page_size' ] ?? PAGE_LIST_ROWS,
'addons' => join(',',$existed_addons),
];
$re = $this->doPost('/upgrade/upgrade/patchLists', $post_data);
$re = json_decode($re, true);
if(!empty($re['data']['list'])){
$patch_ids = array_column($re['data']['list'], 'id');
$patch_list = model('sys_patch')->getList([['patch_id', 'in', $patch_ids]]);
$patch_list = array_column($patch_list, null, 'patch_id');
foreach($re['data']['list'] as &$val){
$val['patch_res'] = $patch_list[$val['id']] ?? null;
}
}
return $re;
}
/**
* 处理补丁结果
* @param $patch_id
* @param $patch_res
* @return array
*/
public function dealPatchRes($patch_id, $patch_res)
{
$info = model('sys_patch')->getInfo([['patch_id', '=', $patch_id]]);
if(!empty($info)){
model('sys_patch')->update([
'patch_res' => $patch_res,
'patch_time' => time(),
], [['patch_id', '=', $patch_id]]);
}else{
model('sys_patch')->add([
'patch_id' => $patch_id,
'patch_res' => $patch_res,
'patch_time' => time(),
]);
}
return $this->success();
}
/**
* 下载补丁
* @param $patch_id
* @param $patch_link
* @return array
*/
public function downloadPatch($patch_id, $patch_link)
{
try{
$info = model('sys_patch')->getInfo([['patch_id', '=', $patch_id]]);
if(!empty($info['patch_link'])){
@unlink($info['patch_link']);
}
$temp_dir = "upload/version/patch/";
if (!is_dir($temp_dir)) mkdir($temp_dir, 0777, true);
$arrContextOptions = array(
"ssl" => array(
"verify_peer" => false,
"verify_peer_name" => false,
"allow_self_signed" => true,
),
);
$fileContent = file_get_contents($patch_link, false, stream_context_create($arrContextOptions));
$temp_file = $temp_dir . uniqid() . ".zip";
file_put_contents($temp_file, $fileContent);
if(!empty($info)){
model('sys_patch')->update([
'patch_link' => $temp_file,
], [['patch_id', '=', $patch_id]]);
}else{
model('sys_patch')->add([
'patch_id' => $patch_id,
'patch_link' => $temp_file,
]);
}
return $this->success([
'patch_link' => $temp_file,
]);
}catch(\Exception $e){
return $this->error(null, '下载错误');
}
}
}

824
app/model/system/User.php Executable file
View File

@@ -0,0 +1,824 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\store\Store;
use think\facade\Session;
use app\model\BaseModel;
/**
* 管理员模型
*/
class User extends BaseModel
{
/*******************************************************************用户 编辑查询 start*****************************************************/
/**
* 添加用户
* @param $data
* @param int $store_id
* @param string $source_type register 注册 add 添加
* @return array
*/
public function addUser($data, $store_id = 0, $source_type = 'register')
{
$site_id = $data[ 'site_id' ] ?? '';
$app_module = $data[ 'app_module' ] ?? '';
$member_id = $data[ 'member_id' ] ?? 0;
if ($site_id === '') return $this->error('', 'REQUEST_SITE_ID');
if ($app_module === '') return $this->error('', 'REQUEST_APP_MODULE');
if (empty($data[ "username" ])) return $this->error('', '用户名不能为空');
if (empty($data[ "password" ])) return $this->error('', '密码不能为空');
//判断 用户名 是否存在
$user_info = model('user')->getInfo(
[
[ 'username', "=", $data[ "username" ] ],
[ 'site_id', '=', $site_id ],
[ 'app_module', '=', $app_module ]
]
);
if ($source_type == 'add') {
if (!empty($user_info)) {
return $this->error('', '账号已存在');
}
} else {
if (!empty($user_info)) {
if (data_md5($data[ "password" ]) == $user_info[ 'password' ]) {
return $this->success(2);
} else {
return $this->error('', '账号已存在');
}
}
}
if ($member_id > 0) {
$temp_condition = array (
"app_module" => $data[ "app_module" ],
"member_id" => $member_id
);
$temp_count = model('user')->getCount($temp_condition, 'uid');
if ($temp_count > 0) {
return $this->error('', 'USERNAME_EXISTED');
}
}
$group_id = $data[ 'group_id' ] ?? 0;
$data[ "group_name" ] = '';
if ($group_id > 0) {
$group_model = new Group();
$group_info = $group_model->getGroupInfo([ [ "group_id", "=", $group_id ], [ "site_id", "=", $site_id ], [ "app_module", "=", $app_module ] ], "group_name")[ 'data' ];
$data[ "group_name" ] = $group_info[ "group_name" ] ?? '';
}
$data[ "password" ] = data_md5($data[ "password" ]);
$data[ "create_time" ] = time();
//记录创建用户信息
if($source_type == 'add' && isset($data['create_uid'])){
$user_info = model('user')->getInfo([['uid', '=', $data['create_uid']]], 'uid,username,create_user_data');
$create_user_data = json_decode($user_info['create_user_data'], true);
$create_user_data[] = ['id' => (string)$user_info['uid'], 'name' => $user_info['username']];
$data['create_user_data'] = json_encode($create_user_data, JSON_UNESCAPED_UNICODE);
}
model("user")->startTrans();
try {
$uid = model("user")->add($data);
if ($uid === false) {
model("user")->rollback();
return $this->error('', 'UNKNOW_ERROR');
}
if (isset($data[ 'store' ]) && !empty($data[ 'store' ])) {
$store_user_list = [];
foreach ($data[ 'store' ] as $item) {
if (empty($item[ 'store_id' ])) {
model("user")->rollback();
return $this->error('', '门店id不能为空');
}
if (empty($item[ 'group_id' ])) {
model("user")->rollback();
return $this->error('', '门店角色不能为空');
}
array_push($store_user_list, [
'uid' => $uid,
'site_id' => $data[ 'site_id' ],
'store_id' => $item[ 'store_id' ],
'group_id' => $item[ 'group_id' ],
'create_time' => time(),
'app_module' => 'store'
]);
}
model('user_group')->addList($store_user_list);
}
model("user")->commit();
return $this->success($uid);
} catch (\Exception $e) {
model("user")->rollback();
return $this->error('', '用户添加失败');
}
}
public function getUserColumn($condition = [], $field = '')
{
$res = model('user')->getColumn($condition, $field);
return $res;
}
/**
* 编辑用户
* @param $data
* @param $condition
* @param int $store_id
* @return array
*/
public function editUser($data, $condition, $store_id = 0)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition[ 'site_id' ] ?? '';
$app_module = $check_condition[ 'app_module' ] ?? '';
$uid = $check_condition[ 'uid' ] ?? '';
if ($uid === '') {
return $this->error('', '缺少必须参数UID');
}
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
$group_id = $data[ 'group_id' ] ?? 0;
$data[ "group_name" ] = '';
if ($group_id > 0) {
$group_model = new Group();
$group_info = $group_model->getGroupInfo([ [ "group_id", "=", $group_id ], [ "site_id", "=", $site_id ], [ 'app_module', '=', $app_module ] ], "group_name")[ 'data' ];
$data[ "group_name" ] = $group_info[ "group_name" ] ?? '';
}
model('user')->startTrans();
try {
$res = model("user")->update($data, $condition);
if ($res === false) {
model('user')->rollback();
return $this->error('', 'UNKNOW_ERROR');
}
model('user_group')->delete([ [ 'site_id', '=', $site_id ], [ 'uid', '=', $uid ], [ 'app_module', '=', 'store' ] ]);
if (isset($data[ 'store' ]) && !empty($data[ 'store' ])) {
$store_user_list = [];
foreach ($data[ 'store' ] as $item) {
if (empty($item[ 'store_id' ])) {
model("user")->rollback();
return $this->error('', '门店id不能为空');
}
if (empty($item[ 'group_id' ])) {
model("user")->rollback();
return $this->error('', '门店角色不能为空');
}
array_push($store_user_list, [
'uid' => $uid,
'site_id' => $site_id,
'store_id' => $item[ 'store_id' ],
'group_id' => $item[ 'group_id' ],
'create_time' => time(),
'app_module' => 'store'
]);
}
model('user_group')->addList($store_user_list);
}
model("user")->commit();
return $this->success($res);
} catch (\Exception $e) {
model("user")->rollback();
return $this->error('', '用户编辑失败');
}
}
/**
* 编辑用户状态
* @param $status
* @param $condition
* @return array
*/
public function modifyUserStatus($status, $condition)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition[ 'site_id' ] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$data = array (
"status" => $status,
"update_time" => time()
);
$res = model('user')->update($data, $condition);
if ($res === false) {
return $this->error('', 'UNKNOW_ERROR');
}
return $this->success($res);
}
/**
* 重置密码
* @param $password
* @param $condition
* @return array
*/
public function modifyUserPassword($password, $condition)
{
$res = model('user')->update([ 'password' => data_md5($password) ], $condition);
if ($res === false) {
return $this->error('', 'RESULT_ERROR');
}
return $this->success($res);
}
/**
* 系统用户修改密码
* @param $condition
* @param $new_password
* @return array
*/
public function modifyAdminUserPassword($condition, $new_password)
{
if (addon_is_exit("demo")) {
return $this->error('', '权限不足,请联系客服');
}
$res = model('user')->getInfo($condition, "uid,password");
if (!empty($res)) {
$data = array (
'password' => data_md5($new_password)
);
$res = model('user')->update($data, $condition);
return $this->success($res, 'SUCCESS');
} else {
return $this->error('', 'PASSWORD_ERROR');
}
}
/**
* 删除用户
* @param $condition
* @return array
*/
public function deleteUser($condition)
{
$check_condition = array_column($condition, 2, 0);
$app_module = $check_condition[ 'app_module' ] ?? '';
$uid = $check_condition[ 'uid' ] ?? '';
if ($uid === '') {
return $this->error('', '缺少必须参数UID');
}
if ($app_module === '') {
return $this->error('', 'REQUEST_APP_MODULE');
}
//自己和下属都删除
$uid_arr = model('user')->getColumn([['create_user_data', 'like', '%"'.$uid.'"%']], 'uid');
$uid_arr[] = $uid;
$res = model('user')->delete([['uid', 'in', $uid_arr]]);
if ($res === false) {
return $this->error('', 'UNKNOW_ERROR');
}
//用户组也删除
model('user_group')->delete([ [ 'uid', 'in', $uid_arr ] ]);
model('group')->delete([['create_uid', 'in', $uid_arr]]);
if(addon_is_exit('cashier')){
model('cashier_auth_group')->delete([['create_uid', 'in', $uid_arr]]);
}
return $this->success($res);
}
/**
* 清除后台所有用户的登录信息
* @param $app_module
* @param $site_id
* @return array
*/
public function deleteUserLoginInfo($app_module, $site_id)
{
$dir = './runtime/session';
$this->deldir($dir);
Session::delete($app_module . "_" . $site_id . ".uid");
return $this->success();
}
/**
* @param $dir
*/
public function deldir($dir)
{
//先删除目录下的文件:
$dh = opendir($dir);
while ($file = readdir($dh)) {
if ($file != "." && $file != "..") {
$fullpath = $dir . "/" . $file;
if (!is_dir($fullpath)) {
unlink($fullpath);
} else {
$this->deldir($fullpath);
}
}
}
closedir($dh);
}
/**
* 获取用户信息
* @param $condition
* @param string $field
* @return array
*/
public function getUserInfo($condition, $field = "uid, app_module, site_id, group_id, group_name, username, member_id, create_time, update_time, status, login_time, login_ip, is_admin")
{
$info = model('user')->getInfo($condition, $field);
if (!empty($info)) {
if (isset($info[ 'uid' ])) {
if(isset($info['is_admin']) && isset($info['site_id']) && $info['is_admin'] == 1 && addon_is_exit('cashier', $info['site_id'])){
//如果是超级管理员,默认有所有门店的管理员角色
$join = [
[ 'cashier_auth_group g', "g.keyword = 'admin'", 'inner' ],
];
$info[ 'user_group_list' ] = model('store')->getList([ [ 's.site_id', '=', $info[ 'site_id' ] ],['s.is_frozen', '=', 0] ], 's.store_id,s.store_name,g.group_id,g.menu_array', 's.is_default desc,store_id desc', 's', $join);
}else{
$join = [
[ 'store s', 's.store_id = ug.store_id', 'inner' ],
[ 'cashier_auth_group g', 'g.group_id = ug.group_id', 'inner' ]
];
$info[ 'user_group_list' ] = model('user_group')->getList([ [ 'ug.uid', '=', $info[ 'uid' ] ],['s.is_frozen', '=', 0] ], 's.store_id,s.store_name,g.group_id,g.menu_array', 's.is_default desc,store_id desc', 'ug', $join);
}
}
}
return $this->success($info);
}
/**
* 获取用户列表
* @param array $condition
* @param string $field
* @param string $order
* @param null $limit
* @return array
*/
public function getUserList($condition = [], $field = 'uid, app_module, site_id, group_id, username, member_id, create_time, update_time, status, login_time, login_ip, is_admin, group_name', $order = '', $limit = null)
{
$list = model('user')->getList($condition, $field, $order, '', '', '', $limit);
return $this->success($list);
}
/**
* 获取会员分页列表
* @param array $condition
* @param int $page
* @param int $page_size
* @param string $order
* @param string $field
* @return array
*/
public function getUserPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = 'uid, app_module, site_id, group_id, username, member_id, create_time, update_time, status, login_time, login_ip, is_admin, group_name, login_time')
{
$list = model('user')->pageList($condition, $field, $order, $page, $page_size);
return $this->success($list);
}
/**
* 获取站点用户分页列表
* @param array $condition
* @param int $page
* @param int $page_size
* @param string $order
* @return array
*/
public function getSiteUserPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '')
{
$field = ' nu.uid, nu.app_module, nu.app_group,
nu.is_admin, nu.site_id, nu.group_id, nu.group_name, nu.username, nu.member_id, nu.create_time,
nu.update_time, nu.status, nu.login_time, nu.login_ip, ns.site_name,';
$alias = 'nu';
$join = [
[
'shop ns',
'nu.site_id = ns.site_id',
'left'
],
];
$list = model("user")->pageList($condition, $field, $order, $page, $page_size, $alias, $join);
return $this->success($list);
}
/**
* 检测权限success通过error拒绝
* @param $url
* @param $app_module
* @param $group_info
* @param string $addon
* @return array
*/
public function checkAuth($url, $app_module, $group_info, $addon = '')
{
$auth_control = event("AuthControl", [ 'url' => $url, 'app_module' => $app_module ], 1);
if (!empty($auth_control)) {
if ($auth_control[ 'code' ] < 0) {
return $this->error();
}
}
// 权限组
if (empty($group_info)) {
return $this->error();
}
if ($group_info[ 'is_system' ] == 1) {
return $this->success();
}
$menu_model = new Menu();
$menu_info = $menu_model->getMenuInfoByUrl($url, $app_module, $addon)[ 'data' ];
if (!empty($menu_info)) {
if ($menu_info[ 'is_control' ] == 0) {
return $this->success();
}
if (strpos(',' . $group_info[ 'menu_array' ] . ',', ',' . $menu_info[ 'name' ] . ',') !== false) {
return $this->success();
} else {
return $this->error($menu_info);
}
} else {
$count = $menu_model->getMenuCount([ [ 'url', '=', $url ] ])['data'];
if ($count > 0) {
return $this->error();
}
return $this->success();
}
}
/**
* 检测和获取重定向信息
* @param $url_param
* @param $group_info
* @return array
*/
public function checkAndGetRedirectUrl($url_param, $group_info)
{
//静态处理不用重复查询
static $menu_tree_data = null;
static $menu_tree_md5 = '';
$res = [
'is_auth' => false,
'redirect_url' => '',
];
$menu_model = new Menu();
//链接对应的菜单
$menu_info = $menu_model->getMenuList([
['url', '=', $url_param['url']],
['app_module', '=', $url_param['app_module']],
], '*', 'level desc')[ 'data' ][0] ?? null;
//1、菜单不存在默认可以访问
if(empty($menu_info)){
$res['is_auth'] = true;
return $res;
}
//2、菜单不控制权限可以访问
if($menu_info['is_control'] == 0){
$res['is_auth'] = true;
return $res;
}
//菜单路径
$crumbs = [$menu_info];
while ($menu_info['parent']){
$menu_info = $menu_model->getMenuInfo([
['name', '=', $menu_info['parent']],
['app_module', '=', $url_param['app_module']],
])[ 'data' ];
array_unshift($crumbs, $menu_info);
}
//权限树
if(is_null($menu_tree_data) || md5($group_info[ 'menu_array' ]) != $menu_tree_md5){
$menu_tree_md5 = md5($group_info[ 'menu_array' ]);
$menu_array = "'".str_replace(',',"','", $group_info[ 'menu_array' ])."'";
$menu_list = $menu_model->getMenuList([
[ 'app_module', '=', $url_param['app_module'] ],
['', 'exp', \think\facade\Db::raw("name in ({$menu_array}) or is_control = 0")]
], '*', 'level asc,sort asc,id asc')['data'];
$menu_tree_data = list_to_tree($menu_list, 'name', 'parent', 'child_list', '');
}
$menu_tree = $menu_tree_data;
//菜单路径和权限树进行比对,如果比对到最后则说明有权限,没有比对到最后要看产生分歧的分支的首个有权限菜单
$is_to_last = true;
foreach($crumbs as $menu_info){
if(isset($menu_tree[$menu_info['name']])){
$menu_tree = $menu_tree[$menu_info['name']]['child_list'];
}else{
$is_to_last = false;
break;
}
}
//3、在权限集中可以访问
if($is_to_last){
$res['is_auth'] = true;
return $res;
}
//4、查找重定向链接重定向访问
$is_continue = true;
while ($is_continue){
$is_continue = false;
foreach($menu_tree as $menu_info){
if($menu_info['type'] == 'page'){
$real_menu_info = $menu_info;
$menu_tree = $menu_info['child_list'];
$is_continue = true;
break;
}
}
}
if(!empty($real_menu_info)){
if(strtolower($real_menu_info['url']) != strtolower($url_param['url'])){
$res['redirect_url'] = $real_menu_info['url'];
return $res;
}
}
return $res;
}
/*******************************************************************用户 编辑查询 end*****************************************************/
/*******************************************************************用户注册登录 start*****************************************************/
/**
* 用户登录
* @param $username
* @param $password
* @param string $app_module
* @param int $site_id
* @return array
*/
public function login($username, $password, $app_module = 'shop', $site_id = 0)
{
$user_condition = [
[ 'username', '=', $username ],
[ 'app_module', '=', $app_module ],
[ 'site_id', '=', $site_id ]
];
// if ($app_module == 'shop') $user_condition[] = [ 'group_id', '>', 0 ];
$user_info = model('user')->getInfo($user_condition);
if (empty($user_info)) {
return $this->error('', 'USER_LOGIN_ERROR');
}
if ($user_info[ 'password' ] != data_md5($password)) {
return $this->error('', 'USER_LOGIN_ERROR');
}
if ($user_info[ 'status' ] !== 1) {
return $this->error([], 'USER_IS_LOCKED');
}
// 检查是否有权限登录
if ($app_module == 'shop' && $user_info[ 'group_id' ] == 0) {
return $this->error('', 'PERMISSION_DENIED');
}
$this->initLogin($user_info);
return $this->success();
}
/**
* 初始化登录
* @param $user_info
*/
private function initLogin($user_info)
{
$time = time();
//初始化登录信息
$auth = array (
'uid' => $user_info[ 'uid' ],
'username' => $user_info[ 'username' ],
'create_time' => $user_info[ 'create_time' ],
'status' => $user_info[ 'status' ],
'group_id' => $user_info[ "group_id" ],
'site_id' => $user_info[ "site_id" ],
'app_group' => $user_info[ "app_group" ],
'is_admin' => $user_info[ 'is_admin' ],
'login_time' => $time,
'login_ip' => request()->ip(),
'sys_uid' => $user_info[ 'sys_uid' ],
'password' => $user_info[ 'password' ],
'app_module' => $user_info[ 'app_module' ]
);
//更新登录记录
$data = [
'login_time' => time(),
'login_ip' => request()->ip(),
];
model('user')->update($data, [ [ 'uid', "=", $user_info[ 'uid' ] ] ]);
Session::set($user_info[ 'app_module' ] . "_" . $user_info[ 'site_id' ] . ".uid", $user_info[ 'uid' ]);
Session::set($user_info[ 'app_module' ] . "_" . $user_info[ 'site_id' ] . ".user_info", $auth);
Session::set('app_module' . "_" . $user_info[ 'site_id' ] . ".login_module", $user_info[ 'app_module' ]);
$this->addUserLog($user_info[ 'uid' ], $user_info[ 'username' ], $user_info[ 'site_id' ], "用户登录", []);//添加日志
}
/**
* uni-app端用户登录
* @param $username
* @param $password
* @param $app_module
* @return array
*/
public function uniAppLogin($username, $password, $app_module)
{
$time = time();
// 验证参数 预留
$user_info = $this->getUserInfo([ [ 'username', "=", $username ] ], 'uid,app_module,site_id,group_id,group_name,username,status,is_admin,password')[ 'data' ];
if (empty($user_info)) {
return $this->error('', 'USER_LOGIN_ERROR');
} else if (data_md5($password) !== $user_info[ 'password' ]) {
return $this->error([], 'PASSWORD_ERROR');
} else if ($user_info[ 'status' ] !== 1) {
return $this->error([], 'USER_IS_LOCKED');
}
// 检查是否有权限登录
if ($app_module == 'shop' && $user_info[ 'group_id' ] == 0) {
return $this->error('', 'PERMISSION_DENIED');
}
//更新登录记录
$data = [
'login_time' => $time,
'login_ip' => request()->ip(),
];
model('user')->update($data, [ [ 'uid', "=", $user_info[ 'uid' ] ] ]);
$this->addUserLog($user_info[ 'uid' ], $user_info[ 'username' ], $user_info[ 'site_id' ], "用户登录", []); //添加日志
unset($user_info[ 'password' ]);
return $this->success($user_info);
}
/**
* 获取当前登录uid
* @param $app_module
* @param int $site_id
* @return mixed
*/
public function uid($app_module, $site_id = 0)
{
return Session::get($app_module . "_" . $site_id . ".uid");
}
/**
* 登录模块
* @param $site_id
* @return mixed|string
*/
public function loginModule($site_id)
{
$login_module = Session::get('app_module' . "_" . $site_id . ".login_module");
if (empty($login_module) || !strstr($_SERVER[ "REQUEST_URI" ], 'store/store')) {
return 'shop';
} else {
return $login_module;
}
}
/**
* 获取当前登录管理员信息
* @param $app_module
* @param int $site_id
* @return mixed
*/
public function userInfo($app_module, $site_id = 0)
{
return Session::get($app_module . "_" . $site_id . ".user_info");
}
/**
* 设置当前登录管理员信息
* @param $user_info
*/
public function setUserInfo($user_info)
{
Session::set($user_info[ 'app_module' ] . "_" . $user_info[ 'site_id' ] . ".user_info", $user_info);
}
/**
* 检测当前登录管理员密码是否正确
* @param $user_info
* @param $app_module
* @param int $site_id
* @return int|mixed
*/
public function checkPassword($user_info, $app_module, $site_id = 0)
{
// 兼容v5.2.0版本,下个版本可以移除
if (empty($user_info[ 'password' ])) {
return 1;
}
$count = model('user')->getCount([
[ 'site_id', '=', $site_id ],
[ 'app_module', '=', $app_module ],
[ 'uid', '=', $user_info[ 'uid' ] ],
[ 'username', '=', $user_info[ 'username' ] ],
[ 'password', '=', $user_info[ 'password' ] ]
]);
return $count;
}
/**
* 清除登录信息
*/
public function clearLogin($app_module, $site_id = 0)
{
Session::delete($app_module . "_" . $site_id);
}
/*******************************************************************用户注册登录 end*****************************************************/
/*******************************************************************用户日志 start*****************************************************/
/**
* 添加用户日志
* @param $uid
* @param $username
* @param $site_id
* @param $action_name
* @param array $data
* @return array
*/
public function addUserLog($uid, $username, $site_id, $action_name, $data = [])
{
$url = request()->parseUrl();
$ip = request()->ip();
$log = array (
"uid" => $uid,
"username" => $username,
"site_id" => $site_id,
"url" => $url,
"ip" => $ip,
"data" => json_encode($data),
"action_name" => $action_name,
"create_time" => time(),
);
$res = model("user_log")->add($log);
if ($res === false) {
return $this->error('', 'UNKNOW_ERROR');
}
return $this->success($res);
}
/**
* 删除用户日志
* @param $condition
* @return array
*/
public function deleteUserLog($condition)
{
$check_condition = array_column($condition, 2, 0);
$site_id = $check_condition[ 'site_id' ] ?? '';
if ($site_id === '') {
return $this->error('', 'REQUEST_SITE_ID');
}
$res = model("user_log")->delete($condition);
if ($res === false) {
return $this->error('', 'UNKNOW_ERROR');
}
return $this->success($res);
}
/**
* 获用户员日志分页列表
* @param array $condition
* @param int $page
* @param int $page_size
* @param string $order
* @param string $field
* @return array
*/
public function getUserLogPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = 'username, site_id, url, id, uid, data, ip, action_name, create_time')
{
$list = model('user_log')->pageList($condition, $field, $order, $page, $page_size);
return $this->success($list);
}
/*******************************************************************用户日志 end*****************************************************/
}

70
app/model/system/UserGroup.php Executable file
View File

@@ -0,0 +1,70 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
/**
* 查询用户信息以user_group为主表
* @author Administrator
*/
class UserGroup extends BaseModel
{
/**
* @param array $condition
* @param number $page
* @param string $page_size
* @param string $order
* @param string $field
* @return multitype:string mixed
*/
public function getUserPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = 'group_id desc', $field = '*', $alias = 'a', $join = [])
{
$list = model('user_group')->pageList($condition, $field, $order, $page, $page_size, $alias, $join);
return $this->success($list);
}
/**
* @param array $condition
* @param string $field
* @param string $alias
* @param array $join
* @return array
*/
public function getUserInfo($condition = [], $field = '*', $alias = 'a', $join = []){
$list = model('user_group')->getInfo($condition, $field, $alias, $join);
return $this->success($list);
}
/**
* @param array $condition
* @param string $field
* @param string $alias
* @param array $join
* @return array
*/
public function getUserList($condition = [], $field = '*', $order = '', $alias = 'a', $join = []){
$list = model('user_group')->getList($condition, $field, $order, $alias, $join);
return $this->success($list);
}
/**
* 删除用户
* @param $condition
* @return array
*/
public function deleteUser($condition){
$res = model('user_group')->delete($condition);
if ($res) return $this->success();
return $this->error();
}
}

452
app/model/system/Visit.php Executable file
View File

@@ -0,0 +1,452 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use think\facade\Cache;
use think\Session;
use think\facade\Db;
use app\model\BaseModel;
/**
* 访问统计
*/
class Visit extends BaseModel
{
/**
* 获取访问信息(以日为基本单位)
* @param $condition
* @return \multitype
*/
public function getVisitInfo($condition)
{
$visit_model = model("nc_visit");//访问统计记录表
$info = $visit_model->getInfo($condition);
return $this->success($info);
}
/**
* 获取访问ip信息(以日为基本单位)
* @param $condition
* @return \multitype
*/
public function getVisitIpInfo($condition)
{
$visit_ip_model = model("nc_visit_ip");//访问统计记录表
$info = $visit_ip_model->getInfo($condition);
return $this->success($info);
}
/**
* 获取用户访问记录
* @param $condition
* @return \multitype
*/
public function getVisitUserInfo($condition)
{
$visit_user_model = model("nc_visit_user");//用户访问记录表
$info = $visit_user_model->getInfo($condition);
return $this->success($info);
}
/**
* 当日的访问数据写入
* @param array $param
*/
public function todayVisit($param = [])
{
//加入防止写入过多无效访问
$now_time = time();
$today_date = date("Ymd");
$expire_time = 1800;//过期的周期时长
$visit_session_name = "visit_" . $param["site_id"] . "_" . $param["type"] . "_" . $param["module"] . "_" . $param["addon"] . "_" . $today_date;
if (!empty(Session::get($visit_session_name)) && (Session::get($visit_session_name) + $expire_time) > $now_time) {
return $this->success();
}
Session::set($visit_session_name, $now_time);//设置访问记录,存入时间
$yesterday = date("Ymd", strtotime('-1 days'));
Cache::clear("visit_info" . $yesterday);//清理昨天的缓存
Cache::clear("visit_ip_info" . $yesterday);//清理昨天的缓存
$visit_model = model("nc_visit");//访问统计记录表
$visit_ip_model = model("nc_visit_ip");//ip访问记录表
$visit_user_model = model("nc_visit_user");//用户模块访问记录表
// 启动事务
$ip_count = 0;
//ip访问记录
$ip = ip2long(getip());
$vivit_ip_condition = array(
"date" => $today_date,
"site_id" => $param["site_id"],
"type" => $param["type"],
"module" => $param["module"],
"ip" => $ip,
"addon" => $param["addon"]
);
$visit_ip_result = $this->getVisitIpInfo($vivit_ip_condition);
$visit_ip_info = $visit_ip_result["data"];
$ip_data = array(
"date" => $today_date,
"site_id" => $param["site_id"],
"type" => $param["type"],
"module" => $param["module"],
"ip" => $ip,
"addon" => $param["addon"]
);
if (empty($visit_ip_info)) {
$ip_count += 1;
$ip_data["ip_count"] = 1;
$visit_ip_res = $visit_ip_model->add($ip_data);
} else {
$ip_data["ip_count"] = $visit_ip_info["ip_count"] + 1;
$visit_ip_res = $visit_ip_model->update($ip_data, $vivit_ip_condition);
}
Cache::tag("visit_ip_info" . $today_date)->set("visit_ip_info_" . $param["site_id"] . "_" . $param["type"] . "_" . $param["module"] . "_" . $param["addon"] . "_" . $ip["ip"] . "_" . $today_date, $ip_data);
//用户模块访问记录
if ($param["uid"] > 0) {
$visit_user_condition = array(
"uid" => $param["uid"],
"site_id" => $param["site_id"],
"module" => $param["module"],
"addon" => $param["addon"]
);
$visit_user_result = $this->getVisitUserInfo($visit_user_condition);
$visit_user_info = $visit_user_result["data"];
$visit_user_data = array(
"uid" => $param["uid"],
"site_id" => $param["site_id"],
"module" => $param["module"],
"addon" => $param["addon"]
);
if (empty($visit_user_info)) {
$visit_user_data["create_time"] = time();
$visit_user_result = $visit_user_model->add($visit_user_data);
} else {
$visit_user_data["update_time"] = time();
$visit_user_result = $visit_user_model->update($visit_user_data, $visit_user_condition);
}
Cache::tag("visit_user_info" . $param["site_id"])->set("visit_user_info_" . $param["site_id"] . "_" . $param["uid"] . "_" . $param["module"] . "_" . $param["addon"], $visit_user_data);
}
//访问记录
$vivit_condition = array(
"date" => $today_date,
"site_id" => $param["site_id"],
"type" => $param["type"],
"module" => $param["module"],
"addon" => $param["addon"]
);
$visit_result = $this->getVisitInfo($vivit_condition);
$visit_info = $visit_result["data"];
//如果当前日不存在访问统计数据,则需要创建
$data = array(
"date" => $today_date,
"site_id" => $param["site_id"],
"type" => $param["type"],
"module" => $param["module"],
"addon" => $param["addon"]
);
if (empty($visit_info)) {
$data["count"] = 1;
$data["ip_count"] = $ip_count;
$res = $visit_model->add($data);
} else {
$data["count"] = $visit_info["count"] + 1;
$data["ip_count"] = $visit_info["ip_count"] + $ip_count;
$res = $visit_model->update($data, $vivit_condition);
}
Cache::tag("visit_info" . $today_date)->set("visit_info_" . $param["site_id"] . "_" . $param["type"] . "_" . $param["module"] . "_" . $param["addon"] . "_" . $today_date, $data);
return $res;
}
/**
* 查询统计 访问数据
* @param array $param
*/
public function getVisitStatisticsData($param = [])
{
$visit_model = model("nc_visit");//访问统计记录表
$date_range = $param["date_range"] ?? [];//时间范围
$date_type = $param["date_type"];//日期类型 用于查询方式
$type = $param["type"];//访问类型查询
if (empty($type) && !in_array($type, array('HOME', 'APP', 'API', 'ALL'))) {
$type = "ALL";
}
$condition = array();
switch ($type) {
case "HOME":
$condition["type"] = ["in", ["admin", "sitehome"]];
break;
case "APP":
$condition["type"] = ["in", ["wap", "web"]];
break;
case "API":
$condition["type"] = ["in", ["api"]];
break;
}
//站点id
if (!empty($param["site_id"])) {
$condition["site_id"] = $param["site_id"];
}
$today_date = date('Ymd');//当前日日期
$today_time = strtotime($today_date);
switch ($date_type) {
case 'today':
$date_condition = $today_date;
$date_x = periodGroup($today_time, $today_time);
break;
case 'yesterday':
$yesterday = strtotime(date("Ymd", strtotime('-1 days')));
$date_condition = date('Ymd', $yesterday);
$date_x = periodGroup($yesterday, $yesterday);
break;
case 'week':
$week = strtotime(date("Ymd", strtotime('-6 days')));
$date_condition = ["between", [date('Ymd', $week), $today_date]];
$date_x = periodGroup($week, $today_date);
break;
case 'month':
$month = strtotime(date("Ymd", strtotime('-29 days')));
$date_condition = ["between", [date('Ymd', $month), $today_date]];
$date_x = periodGroup($month, $today_time);
break;
case 'daterange':
$start_time = strtotime($date_range['start_date']);
$end_time = strtotime($date_range['end_date']);
$start_date = date('Ymd', $start_time);//开始日期
$end_date = date('Ymd', $end_time);//结束日期
$date_x = periodGroup($start_time, $end_time);
$date_condition = ["between", [$start_date, $end_date]];
break;
}
if (!empty($date_condition)) {
$condition["date"] = $date_condition;
}
$data1 = $visit_model->getList($condition, "*,sum(count) as visit_count", '', '', '', "date");
$visit_ip_model = model("nc_visit_ip");//访问统计记录表
$data2 = $visit_ip_model->getList($condition, "*,count( DISTINCT ip ) as visit_ip_count", '', '', '', "date");
$visit_data = [];
$ip_visit_data = [];
foreach ($date_x as $k => $v) {
$visit_count = 0;
$visit_ip_count = 0;
foreach ($data1 as $data1_k => $data1_v) {
if ($data1_v["date"] == $v) {
$visit_count = $data1_v["visit_count"];
continue;
}
}
foreach ($data2 as $data2_k => $data2_v) {
if ($data2_v["date"] == $v) {
$visit_ip_count = $data2_v["visit_ip_count"];
continue;
}
}
$visit_data[] = $visit_count;
$ip_visit_data[] = $visit_ip_count;
}
$data = array(
"date" => $date_x,
"data" => array(
"count_data" => $visit_data,
"ip_count_data" => $ip_visit_data,
)
);
return $this->success($data);
}
/**
* 统计一段时间内的总访问量
* @param $param
* @return \multitype
*/
public function getVisitCountData($param)
{
$visit_model = Db::table("nc_visit");//访问统计记录表
$date_range = $param["date_range"] ?? [];//时间范围
$date_type = $param["date_type"];//日期类型 用于查询方式
$type = $param["type"] ?? '';//访问类型查询
if (empty($type) && !in_array($type, array('HOME', 'APP', 'API', 'ALL'))) {
$type = "ALL";
}
$condition = array();
if ($type != "ALL") {
$condition["type"] = $type;
$visit_model = $visit_model->where("type", $type);
}
//站点id
if (!empty($param["site_id"])) {
$condition["site_id"] = $param["site_id"];
$visit_model = $visit_model->where("site_id", $param["site_id"]);
}
$today_date = date('Ymd');//当前日日期
switch ($date_type) {
case 'today':
$visit_model = $visit_model->where("date", $today_date);
break;
case 'yesterday':
$visit_model = $visit_model->where("date", strtotime('-1 days'));
break;
case 'week':
$visit_model = $visit_model->whereBetween("date", date('Ymd', strtotime('-6 days')), $today_date);
break;
case 'month':
$visit_model = $visit_model->whereBetween("date", date('Ymd', strtotime('-29 days')), $today_date);
break;
case 'daterange':
$start_date = date('Ymd', strtotime($date_range['start_date']));//开始日期
$end_date = date('Ymd', strtotime($date_range['end_date']));//结束日期
$visit_model = $visit_model->whereBetween("date", $start_date, $end_date);
break;
}
$visit_count = $visit_model->count();
$visit_ip_model = model("nc_visit_ip");//访问统计记录表
$visit_ip_result = $visit_ip_model->getInfo($condition, "count( DISTINCT ip ) as ip_count");
$visit_ip_count = $visit_ip_result["ip_count"];
$data = array(
"visit_count" => $visit_count,
"visit_ip_count" => $visit_ip_count
);
return $this->success($data);
}
public function test()
{
$arr = array('HOME', 'APP', 'API');
for ($i = 0; $i <= 100; $i++) {
$param["type"] = $arr[array_rand($arr)];
$param["site_id"] = rand(11111, 12000);
$param["module"] = "";
$num = sprintf("%02d", rand(1, 30));
$today_date = date("Ym" . $num);
$visit_model = model("nc_visit");//访问统计记录表
$visit_ip_model = model("nc_visit_ip");//ip访问记录表
// 启动事务
$ip_count = 0;
//ip访问记录
$ip = ip2long($this->get_rand_ip());
$vivit_ip_condition = array(
"date" => $today_date,
"site_id" => $param["site_id"],
"type" => $param["type"],
"module" => $param["module"],
"ip" => $ip
);
$visit_ip_info = $visit_ip_model->getInfo($vivit_ip_condition);
if (empty($visit_ip_info)) {
$ip_count += 1;
$ip_data = array(
"date" => $today_date,
"site_id" => $param["site_id"],
"type" => $param["type"],
"module" => $param["module"],
"ip" => $ip,
"ip_count" => 1
);
$visit_ip_res = $visit_ip_model->add($ip_data);
} else {
$ip_data = array(
"ip_count" => $visit_ip_info["ip_count"] + 1
);
$visit_ip_res = $visit_ip_model->update($ip_data, $vivit_ip_condition);
}
//访问记录
$vivit_condition = array(
"date" => $today_date,
"site_id" => $param["site_id"],
"type" => $param["type"],
"module" => $param["module"]
);
$visit_info = $visit_model->getInfo($vivit_condition);
//如果当前日不存在访问统计数据,则需要创建
if (empty($visit_info)) {
$data = array(
"date" => $today_date,
"site_id" => $param["site_id"],
"type" => $param["type"],
"module" => $param["module"],
"count" => 1,
"ip_count" => $ip_count
);
$res = $visit_model->add($data);
} else {
$data = array(
"count" => $visit_info["count"] + 1,
"ip_count" => $visit_info["ip_count"] + $ip_count
);
$visit_model->update($data, $vivit_condition);
}
}
}
function get_rand_ip()
{
$arr_1 = array("218", "218", "66", "66", "218", "218", "60", "60", "202", "204", "66", "66", "66", "59", "61", "60", "222", "221", "66", "59", "60", "60", "66", "218", "218", "62", "63", "64", "66", "66", "122", "211");
$randarr = mt_rand(0, count($arr_1));
// $ip1id = $arr_1[$randarr];
$ip1id = "218";
$ip2id = 600000 / 10000;
$ip3id = 2550000 / 10000;
$ip4id = 2550000 / 10000 - rand(0, 10);
return $ip1id . "." . $ip2id . "." . $ip3id . "." . $ip4id;
}
/**
* 获取时间段内分组
*/
public function periodGroup($srart_time, $end_time)
{
$type_time = 3600 * 24;
$format = 'Ymd';
$data = [];
for ($i = $srart_time; $i <= $end_time; $i += $type_time) {
$data[] = date($format, $i);
}
return $data;
}
/**
* 删除站点
* @param unknown $site_id
*/
public function deleteSite($site_id)
{
$visit_model = model("nc_visit");//访问统计记录表
$visit_ip_model = model("nc_visit_ip");//ip访问记录表
$visit_user_model = model("nc_visit_user");//用户模块访问记录表
$visit_model->delete(['site_id' => $site_id]);
$visit_ip_model->delete(['site_id' => $site_id]);
$visit_user_model->delete(['site_id' => $site_id]);
return $this->success();
}
}

67
app/model/system/Web.php Executable file
View File

@@ -0,0 +1,67 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\system;
use app\model\BaseModel;
use think\facade\Cache;
class Web extends BaseModel
{
private $url = "https://www.niushop.com/api/%s";
public function __construct()
{
}
/**
* 官网资讯
*/
public function news()
{
$cache = Cache::get("new_day");
if (!empty($cache)) {
return $cache;
}
$url = sprintf($this->url, 'news/news');
$post_data = [
];
$result = $this->doPost($url, $post_data);
$res = json_decode($result, true);
if ($res["code"] >= 0) {
Cache::set("new_day", $res, 86400);
}
return $res;
}
/**
* post 服务器请求
*/
private function doPost($post_url, $post_data)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $post_url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
if ($post_data != '' && !empty($post_data)) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}