初始化代码

This commit is contained in:
Anyon 2021-11-22 17:21:39 +08:00
parent a9c9aadd42
commit a245dfb938
587 changed files with 52382 additions and 55024 deletions

3
.gitattributes vendored
View File

@ -1,3 +0,0 @@
*.js linguist-language=php
*.css linguist-language=php
*.html linguist-language=php

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,69 +0,0 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- 尝试创建微信自动回复数据表
CREATE TABLE IF NOT EXISTS `wechat_auto`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '类型(text,image,news)',
`time` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '延迟时间',
`code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '消息编号',
`appid` char(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '公众号APPID',
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '文本内容',
`image_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '图片链接',
`voice_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '语音链接',
`music_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '音乐标题',
`music_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '音乐链接',
`music_image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '缩略图片',
`music_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '音乐描述',
`video_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '视频标题',
`video_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '视频URL',
`video_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '视频描述',
`news_id` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '图文ID',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0禁用,1启用)',
`create_by` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '创建人',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_wechat_auto_type` (`type`) USING BTREE,
INDEX `idx_wechat_auto_keys` (`time`) USING BTREE,
INDEX `idx_wechat_auto_appid` (`appid`) USING BTREE,
INDEX `idx_wechat_auto_code` (`code`) USING BTREE
) ENGINE = InnoDB
AUTO_INCREMENT = 1
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci COMMENT = '微信-回复'
ROW_FORMAT = COMPACT;
-- 调整字段名称长度
ALTER TABLE `system_queue`
MODIFY COLUMN `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '任务名称' AFTER `code`;
-- 尝试创建数据字典数据表
CREATE TABLE IF NOT EXISTS `system_base`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '数据类型',
`code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '数据代码',
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '数据名称',
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '数据内容',
`sort` bigint(20) NULL DEFAULT 0 COMMENT '排序权重',
`status` tinyint(1) NULL DEFAULT 1 COMMENT '数据状态(0禁用,1启动)',
`deleted` tinyint(1) NULL DEFAULT 0 COMMENT '删除状态(0正常,1已删)',
`deleted_at` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '删除时间',
`deleted_by` bigint(20) NULL DEFAULT 0 COMMENT '删除用户',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_system_base_type` (`type`) USING BTREE,
INDEX `idx_system_base_code` (`code`) USING BTREE,
INDEX `idx_system_base_name` (`name`(191)) USING BTREE
) ENGINE = InnoDB
AUTO_INCREMENT = 1
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci COMMENT = '系统-字典'
ROW_FORMAT = COMPACT;
-- 权限表增加身份权限字段
ALTER TABLE `system_user`
ADD COLUMN `usertype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '用户类型' AFTER `id`;
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -1,125 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemAuth;
use think\admin\model\SystemNode;
use think\admin\service\AdminService;
/**
* 系统权限管理
* Class Auth
* @package app\admin\controller
*/
class Auth extends Controller
{
/**
* 系统权限管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
SystemAuth::mQuery()->layTable(function () {
$this->title = '系统权限管理';
}, function (QueryHelper $query) {
$query->dateBetween('create_at')->like('title,desc')->equal('status,utype');
});
}
/**
* 添加系统权限
* @auth true
*/
public function add()
{
SystemAuth::mForm('form');
}
/**
* 编辑系统权限
* @auth true
*/
public function edit()
{
SystemAuth::mForm('form');
}
/**
* 修改权限状态
* @auth true
*/
public function state()
{
SystemAuth::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除系统权限
* @auth true
*/
public function remove()
{
SystemAuth::mDelete();
}
/**
* 权限配置节点
* @auth true
* @throws \ReflectionException
*/
public function apply()
{
$map = $this->_vali(['auth.require#id' => '权限ID不能为空']);
if (input('action') === 'get') {
$admin = AdminService::instance();
if ($this->app->isDebug()) $admin->clearCache();
$nodes = SystemNode::mk()->where($map)->column('node');
$this->success('获取权限节点成功!', $admin->getTree($nodes));
} elseif (input('action') === 'save') {
[$post, $data] = [$this->request->post(), []];
foreach ($post['nodes'] ?? [] as $node) {
$data[] = ['auth' => $map['auth'], 'node' => $node];
}
SystemNode::mk()->where($map)->delete();
SystemNode::mk()->insertAll($data);
sysoplog('系统权限管理', "配置系统权限[{$map['auth']}]授权成功");
$this->success('访问权限修改成功!', 'javascript:history.back()');
} else {
SystemAuth::mForm('apply');
}
}
/**
* 表单后置数据处理
* @param array $data
*/
protected function _apply_form_filter(array &$data)
{
if ($this->request->isGet()) {
$this->title = "编辑【{$data['title']}】授权";
}
}
}

View File

@ -1,110 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemBase;
/**
* 数据字典管理
* Class Base
* @package app\admin\controller
*/
class Base extends Controller
{
/**
* 数据字典管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
SystemBase::mQuery()->layTable(function () {
$this->title = '数据字典管理';
$this->types = SystemBase::mk()->types();
$this->type = input('get.type', $this->types[0] ?? '-');
}, function (QueryHelper $query) {
$query->where(['deleted' => 0])->equal('type');
$query->like('code,name,status')->dateBetween('create_at');
});
}
/**
* 添加数据字典
* @auth true
*/
public function add()
{
SystemBase::mForm('form');
}
/**
* 编辑数据字典
* @auth true
*/
public function edit()
{
SystemBase::mForm('form');
}
/**
* 表单数据处理
* @param array $data
*/
protected function _form_filter(array &$data)
{
if ($this->request->isGet()) {
$this->types = SystemBase::mk()->types();
$this->types[] = '--- 新增类型 ---';
$this->type = input('get.type') ?: ($this->types[0] ?? '-');
} else {
$map = [];
$map[] = ['deleted', '=', 0];
$map[] = ['code', '=', $data['code']];
$map[] = ['type', '=', $data['type']];
if (isset($data['id'])) $map[] = ['id', '<>', $data['id']];
if (SystemBase::mk()->where($map)->count() > 0) {
$this->error("同类型的数据编码已经存在!");
}
}
}
/**
* 修改数据状态
* @auth true
*/
public function state()
{
SystemBase::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除数据记录
* @auth true
*/
public function remove()
{
SystemBase::mDelete();
}
}

View File

@ -1,109 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\service\AdminService;
use think\admin\service\ModuleService;
use think\admin\service\SystemService;
use think\admin\storage\AliossStorage;
use think\admin\storage\QiniuStorage;
use think\admin\storage\TxcosStorage;
/**
* 系统参数配置
* Class Config
* @package app\admin\controller
*/
class Config extends Controller
{
/**
* 系统参数配置
* @auth true
* @menu true
*/
public function index()
{
$this->title = '系统参数配置';
$this->isSuper = AdminService::instance()->isSuper();
$this->version = ModuleService::instance()->getVersion();
$this->fetch();
}
/**
* 修改系统参数
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function system()
{
$this->_applyFormToken();
if ($this->request->isGet()) {
$this->title = '修改系统参数';
$this->fetch();
} else {
if ($xpath = $this->request->post('xpath')) {
if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $xpath)) {
$this->error('后台入口名称需要是由英文字母开头!');
}
if ($xpath !== 'admin' && file_exists($this->app->getBasePath() . $xpath)) {
$this->error("后台入口名称{$xpath}已经存在应用!");
}
SystemService::instance()->setRuntime(null, [$xpath => 'admin']);
}
foreach ($this->request->post() as $name => $value) sysconf($name, $value);
sysoplog('系统配置管理', "修改系统参数成功");
$this->success('修改系统参数成功!', admuri('admin/config/index'));
}
}
/**
* 修改文件存储
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function storage()
{
$this->_applyFormToken();
if ($this->request->isGet()) {
$this->type = input('type', 'local');
if ($this->type === 'alioss') {
$this->points = AliossStorage::region();
} elseif ($this->type === 'qiniu') {
$this->points = QiniuStorage::region();
} elseif ($this->type === 'txcos') {
$this->points = TxcosStorage::region();
}
$this->fetch("storage-{$this->type}");
} else {
$post = $this->request->post();
if (!empty($post['storage']['allow_exts'])) {
$deny = ['sh', 'asp', 'bat', 'cmd', 'exe', 'php'];
$exts = array_unique(str2arr(strtolower($post['storage']['allow_exts'])));
if (count(array_intersect($deny, $exts)) > 0) $this->error('禁止上传可执行的文件!');
$post['storage']['allow_exts'] = join(',', $exts);
}
foreach ($post as $name => $value) sysconf($name, $value);
sysoplog('系统配置管理', "修改系统存储参数");
$this->success('修改文件存储成功!');
}
}
}

View File

@ -1,121 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\model\SystemUser;
use think\admin\service\AdminService;
use think\admin\service\MenuService;
/**
* 后台界面入口
* Class Index
* @package app\admin\controller
*/
class Index extends Controller
{
/**
* 显示后台首页
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
/*! 根据运行模式刷新权限 */
$debug = $this->app->isDebug();
AdminService::instance()->apply($debug);
/*! 读取当前用户权限菜单树 */
$this->menus = MenuService::instance()->getTree();
/*! 判断当前用户的登录状态 */
$this->login = AdminService::instance()->isLogin();
/*! 菜单为空且未登录跳转到登录页 */
if (empty($this->menus) && empty($this->login)) {
$this->redirect(sysuri('admin/login/index'));
} else {
$this->title = '系统管理后台';
$this->isSuper = AdminService::instance()->isSuper();
$this->fetch();
}
}
/**
* 修改用户资料
* @login true
* @param mixed $id 用户ID
*/
public function info($id = 0)
{
$this->_applyFormToken();
if (AdminService::instance()->getUserId() === intval($id)) {
SystemUser::mForm('admin@user/form', 'id', [], ['id' => $id]);
} else {
$this->error('只能修改自己的资料!');
}
}
/**
* 资料修改后处理
* @param bool $status
*/
protected function _info_form_result(bool $status)
{
if ($status) {
$this->success('用户资料修改成功!', 'javascript:location.reload()');
}
}
/**
* 修改当前用户密码
* @login true
* @param mixed $id
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function pass($id = 0)
{
$this->_applyFormToken();
if (AdminService::instance()->getUserId() !== intval($id)) {
$this->error('只能修改当前用户的密码!');
}
if ($this->app->request->isGet()) {
$this->verify = true;
SystemUser::mForm('admin@user/pass', 'id', [], ['id' => $id]);
} else {
$data = $this->_vali([
'password.require' => '登录密码不能为空!',
'repassword.require' => '重复密码不能为空!',
'oldpassword.require' => '旧的密码不能为空!',
'password.confirm:repassword' => '两次输入的密码不一致!',
]);
$user = SystemUser::mk()->find($id);
if (empty($user)) $this->error('用户不存在!');
if (md5($data['oldpassword']) !== $user['password']) {
$this->error('旧密码验证失败,请重新输入!');
}
if ($user->save(['password' => md5($data['password'])])) {
sysoplog('系统用户管理', "修改用户[{$user['id']}]密码成功");
$this->success('密码修改成功,下次请使用新密码登录!', '');
} else {
$this->error('密码修改失败,请稍候再试!');
}
}
}
}

View File

@ -1,126 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
use think\admin\model\SystemUser;
use think\admin\service\AdminService;
use think\admin\service\CaptchaService;
use think\admin\service\SystemService;
/**
* 用户登录管理
* Class Login
* @package app\admin\controller
*/
class Login extends Controller
{
/**
* 后台登录入口
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
if ($this->app->request->isGet()) {
if (AdminService::instance()->isLogin()) {
$this->redirect(sysuri('admin/index/index'));
} else {
$this->title = '系统登录';
$this->captchaType = 'LoginCaptcha';
$this->captchaToken = CodeExtend::uniqidDate(18);
$this->developMode = SystemService::instance()->checkRunMode();
$this->backgrounds = strtr(sysconf('login_image') ?: '', '|', ',');
// 刷新当前后台域名
$host = "{$this->request->scheme()}://{$this->request->host()}";
if ($host !== sysconf('base.site_host')) sysconf('base.site_host', $host);
// 标记登录验证令牌
if (!$this->app->session->get('LoginInputSessionError')) {
$this->app->session->set($this->captchaType, $this->captchaToken);
}
$this->fetch();
}
} else {
$data = $this->_vali([
'username.require' => '登录账号不能为空!',
'username.min:4' => '登录账号不能少于4位字符!',
'password.require' => '登录密码不能为空!',
'password.min:4' => '登录密码不能少于4位字符!',
'verify.require' => '图形验证码不能为空!',
'uniqid.require' => '图形验证标识不能为空!',
]);
if (!CaptchaService::instance()->check($data['verify'], $data['uniqid'])) {
$this->error('图形验证码验证失败,请重新输入!');
}
/*! 用户信息验证 */
$map = ['username' => $data['username'], 'is_deleted' => 0];
$user = SystemUser::mk()->where($map)->find();
if (empty($user)) {
$this->app->session->set("LoginInputSessionError", true);
$this->error('登录账号或密码错误,请重新输入!');
}
if (empty($user['status'])) {
$this->app->session->set("LoginInputSessionError", true);
$this->error('账号已经被禁用,请联系管理员!');
}
if (md5("{$user['password']}{$data['uniqid']}") !== $data['password']) {
$this->app->session->set("LoginInputSessionError", true);
$this->error('登录账号或密码错误,请重新输入!');
}
$this->app->session->set('user', $user->toArray());
$this->app->session->delete("LoginInputSessionError");
$user->save([
'login_ip' => $this->app->request->ip(),
'login_at' => $this->app->db->raw('now()'),
'login_num' => $this->app->db->raw('login_num+1'),
]);
sysoplog('系统用户登录', '登录系统后台成功');
$this->success('登录成功', sysuri('admin/index/index'));
}
}
/**
* 生成验证码
*/
public function captcha()
{
$input = $this->_vali([
'type.require' => '验证码类型不能为空!',
'token.require' => '验证码标识不能为空!',
]);
$image = CaptchaService::instance()->initialize();
$captcha = ['image' => $image->getData(), 'uniqid' => $image->getUniqid()];
if ($this->app->session->get($input['type']) === $input['token']) {
$captcha['code'] = $image->getCode();
$this->app->session->delete($input['type']);
}
$this->success('生成验证码成功', $captcha);
}
/**
* 退出登录
*/
public function out()
{
$this->app->session->clear();
$this->app->session->destroy();
$this->success('退出登录成功!', sysuri('admin/login/index'));
}
}

View File

@ -1,150 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\extend\DataExtend;
use think\admin\model\SystemMenu;
use think\admin\service\AdminService;
use think\admin\service\MenuService;
use think\admin\service\NodeService;
/**
* 系统菜单管理
* Class Menu
* @package app\admin\controller
*/
class Menu extends Controller
{
/**
* 系统菜单管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '系统菜单管理';
$this->type = input('get.type', 'index');
SystemMenu::mQuery()->order('sort desc,id asc')->page(false, true);
}
/**
* 列表数据处理
* @param array $data
*/
protected function _index_page_filter(array &$data)
{
$data = DataExtend::arr2tree($data);
// 回收站过滤有效菜单
if ($this->type === 'recycle') foreach ($data as $k1 => &$p1) {
if (!empty($p1['sub'])) foreach ($p1['sub'] as $k2 => &$p2) {
if (!empty($p2['sub'])) foreach ($p2['sub'] as $k3 => $p3) {
if ($p3['status'] > 0) unset($p2['sub'][$k3]);
}
if (empty($p2['sub']) && ($p2['url'] === '#' or $p1['status'] > 0)) unset($p1['sub'][$k2]);
}
if (empty($p1['sub']) && ($p1['url'] === '#' or $p1['status'] > 0)) unset($data[$k1]);
}
// 菜单数据树数据变平化
$data = DataExtend::arr2table($data);
foreach ($data as &$vo) {
if ($vo['url'] !== '#' && !preg_match('/^(https?:)?(\/\/|\\\\)/i', $vo['url'])) {
$vo['url'] = trim(url($vo['url']) . ($vo['params'] ? "?{$vo['params']}" : ''), '\\/');
}
$vo['ids'] = join(',', DataExtend::getArrSubIds($data, $vo['id']));
}
}
/**
* 添加系统菜单
* @auth true
*/
public function add()
{
$this->_applyFormToken();
SystemMenu::mForm('form');
}
/**
* 编辑系统菜单
* @auth true
*/
public function edit()
{
$this->_applyFormToken();
SystemMenu::mForm('form');
}
/**
* 表单数据处理
* @param array $vo
* @throws \ReflectionException
*/
protected function _form_filter(array &$vo)
{
if ($this->request->isGet()) {
/* 清理权限节点 */
if ($this->app->isDebug()) {
AdminService::instance()->clearCache();
}
/* 选择自己的上级菜单 */
$vo['pid'] = $vo['pid'] ?? input('pid', '0');
/* 读取系统功能节点 */
$this->auths = [];
$this->nodes = MenuService::instance()->getList();
foreach (NodeService::instance()->getMethods() as $node => $item) {
if ($item['isauth'] && substr_count($node, '/') >= 2) {
$this->auths[] = ['node' => $node, 'title' => $item['title']];
}
}
/* 列出可选上级菜单 */
$menus = SystemMenu::mk()->order('sort desc,id asc')->column('id,pid,icon,url,node,title,params', 'id');
$this->menus = DataExtend::arr2table(array_merge($menus, [['id' => '0', 'pid' => '-1', 'url' => '#', 'title' => '顶部菜单']]));
if (isset($vo['id'])) foreach ($this->menus as $menu) if ($menu['id'] === $vo['id']) $vo = $menu;
foreach ($this->menus as $key => $menu) if ($menu['spt'] >= 3 || $menu['url'] !== '#') unset($this->menus[$key]);
if (isset($vo['spt']) && isset($vo['spc']) && in_array($vo['spt'], [1, 2]) && $vo['spc'] > 0) {
foreach ($this->menus as $key => $menu) if ($vo['spt'] <= $menu['spt']) unset($this->menus[$key]);
}
}
}
/**
* 修改菜单状态
* @auth true
*/
public function state()
{
$this->_applyFormToken();
SystemMenu::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除系统菜单
* @auth true
*/
public function remove()
{
$this->_applyFormToken();
SystemMenu::mDelete();
}
}

View File

@ -1,74 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\service\ModuleService;
/**
* 系统模块管理
* Class Module
* @package app\admin\controller
*/
class Module extends Controller
{
/**
* 系统模块管理
* @auth true
* @menu true
*/
public function index()
{
$this->title = '系统模块管理';
$this->modules = ModuleService::instance()->change();
$this->fetch();
}
/**
* 安装更新模块
* @auth true
*/
public function install()
{
$data = $this->_vali(['name.require' => '模块名称不能为空!']);
[$state, $message] = ModuleService::instance()->install($data['name']);
$state ? $this->success($message) : $this->error($message);
}
/**
* 查看模块更新
* @auth true
*/
public function change()
{
$data = $this->_vali(['name.require' => '模块名称不能为空!']);
$modules = ModuleService::instance()->online();
$locals = ModuleService::instance()->getModules();
if (isset($modules[$data['name']])) {
$this->module = $modules[$data['name']];
$this->current = $locals[$data['name']] ?? [];
$pattern = "|^(\d{4})\.(\d{2})\.(\d{2})\.(\d+)$|";
$this->module['change'] = array_reverse($this->module['change']);
foreach ($this->module['change'] as $version => &$change) {
$change = ['content' => $change, 'version' => preg_replace($pattern, '$1年$2月$3日 第 $4 次更新', $version)];
}
$this->fetch();
} else {
$this->error('未查询到模块更新记录!');
}
}
}

View File

@ -1,93 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use Exception;
use Ip2Region;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemOplog;
use think\exception\HttpResponseException;
/**
* 系统日志管理
* Class Oplog
* @package app\admin\controller
*/
class Oplog extends Controller
{
/**
* 系统日志管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
SystemOplog::mQuery()->layTable(function () {
$this->title = '系统日志管理';
$columns = SystemOplog::mk()->column('action,username', 'id');
$this->users = array_unique(array_column($columns, 'username'));
$this->actions = array_unique(array_column($columns, 'action'));
}, function (QueryHelper $query) {
$query->dateBetween('create_at')->equal('username,action')->like('content,geoip,node');
});
}
/**
* 列表数据处理
* @auth true
* @param array $data
* @throws \Exception
*/
protected function _index_page_filter(array &$data)
{
$region = new Ip2Region();
foreach ($data as &$vo) {
$isp = $region->btreeSearch($vo['geoip']);
$vo['geoisp'] = str_replace(['内网IP', '0', '|'], '', $isp['region'] ?? '') ?: '-';
}
}
/**
* 清理系统日志
* @auth true
*/
public function clear()
{
try {
SystemOplog::mQuery()->empty();
sysoplog('系统运维管理', '成功清理所有日志数据');
$this->success('日志清理成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error("日志清理失败,{$exception->getMessage()}");
}
}
/**
* 删除系统日志
* @auth true
*/
public function remove()
{
SystemOplog::mDelete();
}
}

View File

@ -1,106 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use Exception;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemQueue;
use think\admin\service\AdminService;
use think\admin\service\ProcessService;
use think\admin\service\QueueService;
use think\exception\HttpResponseException;
/**
* 系统任务管理
* Class Queue
* @package app\admin\controller
*/
class Queue extends Controller
{
/**
* 系统任务管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
SystemQueue::mQuery()->layTable(function () {
$this->title = '系统任务管理';
$this->iswin = ProcessService::instance()->iswin();
// 超级管理面板
if ($this->isSuper = AdminService::instance()->isSuper()) {
$process = ProcessService::instance();
if ($process->iswin() || empty($_SERVER['USER'])) {
$this->command = $process->think('xadmin:queue start');
} else {
$this->command = "sudo -u {$_SERVER['USER']} {$process->think('xadmin:queue start')}";
}
}
// 任务状态统计
$this->total = ['dos' => 0, 'pre' => 0, 'oks' => 0, 'ers' => 0];
SystemQueue::mk()->field('status,count(1) count')->group('status')->select()->map(function ($item) {
if ($item['status'] === 1) $this->total['pre'] = $item['count'];
if ($item['status'] === 2) $this->total['dos'] = $item['count'];
if ($item['status'] === 3) $this->total['oks'] = $item['count'];
if ($item['status'] === 4) $this->total['ers'] = $item['count'];
});
}, function (QueryHelper $query) {
$query->equal('status')->like('code,title,command');
$query->timeBetween('enter_time,exec_time')->dateBetween('create_at');
});
}
/**
* 重启系统任务
* @auth true
*/
public function redo()
{
try {
$data = $this->_vali(['code.require' => '任务编号不能为空!']);
$queue = QueueService::instance()->initialize($data['code'])->reset();
$queue->progress(1, '>>> 任务重置成功 <<<', 0.00);
$this->success('任务重置成功!', $queue->code);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 清理运行数据
* @auth true
*/
public function clean()
{
$this->_queue('定时清理系统运行数据', "xadmin:queue clean", 0, [], 0, 3600);
}
/**
* 删除系统任务
* @auth true
*/
public function remove()
{
SystemQueue::mDelete();
}
}

View File

@ -1,187 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemAuth;
use think\admin\model\SystemBase;
use think\admin\model\SystemUser;
use think\admin\service\AdminService;
use think\model\Relation;
/**
* 系统用户管理
* Class User
* @package app\admin\controller
*/
class User extends Controller
{
/**
* 系统用户管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->type = input('get.type', 'index');
// 创建快捷查询工具
SystemUser::mQuery()->layTable(function () {
$this->title = '系统用户管理';
$this->bases = SystemBase::mk()->items('身份权限');
}, function (QueryHelper $query) {
// 加载对应数据列表
if ($this->type === 'index') {
$query->where(['is_deleted' => 0, 'status' => 1]);
} elseif ($this->type = 'recycle') {
$query->where(['is_deleted' => 0, 'status' => 0]);
}
// 关联用户身份资料
$query->with(['userinfo' => function (Relation $relation) {
$relation->field('code,name,content');
}]);
// 数据列表搜索过滤
$query->equal('status,usertype')->dateBetween('login_at,create_at');
$query->like('username,nickname,contact_phone#phone,contact_mail#mail');
});
}
/**
* 添加系统用户
* @auth true
*/
public function add()
{
SystemUser::mForm('form');
}
/**
* 编辑系统用户
* @auth true
*/
public function edit()
{
SystemUser::mForm('form');
}
/**
* 修改用户密码
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function pass()
{
$this->_applyFormToken();
if ($this->request->isGet()) {
$this->verify = false;
SystemUser::mForm('pass');
} else {
$data = $this->_vali([
'id.require' => '用户ID不能为空',
'password.require' => '登录密码不能为空!',
'repassword.require' => '重复密码不能为空!',
'repassword.confirm:password' => '两次输入的密码不一致!',
]);
$user = SystemUser::mk()->find($data['id']);
if (!empty($user) && $user->save(['password' => md5($data['password'])])) {
sysoplog('系统用户管理', "修改用户[{$data['id']}]密码成功");
$this->success('密码修改成功,请使用新密码登录!', '');
} else {
$this->error('密码修改失败,请稍候再试!');
}
}
}
/**
* 表单数据处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _form_filter(array &$data)
{
if ($this->request->isPost()) {
// 账号权限绑定处理
$data['authorize'] = arr2str($data['authorize'] ?? []);
if (isset($data['id']) && $data['id'] > 0) {
unset($data['username']);
} else {
// 检查账号是否重复
if (empty($data['username'])) {
$this->error('登录账号不能为空!');
}
$map = ['username' => $data['username'], 'is_deleted' => 0];
if (SystemUser::mk()->where($map)->count() > 0) {
$this->error("账号已经存在,请使用其它账号!");
}
// 新添加的用户密码与账号相同
$data['password'] = md5($data['username']);
}
} else {
// 权限绑定处理
$data['authorize'] = str2arr($data['authorize'] ?? '');
// 用户身份数据
$this->bases = SystemBase::mk()->items('身份权限');
// 用户权限管理
$this->superName = AdminService::instance()->getSuperName();
$this->authorizes = SystemAuth::mk()->items();
}
}
/**
* 修改用户状态
* @auth true
*/
public function state()
{
$this->_checkInput();
SystemUser::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除系统用户
* @auth true
*/
public function remove()
{
$this->_checkInput();
SystemUser::mDelete();
}
/**
* 检查输入变量
*/
private function _checkInput()
{
if (in_array('10000', str2arr(input('id', '')))) {
$this->error('系统超级账号禁止删除!');
}
}
}

View File

@ -1,54 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use think\admin\Controller;
use think\admin\service\AdminService;
/**
* 通用插件管理
* Class Plugs
* @package app\admin\controller\api
*/
class Plugs extends Controller
{
/**
* 图标选择器
* @login true
*/
public function icon()
{
$this->title = '图标选择器';
$this->field = $this->app->request->get('field', 'icon');
$this->fetch(realpath(__DIR__ . '/../../view/api/icon.html'));
}
/**
* 优化数据库
* @login true
*/
public function optimize()
{
if (AdminService::instance()->isSuper()) {
sysoplog('系统运维管理', '创建数据库优化任务');
$this->_queue('优化数据库所有数据表', 'xadmin:database optimize');
} else {
$this->error('只有超级管理员才能操作!');
}
}
}

View File

@ -1,112 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use Exception;
use think\admin\Controller;
use think\admin\service\AdminService;
use think\admin\service\QueueService;
use think\exception\HttpResponseException;
/**
* 后台任务通用接口
* Class Queue
* @package app\admin\controller\api
*/
class Queue extends Controller
{
/**
* 任务进度查询
* @login true
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function progress()
{
$input = $this->_vali(['code.require' => '任务编号不能为空!']);
$queue = QueueService::instance()->initialize($input['code']);
$this->success('获取任务进度成功!', $queue->progress());
}
/**
* WIN停止监听进程
* @login true
*/
public function stop()
{
try {
$message = nl2br($this->app->console->call('xadmin:queue', ['stop'])->fetch());
if (stripos($message, 'sent end signal to process')) {
sysoplog('系统运维管理', '尝试停止后台服务主进程');
$this->success('停止后台服务主进程成功!');
} elseif (stripos($message, 'processes to stop')) {
$this->success('没有找到需要停止的进程!');
} else {
$this->error($message);
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* WIN创建监听进程
* @login true
*/
public function start()
{
try {
$message = $this->app->console->call('xadmin:queue', ['start'])->fetch();
if (stripos($message, 'daemons started successfully for pid')) {
sysoplog('系统运维管理', '尝试启动后台服务主进程');
$this->success('后台服务主进程启动成功!');
} elseif (stripos($message, 'daemons already exist for pid')) {
$this->success('后台服务主进程已经存在!');
} else {
$this->error(nl2br($message));
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 检查任务状态
* @login true
*/
public function status()
{
if (AdminService::instance()->isSuper()) try {
$message = $this->app->console->call('xadmin:queue', ['status'])->fetch();
if (preg_match('/process.*?\d+.*?running/', $message, $attrs)) {
echo '<span class="color-green">' . $message . '</span>';
} else {
echo '<span class="color-red">' . $message . '</span>';
}
} catch (Exception $exception) {
echo '<span class="color-red">' . $exception->getMessage() . '</span>';
} else {
echo '<span class="color-red">只有超级管理员才能操作!</span>';
}
}
}

View File

@ -1,121 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use Exception;
use think\admin\Controller;
use think\admin\model\SystemConfig;
use think\admin\service\AdminService;
use think\admin\service\SystemService;
use think\exception\HttpResponseException;
/**
* 系统运行控制管理
* Class Runtime
* @package app\admin\controller\api
*/
class Runtime extends Controller
{
/**
* 网站压缩发布
* @login true
*/
public function push()
{
if (AdminService::instance()->isSuper()) try {
AdminService::instance()->clearCache();
SystemService::instance()->pushRuntime();
sysoplog('系统运维管理', '刷新并创建网站路由缓存');
$this->success('网站缓存加速成功!', 'javascript:location.reload()');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
} else {
$this->error('只有超级管理员才能操作!');
}
}
/**
* 清理运行缓存
* @login true
*/
public function clear()
{
if (AdminService::instance()->isSuper()) try {
AdminService::instance()->clearCache();
SystemService::instance()->clearRuntime();
sysoplog('系统运维管理', '清理网站日志及缓存数据');
$this->success('清空缓存日志成功!', 'javascript:location.reload()');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
} else {
$this->error('只有超级管理员才能操作!');
}
}
/**
* 当前运行模式
* @login true
*/
public function debug()
{
if (AdminService::instance()->isSuper()) if (input('state')) {
SystemService::instance()->setRuntime('product');
sysoplog('系统运维管理', '由开发模式切换为生产模式');
$this->success('已切换为生产模式!', 'javascript:location.reload()');
} else {
SystemService::instance()->setRuntime('debug');
sysoplog('系统运维管理', '由生产模式切换为开发模式');
$this->success('已切换为开发模式!', 'javascript:location.reload()');
} else {
$this->error('只有超级管理员才能操作!');
}
}
/**
* 清理系统配置
* @login true
*/
public function config()
{
if (AdminService::instance()->isSuper()) try {
[$tmpdata, $newdata] = [[], []];
foreach (SystemConfig::mk()->order('type,name asc')->cursor() as $item) {
$tmpdata[$item['type']][$item['name']] = $item['value'];
}
foreach ($tmpdata as $type => $items) foreach ($items as $name => $value) {
$newdata[] = ['type' => $type, 'name' => $name, 'value' => $value];
}
$this->app->db->transaction(function () use ($newdata) {
SystemConfig::mQuery()->empty()->insertAll($newdata);
});
$this->app->cache->delete('SystemConfig');
sysoplog('系统运维管理', '清理系统参数配置成功');
$this->success('清理系统配置成功!', 'javascript:location.reload()');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
} else {
$this->error('只有超级管理员才能操作!');
}
}
}

View File

@ -1,77 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use think\admin\Controller;
use think\admin\service\ModuleService;
use think\admin\service\SystemService;
/**
* 安装服务端支持
* Class Update
* @package app\admin\controller\api
*/
class Update extends Controller
{
/**
* 访问环境拦截
*/
protected function initialize()
{
if (!SystemService::instance()->checkRunMode()) {
$this->error('只允许访问本地或官方代码!');
}
}
/**
* 读取文件内容
*/
public function get()
{
$filename = decode(input('encode', '0'));
if (!ModuleService::instance()->checkAllowDownload($filename)) {
$this->error('下载的文件不在认证规则中!');
}
if (file_exists($realname = $this->app->getRootPath() . $filename)) {
$this->success('读取文件内容成功!', [
'content' => base64_encode(file_get_contents($realname)),
]);
} else {
$this->error('读取文件内容失败!');
}
}
/**
* 读取文件列表
*/
public function node()
{
$this->success('获取文件列表成功!', ModuleService::instance()->getChanges(
json_decode($this->request->post('rules', '[]', ''), true),
json_decode($this->request->post('ignore', '[]', ''), true)
));
}
/**
* 获取模块信息
*/
public function version()
{
$this->success('获取模块信息成功!', ModuleService::instance()->getModules());
}
}

View File

@ -1,228 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use Exception;
use think\admin\Controller;
use think\admin\Storage;
use think\admin\storage\AliossStorage;
use think\admin\storage\LocalStorage;
use think\admin\storage\QiniuStorage;
use think\admin\storage\TxcosStorage;
use think\exception\HttpResponseException;
use think\file\UploadedFile;
use think\Response;
/**
* 文件上传接口
* Class Upload
* @package app\admin\controller\api
*/
class Upload extends Controller
{
/**
* 文件上传脚本
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index(): Response
{
$data = ['exts' => []];
foreach (str2arr(sysconf('storage.allow_exts')) as $ext) {
$data['exts'][$ext] = Storage::mime($ext);
}
$template = realpath(__DIR__ . '/../../view/api/upload.js');
$data['exts'] = json_encode($data['exts'], JSON_UNESCAPED_UNICODE);
$data['nameType'] = sysconf('storage.name_type') ?: 'xmd5';
return view($template, $data)->contentType('application/x-javascript');
}
/**
* 文件上传检查
* @login true
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function state()
{
[$name, $safe] = [input('name'), $this->getSafe()];
$data = ['uptype' => $this->getType(), 'safe' => intval($safe), 'key' => input('key')];
if ($info = Storage::instance($data['uptype'])->info($data['key'], $safe, $name)) {
$data['url'] = $info['url'];
$data['key'] = $info['key'];
$this->success('文件已经上传', $data, 200);
} elseif ('local' === $data['uptype']) {
$data['url'] = LocalStorage::instance()->url($data['key'], $safe, $name);
$data['server'] = LocalStorage::instance()->upload();
} elseif ('qiniu' === $data['uptype']) {
$data['url'] = QiniuStorage::instance()->url($data['key'], $safe, $name);
$data['token'] = QiniuStorage::instance()->buildUploadToken($data['key'], 3600, $name);
$data['server'] = QiniuStorage::instance()->upload();
} elseif ('alioss' === $data['uptype']) {
$token = AliossStorage::instance()->buildUploadToken($data['key'], 3600, $name);
$data['url'] = $token['siteurl'];
$data['policy'] = $token['policy'];
$data['signature'] = $token['signature'];
$data['OSSAccessKeyId'] = $token['keyid'];
$data['server'] = AliossStorage::instance()->upload();
} elseif ('txcos' === $data['uptype']) {
$token = TxcosStorage::instance()->buildUploadToken($data['key'], 3600, $name);
$data['url'] = $token['siteurl'];
$data['q-ak'] = $token['q-ak'];
$data['policy'] = $token['policy'];
$data['q-key-time'] = $token['q-key-time'];
$data['q-signature'] = $token['q-signature'];
$data['q-sign-algorithm'] = $token['q-sign-algorithm'];
$data['server'] = TxcosStorage::instance()->upload();
}
$this->success('获取上传授权参数', $data, 404);
}
/**
* 文件上传入口
* @login true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function file()
{
if (!($file = $this->getFile())->isValid()) {
$this->error('文件上传异常,文件过大或未上传!');
}
$safeMode = $this->getSafe();
$extension = strtolower($file->getOriginalExtension());
$saveName = input('key') ?: Storage::name($file->getPathname(), $extension, '', 'md5_file');
// 检查文件名称是否合法
if (strpos($saveName, '../') !== false) {
$this->error('文件路径不能出现跳级操作!');
}
// 检查文件后缀是否被恶意修改
if (pathinfo(parse_url($saveName, PHP_URL_PATH), PATHINFO_EXTENSION) !== $extension) {
$this->error('文件后缀异常,请重新上传文件!');
}
// 屏蔽禁止上传指定后缀的文件
if (!in_array($extension, str2arr(sysconf('storage.allow_exts')))) {
$this->error('文件类型受限,请在后台配置规则!');
}
if (in_array($extension, ['sh', 'asp', 'bat', 'cmd', 'exe', 'php'])) {
$this->error('文件安全保护,禁止上传可执行文件!');
}
try {
if ($this->getType() === 'local') {
$local = LocalStorage::instance();
$distName = $local->path($saveName, $safeMode);
$file->move(dirname($distName), basename($distName));
$info = $local->info($saveName, $safeMode, $file->getOriginalName());
if (in_array($extension, ['jpg', 'gif', 'png', 'bmp', 'jpeg', 'wbmp'])) {
if ($this->imgNotSafe($distName) && $local->del($saveName)) {
$this->error('图片未通过安全检查!');
}
[$width, $height] = getimagesize($distName);
if (($width < 1 || $height < 1) && $local->del($saveName)) {
$this->error('读取图片的尺寸失败!');
}
}
} else {
$bina = file_get_contents($file->getPathname());
$info = Storage::instance($this->getType())->set($saveName, $bina, $safeMode, $file->getOriginalName());
}
if (isset($info['url'])) {
$this->success('文件上传成功!', ['url' => $safeMode ? $saveName : $info['url']]);
} else {
$this->error('文件处理失败,请稍候再试!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 获取文件上传类型
* @return boolean
*/
private function getSafe(): bool
{
return boolval(input('safe', '0'));
}
/**
* 获取文件上传方式
* @return string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getType(): string
{
$type = strtolower(input('uptype', ''));
if (in_array($type, ['local', 'qiniu', 'alioss', 'txcos'])) {
return $type;
} else {
return strtolower(sysconf('storage.type'));
}
}
/**
* 获取本地文件对象
* @return UploadedFile|void
*/
private function getFile(): UploadedFile
{
try {
$file = $this->request->file('file');
if ($file instanceof UploadedFile) {
return $file;
} else {
$this->error('未获取到上传的文件对象!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error(lang($exception->getMessage()));
}
}
/**
* 检查图片是否安全
* @param string $filename
* @return boolean
*/
private function imgNotSafe(string $filename): bool
{
$source = fopen($filename, 'rb');
if (($size = filesize($filename)) > 512) {
$hexs = bin2hex(fread($source, 512));
fseek($source, $size - 512);
$hexs .= bin2hex(fread($source, 512));
} else {
$hexs = bin2hex(fread($source, $size));
}
if (is_resource($source)) fclose($source);
$bins = hex2bin($hexs);
/* 匹配十六进制中的 <% ( ) %> 或 <? ( ) ?> 或 <script | /script> */
foreach (['<?php ', '<% ', '<script '] as $key) if (stripos($bins, $key) !== false) return true;
return preg_match("/(3c25.*?28.*?29.*?253e)|(3c3f.*?28.*?29.*?3f3e)|(3C534352495054)|(2F5343524950543E)|(3C736372697074)|(2F7363726970743E)/is", $hexs);
}
}

View File

@ -1,2 +0,0 @@
* 系统模块初始化成功
* 这次更新了许多内容哦

View File

@ -1 +0,0 @@
* 少量更新修复部分BUG

View File

@ -1,2 +0,0 @@
* 修正系统用户搜索
* 系统菜单支持外链

View File

@ -1,2 +0,0 @@
* 修复任意下载问题
* 优化模块管理机制

View File

@ -1,3 +0,0 @@
* 数据展示优化
* 后台UI升级到最新版本
* 后台文件上传机制优化

View File

@ -1,6 +0,0 @@
{
"name": "admin",
"author": "Anyon",
"version": "2021.06.17.01",
"content": "ThinkAdmin 系统基础模块"
}

View File

@ -1,62 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
use think\admin\service\SystemService;
use think\App;
invoke(function (App $app) {
/*! 非开发环境,清理限制文件 */
if ($app->request->isGet() && !SystemService::instance()->checkRunMode()) {
@unlink("{$app->getBasePath()}admin/controller/api/Update.php");
@unlink("{$app->getBasePath()}admin/route/demo.php");
@rmdir("{$app->getBasePath()}admin/route");
return;
}
/*! 演示环境禁止操作路由绑定 */
if (SystemService::instance()->checkRunMode('demo')) {
$app->route->post('index/pass', function () {
return json(['code' => 0, 'info' => '演示环境禁止修改用户密码!']);
});
$app->route->post('config/system', function () {
return json(['code' => 0, 'info' => '演示环境禁止修改系统配置!']);
});
$app->route->post('config/storage', function () {
return json(['code' => 0, 'info' => '演示环境禁止修改系统配置!']);
});
$app->route->post('menu', function () {
return json(['code' => 0, 'info' => '演示环境禁止给菜单排序!']);
});
$app->route->post('menu/index', function () {
return json(['code' => 0, 'info' => '演示环境禁止给菜单排序!']);
});
$app->route->post('menu/add', function () {
return json(['code' => 0, 'info' => '演示环境禁止添加菜单!']);
});
$app->route->post('menu/edit', function () {
return json(['code' => 0, 'info' => '演示环境禁止编辑菜单!']);
});
$app->route->post('menu/state', function () {
return json(['code' => 0, 'info' => '演示环境禁止禁用菜单!']);
});
$app->route->post('menu/remove', function () {
return json(['code' => 0, 'info' => '演示环境禁止删除菜单!']);
});
$app->route->post('user/pass', function () {
return json(['code' => 0, 'info' => '演示环境禁止修改用户密码!']);
});
}
});

File diff suppressed because it is too large Load Diff

View File

@ -1,146 +0,0 @@
define(['md5'], function (SparkMD5, allowMime) {
allowMime = JSON.parse('{$exts|raw}');
return function (element, callable) {
/*! 初始化变量 */
var opt = {elem: $(element), exts: [], mimes: [], files: {}, cache: {}, load: 0, count: {total: 0, uploaded: 0}};
opt.size = opt.elem.data('size') || 0, opt.mult = opt.elem.data('multiple') > 0;
opt.safe = opt.elem.data('safe') ? 1 : 0, opt.hide = opt.elem.data('hide-load') ? 1 : 0;
opt.type = opt.safe ? 'local' : opt.elem.attr('data-uptype') || '';
/*! 查找表单元素, 如果没有找到将不会自动写值 */
if (!opt.elem.data('input') && opt.elem.data('field')) {
var $input = $('input[name="' + opt.elem.data('field') + '"]:not([type=file])');
opt.elem.data('input', $input.size() > 0 ? $input.get(0) : null);
}
/*! 文件选择筛选,使用 MIME 规则过滤文件列表 */
$((opt.elem.data('type') || '').split(',')).map(function (i, e) {
if (allowMime[e]) opt.exts.push(e), opt.mimes.push(allowMime[e]);
});
/*! 初始化上传组件 */
opt.uploader = layui.upload.render({
url: '{:sysuri("admin/api.upload/file")}', auto: false, elem: element, accept: 'file', multiple: opt.mult,
exts: opt.exts.join('|'), acceptMime: opt.mimes.join(','), choose: function (object) {
opt.elem.triggerHandler('upload.choose', opt.files = object.pushFile());
opt.uploader.config.elem.next().val(''), layui.each(opt.files, function (index, file) {
if (opt.size > 0 && file.size > opt.size) return delete opt.files[index], $.msg.tips('文件大小超出限制!');
opt.load = opt.hide || $.msg.loading('上传进度 <span data-upload-progress>0%</span>');
opt.count.total++, file.index = index, opt.cache[index] = file, delete opt.files[index];
md5file(file).then(function (file) {
opt.elem.triggerHandler('upload.hash', file), jQuery.ajax("{:sysuri('admin/api.upload/state')}", {
data: {key: file.xkey, uptype: opt.type, safe: opt.safe, name: file.name}, method: 'post', success: function (ret) {
file.xurl = ret.data.url, file.xsafe = ret.data.safe;
file.xpath = ret.data.key, file.xtype = ret.data.uptype;
if (parseInt(ret.code) === 404) {
opt.uploader.config.url = ret.data.server;
opt.uploader.config.data.key = ret.data.key;
opt.uploader.config.data.safe = ret.data.safe;
opt.uploader.config.data.uptype = ret.data.uptype;
if (ret.data.uptype === 'qiniu') {
opt.uploader.config.data.token = ret.data.token;
} else if (ret.data.uptype === 'alioss') {
opt.uploader.config.data['policy'] = ret.data.policy;
opt.uploader.config.data['signature'] = ret.data.signature;
opt.uploader.config.data['OSSAccessKeyId'] = ret.data.OSSAccessKeyId;
opt.uploader.config.data['success_action_status'] = 200;
opt.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
} else if (ret.data.uptype === 'txcos') {
opt.uploader.config.data['q-ak'] = ret.data['q-ak'];
opt.uploader.config.data['policy'] = ret.data['policy'];
opt.uploader.config.data['q-key-time'] = ret.data['q-key-time'];
opt.uploader.config.data['q-signature'] = ret.data['q-signature'];
opt.uploader.config.data['q-sign-algorithm'] = ret.data['q-sign-algorithm'];
opt.uploader.config.data['success_action_status'] = 200;
opt.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
}
object.upload(file.index, file);
} else if (parseInt(ret.code) === 200) {
file.xurl = ret.data.url;
opt.uploader.config.done({code: 1, url: file.xurl, info: '文件秒传成功!'}, file.index);
} else {
$.msg.tips(ret.info || ret.error.message || '文件上传出错!');
}
}
});
});
});
}, progress: function (number) {
/*! 文件上传进度处理 */
opt.elem.triggerHandler('upload.progress', {number: number, event: arguments[2], file: arguments[3]});
if (opt.count.total > 1) {
$('[data-upload-progress]').html(number + '%' + ' ' + (opt.count.uploaded + 1) + '/' + opt.count.total);
} else {
$('[data-upload-progress]').html(number + '%');
}
}, done: function (ret, idx) {
/*! 检查单个文件上传返回的结果 */
if (ret.code < 1) return $.msg.tips(ret.info || '文件上传失败!');
if (typeof opt.cache[idx].xurl !== 'string') return $.msg.tips('无效的文件上传对象!');
/*! 单个文件上传成功结果处理 */
if (typeof callable === 'function') {
callable.call(opt.elem, opt.cache[idx].xurl, opt.cache['id']);
} else if (opt.mult < 1 && opt.elem.data('input')) {
$(opt.elem.data('input')).val(opt.cache[idx].xurl).trigger('change', opt.cache[idx]);
}
opt.elem.html(opt.elem.data('html')).triggerHandler('upload.done', {file: opt.cache[idx], data: ret});
/*! 所有文件上传完成后结果处理 */
if (++opt.count.uploaded >= opt.count.total) {
opt.hide || $.msg.close(opt.load);
if (opt.mult > 0 && opt.elem.data('input')) {
var urls = opt.elem.data('input').value || [];
if (typeof urls === 'string') urls = urls.split('|');
for (var i in opt.cache) urls.push(opt.cache[i].xurl);
$(opt.elem.data('input')).val(urls.join('|')).trigger('change', opt.cache);
}
opt.elem.triggerHandler('upload.complete', {file: opt.cache});
(opt.cache = [], opt.files = [], opt.count = {uploaded: 0, total: 0}), opt.uploader.reload();
}
}
});
};
function md5file(file) {
var deferred = jQuery.Deferred();
file.xext = file.name.indexOf('.') > -1 ? file.name.split('.').pop() : 'tmp';
/*! 兼容不能计算文件 HASH 的情况 */
var IsDate = '{$nameType|default=""}'.indexOf('date') > -1;
if (!window.FileReader || IsDate) return jQuery.when((function (xmd5, chars) {
while (xmd5.length < 32) xmd5 += chars.charAt(Math.floor(Math.random() * chars.length));
return setFileXdata(file, xmd5, 6), deferred.resolve(file, file.xmd5, file.xkey), deferred;
})(layui.util.toDateString(Date.now(), 'yyyyMMddHHmmss-'), '0123456789'));
/*! 读取文件并计算 HASH 值 */
var spark = new SparkMD5.ArrayBuffer();
var slice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
file.chunkIdx = 0, file.chunkSize = 2097152, file.chunkTotal = Math.ceil(this.size / this.chunkSize);
return jQuery.when(loadNextChunk(file));
function setFileXdata(file, xmd5, slice) {
file.xmd5 = xmd5, file.xkey = file.xmd5.substr(0, slice || 2) + '/' + file.xmd5.substr(slice || 2, 30) + '.' + file.xext;
return delete file.chunkIdx, delete file.chunkSize, delete file.chunkTotal, file;
}
function loadNextChunk(file) {
this.reader = new FileReader();
this.reader.onload = function (event) {
spark.append(event.target.result);
if (++file.chunkIdx < file.chunkTotal) {
loadNextChunk(file);
} else {
setFileXdata(file, spark.end());
deferred.resolve(file, file.xmd5, file.xkey);
}
};
this.reader.onerror = function () {
deferred.reject();
};
this.start = file.chunkIdx * file.chunkSize;
this.loaded = (this.start + file.chunkSize >= file.size) ? file.size : this.start + file.chunkSize;
this.reader.readAsArrayBuffer(slice.call(file, this.start, this.loaded));
return deferred.notify(file, (this.loaded / file.size * 100).toFixed(2)), deferred;
}
}
});

View File

@ -1,104 +0,0 @@
{extend name='main'}
{block name="content"}
<div class="think-box-shadow">
<ul id="zTree" class="ztree notselect"></ul>
<div class="hr-line-dashed"></div>
<div class="layui-form-item text-center">
<button class="layui-btn" data-submit-role type='button'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' onclick="window.history.back()">取消编辑</button>
</div>
</div>
{/block}
{block name="script"}
<script>
require(['jquery.ztree'], function () {
new function () {
var that = this;
this.data = {}, this.ztree = null, this.setting = {
view: {showLine: false, showIcon: false, dblClickExpand: false},
check: {enable: true, nocheck: false, chkboxType: {"Y": "ps", "N": "ps"}}, callback: {
beforeClick: function (id, node) {
node.children.length < 1 ? that.ztree.checkNode(node, !node.checked, null, true) : that.ztree.expandNode(node);
return false;
}
}
};
this.renderChildren = function (list, level) {
var childrens = [];
for (var i in list) childrens.push({
open: true, node: list[i].node, name: list[i].title || list[i].node,
checked: list[i].checked || false, children: this.renderChildren(list[i]._sub_, level + 1)
});
return childrens;
};
this.getData = function () {
$.form.load('{:url("apply")}', {id: '{$vo.id}', action: 'get'}, 'post', function (ret) {
return (that.data = that.renderChildren(ret.data, 1)), that.showTree(), false;
});
};
this.showTree = function () {
this.ztree = $.fn.zTree.init($("#zTree"), this.setting, this.data);
while (true) {
var nodes = this.ztree.getNodesByFilter(function (node) {
return (!node.node && node.children.length < 1);
});
if (nodes.length < 1) break;
for (var i in nodes) this.ztree.removeNode(nodes[i]);
}
};
this.submit = function () {
var nodes = [], data = this.ztree.getCheckedNodes(true);
for (var i in data) if (data[i].node) nodes.push(data[i].node);
$.form.load('{:url("apply")}', {id: '{$vo.id}', action: 'save', nodes: nodes}, 'post');
};
// 刷新数据
this.getData();
// 提交表单
$('[data-submit-role]').on('click', function () {
that.submit();
});
};
});
</script>
{/block}
{block name="style"}
<style>
ul.ztree li {
white-space: normal !important;
}
ul.ztree li span.button.switch {
margin-right: 5px;
}
ul.ztree ul ul li {
display: inline-block;
white-space: normal;
}
ul.ztree > li {
padding: 15px 25px 15px 15px;
}
ul.ztree > li > ul {
margin-top: 12px;
border-top: 1px solid rgba(0, 0, 0, .1);
}
ul.ztree > li > ul > li {
padding: 5px;
}
ul.ztree > li > a > span {
font-weight: 700;
font-size: 15px;
}
ul.ztree .level2 .button.level2 {
background: 0 0;
}
</style>
{/block}

View File

@ -1,25 +0,0 @@
<form class="layui-form layui-card" id="AuthForm" action="{:sysuri()}" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body padding-left-40">
<label class="layui-form-item relative block">
<span class="help-label"><b>权限名称</b>Permission Name</span>
<input maxlength="100" class="layui-input" name="title" value='{$vo.title|default=""}' required placeholder="请输入权限名称">
<span class="help-block">访问权限名称需要保持不重复,在给用户授权时需要根据名称选择!</span>
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>权限描述</b>Permission Description</span>
<textarea placeholder="请输入权限描述" maxlength="200" class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
</label>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>

View File

@ -1,79 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if auth("add")}-->
<button data-modal='{:url("add")}' data-title="添加权限" class='layui-btn layui-btn-sm layui-btn-primary'>添加权限</button>
<!--{/if}-->
<!--{if auth("remove")}-->
<button data-action='{:url("remove")}' data-table-id="RoleData" data-rule="id#{id}" data-confirm="确定要批量删除权限吗?" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file='auth/index_search'}
<table id="RoleData" data-url="{:sysuri()}" data-target-search="form.form-search"></table>
</div>
{/block}
{block name='script'}
<script>
$(function () {
// 初始化表格组件
$('#RoleData').layTable({
even: true, height: 'full',
sort: {field: 'sort desc,id', type: 'desc'},
cols: [[
{checkbox: true, fixed: true},
{field: 'sort', title: '排序权重', align: 'center', width: 100, sort: true, templet: '#SortInputTpl'},
{field: 'title', title: '权限名称', align: 'center', minWidth: 140},
{field: 'desc', title: '权限描述', align: 'center', minWidth: 110, templet: '<div>{{d.desc||"-"}}</div>'},
{field: 'status', title: '权限状态', align: 'center', minWidth: 110, templet: '#StatusSwitchTpl'},
{field: 'create_at', title: '创建时间', align: 'center', minWidth: 170, sort: true},
{toolbar: '#toolbar', title: '操作面板', align: 'center', minWidth: 210, fixed: 'right'},
]]
});
// 数据状态切换操作
layui.form.on('switch(StatusSwitch)', function (obj) {
$.form.load("{:url('state')}", {id: obj.value, status: obj.elem.checked > 0 ? 1 : 0}, 'post', function (ret) {
if (ret.code < 1) $.msg.error(ret.info, 3, function () {
$('#RoleData').trigger('reload'); // 操作异常时重载数据
});
return false;
}, false);
});
});
</script>
<!-- 列表排序权重模板 -->
<script type="text/html" id="SortInputTpl">
<input min="0" type="number" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
</script>
<!-- 数据状态切换模板 -->
<script type="text/html" id="StatusSwitchTpl">
<!--{if auth("state")}-->
<input type="checkbox" value="{{d.id}}" lay-skin="switch" lay-text="已激活|已禁用" lay-filter="StatusSwitch" {{d.status>0?'checked':''}}>
<!--{else}-->
{{d.status ? '<b class="color-green">已启用</b>' : '<b class="color-red">已禁用</b>'}}
<!--{/if}-->
</script>
<!-- 数据操作工具条模板 -->
<script type="text/html" id="toolbar">
<!--{if auth('edit')}-->
<a class="layui-btn layui-btn-primary layui-btn-sm" data-title="编辑权限" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
<!--{/if}-->
<!--{if auth("apply")}-->
<a class="layui-btn layui-btn-normal layui-btn-sm" data-open='{:url("apply")}?id={{d.id}}'>授 权</a>
<!--{/if}-->
<!--{if auth("remove")}-->
<a class="layui-btn layui-btn-danger layui-btn-sm" data-confirm="确定要删除权限吗?" data-action="{:url('remove')}" data-value="id#{{d.id}}">删 除</a>
<!--{/if}-->
</script>
{/block}

View File

@ -1,47 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">权限名称</label>
<div class="layui-input-inline">
<input name="title" value="{$get.title|default=''}" placeholder="请输入权限名称" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">权限描述</label>
<div class="layui-input-inline">
<input name="desc" value="{$get.desc|default=''}" placeholder="请输入权限描述" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">使用状态</label>
<div class="layui-input-inline">
<select class="layui-select" name="status">
<option value=''>-- 全部状态 --</option>
{foreach ['已禁用的权限','已激活的权限'] as $k=>$v}
{if input('get.status') eq $k.""}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
<script>layui.form.render()</script>
</fieldset>

View File

@ -1,69 +0,0 @@
<form class="layui-form layui-card" action="{:sysuri()}" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body padding-left-40">
<div class="layui-form-item">
<div class="help-label label-required-prev"><b>数据类型</b>DataType</div>
{if isset($vo.type)}
<label><input readonly value="{$vo.type|default=''}" class="layui-input think-bg-gray"></label>
{else}
<select class="layui-select" lay-filter="DataType">
{foreach $types as $type}{if (isset($vo.type) and $type eq $vo.type) or ($type eq input('get.type'))}
<option selected value="{$type}">{$type}</option>
{else}
<option value="{$type}">{$type}</option>
{/if}{/foreach}
</select>
<script>
layui.form.render();
(function (callable) {
layui.form.on('select(DataType)', callable);
callable({value: "{$vo.type|default=''}" || $('[lay-filter=DataType]').val()});
})(function (data) {
if (data.value === '--- 新增类型 ---') {
$('#DataTypeInput').removeClass('layui-hide').find('input').val('').focus();
} else {
$('#DataTypeInput').addClass('layui-hide').find('input').val(data.value);
}
});
</script>
{/if}
<p class="help-block">请选择数据类型,数据创建后不能再次修改哦 ~</p>
<div id="DataTypeInput" class="layui-hide relative">
<input class="layui-input" maxlength="20" name="type" required placeholder="请输入数据类型" value="{$vo.type|default=''}">
<p class="help-block">请输入新的数据类型,数据创建后不能再次修改哦 ~</p>
</div>
</div>
<label class="layui-form-item relative block">
<span class="help-label"><b>数据编码</b>DataCode</span>
{if isset($vo.code)}
<input readonly maxlength="50" class="layui-input think-bg-gray" name="code" value='{$vo.code|default=""}' required placeholder="请输入数据编码">
{else}
<input maxlength="50" class="layui-input" name="code" value='{$vo.code|default=""}' required placeholder="请输入数据编码">
{/if}
<span class="help-block">请输入新的数据编码,数据创建后不能再次修改,同种数据类型的数据编码不能出现重复 ~</span>
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>数据名称</b>DataName</span>
<input maxlength="100" class="layui-input" name="name" value='{$vo.name|default=""}' required placeholder="请输入数据名称">
<span class="help-block">请输入当前数据名称,请尽量保持名称的唯一性,数据名称尽量不要出现重复 ~</span>
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>数据内容</b>DataContent</span>
<textarea name="content" class="layui-textarea" placeholder="请输入数据内容">{$vo.content|default=''}</textarea>
</label>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>

View File

@ -1,85 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if auth("add")}-->
<button data-modal='{:url("add")}?type={$type|default=""}' data-title="添加数据" class='layui-btn layui-btn-sm layui-btn-primary'>添加数据</button>
<!--{/if}-->
<!--{if auth("remove")}-->
<button data-action='{:url("remove")}' data-table-id="BaseData" data-rule="id#{id}" data-confirm="确定要批量删除数据吗?" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="layui-tab layui-tab-card">
<ul class="layui-tab-title">
{foreach $types as $t}{if isset($type) and $type eq $t}
<li class="layui-this color-green" data-open="{:sysuri()}?type={$t}">{$t}</li>
{else}
<li data-open="{:sysuri()}?type={$t}">{$t}</li>
{/if}{/foreach}
</ul>
<div class="layui-tab-content">
{include file='base/index_search'}
<table id="BaseData" data-url="{:sysuri()}" data-target-search="form.form-search"></table>
</div>
</div>
{/block}
{block name='script'}
<script>
$(function () {
// 初始化表格组件
$('#BaseData').layTable({
even: true, height: 'full',
sort: {field: 'sort desc,id', type: 'asc'},
where: {type: '{$type|default=""}'},
cols: [[
{checkbox: true, fixed: true},
{field: 'sort', title: '排序权重', width: 100, align: 'center', sort: true, templet: '#SortInputTpl'},
// {field: 'type', title: '数据类型', minWidth: 140, align: 'center'},
{field: 'code', title: '数据编码', minWidth: 140, align: 'center'},
{field: 'name', title: '数据名称', minWidth: 140, align: 'center'},
{field: 'status', title: '数据状态', minWidth: 110, align: 'center', templet: '#StatusSwitchTpl'},
{field: 'create_at', title: '创建时间', minWidth: 170, align: 'center', sort: true},
{toolbar: '#toolbar', align: 'center', minWidth: 150, title: '数据操作', fixed: 'right'},
]]
});
// 数据状态切换操作
layui.form.on('switch(StatusSwitch)', function (obj) {
$.form.load("{:url('state')}", {id: obj.value, status: obj.elem.checked > 0 ? 1 : 0}, 'post', function (ret) {
if (ret.code < 1) $.msg.error(ret.info, 3, function () {
$('#BaseData').trigger('reload'); // 操作异常时重载数据
});
return false;
}, false);
});
});
</script>
<!-- 列表排序权重模板 -->
<script type="text/html" id="SortInputTpl">
<input min="0" type="number" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
</script>
<!-- 数据状态切换模板 -->
<script type="text/html" id="StatusSwitchTpl">
<!--{if auth("state")}-->
<input type="checkbox" value="{{d.id}}" lay-skin="switch" lay-text="已激活|已禁用" lay-filter="StatusSwitch" {{d.status>0?'checked':''}}>
<!--{else}-->
{{d.status ? '<b class="color-green">已启用</b>' : '<b class="color-red">已禁用</b>'}}
<!--{/if}-->
</script>
<!-- 数据操作工具条模板 -->
<script type="text/html" id="toolbar">
<!--{if auth('edit')}-->
<a class="layui-btn layui-btn-primary layui-btn-sm" data-title="编辑数据" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
<!--{/if}-->
<!--{if auth("remove")}-->
<a class="layui-btn layui-btn-danger layui-btn-sm" data-confirm="确定要删除数据吗?" data-action="{:url('remove')}" data-value="id#{{d.id}}">删 除</a>
<!--{/if}-->
</script>
{/block}

View File

@ -1,46 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">数据编码</label>
<div class="layui-input-inline">
<input name="code" value="{$get.code|default=''}" placeholder="请输入数据编码" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">数据名称</label>
<div class="layui-input-inline">
<input name="name" value="{$get.name|default=''}" placeholder="请输入数据名称" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">使用状态</label>
<div class="layui-input-inline">
<select class="layui-select" name="status">
<option value=''>-- 状态 --</option>
{foreach ['已禁用的权限','已激活的权限'] as $k=>$v}
{if input('get.status') eq $k.""}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
<script>form.render()</script>
</fieldset>

View File

@ -1,149 +0,0 @@
{extend name="main"}
{block name="button"}
<!--{if isset($isSuper) and $isSuper}-->
<a class="layui-btn layui-btn-sm layui-btn-primary" data-load="{:url('admin/api.runtime/config')}">清理无效配置</a>
<!--{/if}-->
<!--{if auth('system')}-->
<a class="layui-btn layui-btn-sm layui-btn-primary" data-modal="{:url('system')}">修改系统参数</a>
<!--{/if}-->
{/block}
{block name="content"}
<!--{notempty name='isSuper'}-->
<div class="layui-card padding-20 shadow">
<div class="layui-card-header notselect">
<b>运行模式</b><span class="color-desc font-s12 padding-left-5">Run Mode</span>
</div>
<div class="layui-card-body">
<div class="layui-btn-group shadow-mini nowrap">
<!--{if $app->isDebug()}-->
<a class="layui-btn layui-btn-sm layui-btn-active">以开发模式运行</a>
<a class="layui-btn layui-btn-sm layui-btn-primary" data-confirm="确定要切换到生产模式运行吗?" data-load="{:url('admin/api.runtime/debug')}?state=1">以生产模式运行</a>
<!--{else}-->
<a class="layui-btn layui-btn-sm layui-btn-primary" data-confirm="确定要切换到开发模式运行吗?" data-load="{:url('admin/api.runtime/debug')}?state=0">以开发模式运行</a>
<a class="layui-btn layui-btn-sm layui-btn-active">以生产模式运行</a>
<!--{/if}-->
</div>
<div class="margin-top-20">
<p><b>开发模式</b>:开发人员或在功能调试时使用,系统异常时会显示详细的错误信息,同时还会记录操作日志及数据库 SQL 语句信息。</p>
<p><b>生产模式</b>:项目正式部署上线后使用,系统异常时统一显示 “{:config('app.error_message')}”,只记录重要的异常日志信息,强烈推荐上线后使用此模式。</p>
</div>
</div>
</div>
<!--{/notempty}-->
<div class="layui-card padding-20 shadow">
<div class="layui-card-header notselect">
<b>存储引擎</b><span class="color-desc font-s12 padding-left-5">Storage Engine</span>
</div>
<div class="layui-card-body layui-clear">
<div class="layui-btn-group shadow-mini nowrap">
{foreach ['local' => '本地服务器存储','qiniu' => '七牛云对象存储','alioss' => '阿里云OSS存储','txcos' => '腾讯云COS存储'] as $k => $v} {if sysconf('storage.type') eq $k}
{if auth('storage')}<a data-title="配置{$v}" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{/if}
{else}
{if auth('storage')}<a data-title="配置{$v}" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{/if}
{/if}{/foreach}
</div>
<div class="margin-top-20 nowrap full-width pull-left">
<p><b>本地服务器存储</b>:文件直接上传到本地服务器的 `static/upload` 目录,不支持大文件上传,占用服务器磁盘空间,访问时消耗服务器带宽流量。</p>
<p><b>七牛云对象存储</b>:文件直接上传到七牛云存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
<p><b>阿里云OSS存储</b>:文件直接上传到阿里云 OSS 存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
<p><b>腾讯云COS存储</b>:文件直接上传到腾讯云 COS 存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
</div>
</div>
</div>
<div class="layui-card padding-20 shadow">
<div class="layui-card-header notselect">
<b>系统参数</b><span class="color-desc font-s12 padding-left-5">System Parameter</span>
</div>
<div class="layui-card-body">
<div class="layui-form-item">
<div class="help-label"><b>网站名称</b>Website</div>
<label class="relative block">
<input readonly value="{:sysconf('site_name')}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('site_name')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">网站名称及网站图标,将显示在浏览器的标签上。</div>
</div>
<div class="layui-form-item">
<div class="help-label"><b>管理程序名称</b>Name</div>
<label class="relative block">
<input readonly value="{:sysconf('app_name')}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('app_name')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">管理程序名称,将显示在后台左上角标题。</div>
</div>
<div class="layui-form-item">
<div class="help-label"><b>管理程序版本</b>Version</div>
<label class="relative block">
<input readonly value="{:sysconf('app_version')}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('app_version')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">管理程序版本,将显示在后台左上角标题。</div>
</div>
<div class="layui-form-item">
<div class="help-label"><b>公网备案号</b>Baian</div>
<label class="relative block">
<input readonly value="{:sysconf('beian')?:'-'}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('beian')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<p class="help-block">公网备案号,可以在 <a target="_blank" href="https://beian.miit.gov.cn">备案管理中心</a> 查询获取,将在登录页面下面显示。</p>
</div>
<div class="layui-form-item">
<div class="help-label"><b>网站备案号</b>Miitbeian</div>
<label class="relative block">
<input readonly value="{:sysconf('miitbeian')?:'-'}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('miitbeian')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">网站备案号,可以在 <a target="_blank" href="https://beian.miit.gov.cn">备案管理中心</a> 查询获取,将显示在登录页面下面。</div>
</div>
<div class="layui-form-item">
<div class="help-label"><b>网站版权信息</b>Copyright</div>
<label class="relative block">
<input readonly value="{:sysconf('site_copy')}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('site_copy')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">网站版权信息,在后台登录页面显示版本信息并链接到备案到信息备案管理系统。</div>
</div>
</div>
</div>
<div class="layui-card padding-20 shadow">
<div class="layui-card-header notselect">
<b>系统信息</b><span class="color-desc font-s12 padding-left-5">System Information</span>
</div>
<div class="layui-card-body">
<table class="layui-table" lay-even>
<tbody>
<tr>
<th class="nowrap text-center">核心框架</th>
<td><a target="_blank" href="https://www.thinkphp.cn">ThinkPHP Version {$app->version()}</a></td>
</tr>
<tr>
<th class="nowrap text-center">管理程序</th>
<td><a target="_blank" href="https://thinkadmin.top">ThinkAdmin Version {$version|default='6.0.0'}</a></td>
</tr>
<tr>
<th class="nowrap text-center">服务器信息</th>
<td>{:php_uname()}</td>
</tr>
<tr>
<th class="nowrap text-center">服务器软件</th>
<td>{$request->server('SERVER_SOFTWARE',php_sapi_name())}</td>
</tr>
<tr>
<th class="nowrap text-center">PHP 版本</th>
<td>PHP Version {$Think.const.PHP_VERSION}</td>
</tr>
<tr>
<th class="nowrap text-center">MySQL 版本</th>
<td>MySQL Version {$app->db->query('SELECT VERSION()')[0]['VERSION()']}</td>
</tr>
</tbody>
</table>
</div>
</div>
{/block}

View File

@ -1,46 +0,0 @@
<div class="layui-form-item">
<label class="layui-form-label label-required">
<span class="color-green font-w7">命名方式</span><br><span class="nowrap color-desc">NameType</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.name_type')}{php}sysconf('storage.name_type','xmd5');{/php}{/if}
{foreach ['xmd5'=>'文件哈希值','date'=>'日期+随机'] as $k=>$v}
<label class="think-radio notselect">
{if sysconf('storage.name_type') eq $k}
<input checked type="radio" name="storage.name_type" value="{$k}" lay-ignore> {$v}
{else}
<input type="radio" name="storage.name_type" value="{$k}" lay-ignore> {$v}
{/if}
</label>
{/foreach}
<p class="help-block">类型为“文件哈希”时可以实现文件秒传功能,同一个文件只需上传一次节省存储空间,推荐使用。</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label label-required">
<span class="color-green font-w7">链接类型</span><br><span class="nowrap color-desc">LinkType</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.link_type')}{php}sysconf('storage.link_type','none');{/php}{/if}
{foreach ['none'=>'简洁链接','full'=>'完整链接','none+compress'=>'简洁并压缩图片','full+compress'=>'完整并压缩图片'] as $k=>$v}
<label class="think-radio notselect">
{if sysconf('storage.link_type') eq $k}
<input checked type="radio" name="storage.link_type" value="{$k}" lay-ignore> {$v}
{else}
<input type="radio" name="storage.link_type" value="{$k}" lay-ignore> {$v}
{/if}
</label>
{/foreach}
<p class="help-block">类型为“简洁链接”时链接将只返回 hash 地址,而“完整链接”将携带参数保留文件名,图片压缩功能云平台会单独收费。</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.allow_exts">
<span class="color-green font-w7">允许类型</span><br><span class="nowrap color-desc">AllowExts</span>
</label>
<div class="layui-input-block">
<input id="storage.allow_exts" type="text" name="storage.allow_exts" required value="{:sysconf('storage.allow_exts')}" placeholder="请输入系统文件上传后缀" class="layui-input">
<p class="help-block">设置系统允许上传文件的后缀多个以英文逗号隔开如png,jpg,rar,doc未设置允许上传的后缀</p>
</div>
</div>

View File

@ -1,98 +0,0 @@
<form onsubmit="return false" data-auto="true" action="{:sysuri()}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body padding-top-20">
<div class="color-text margin-left-40 margin-bottom-20 layui-code text-center layui-bg-gray" style="border-left-width:1px">
<p class="margin-bottom-5 font-w7">文件将上传到阿里云 OSS 存储,需要配置 OSS 公开访问及跨域策略</p>
<p>需要配置跨域访问 CORS 规则,设置:来源 Origin 为 *,允许 Methods 为 POST允许 Headers 为 *</p>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<span class="color-green font-w7">访问协议</span><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.alioss_http_protocol')}{php}sysconf('storage.alioss_http_protocol','http');{/php}{/if}
{foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
<label class="think-radio">
{if sysconf('storage.alioss_http_protocol') eq $protocol}
<input checked type="radio" name="storage.alioss_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{else}
<input type="radio" name="storage.alioss_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{/if}
</label>
{/foreach}
<p class="help-block">阿里云OSS存储访问协议其中 HTTPS 需要配置证书才能使用AUTO 为相对协议)</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">
<span class="color-green font-w7">存储区域</span><br><span class="nowrap color-desc label-required">Region</span>
</label>
<div class="layui-input-block">
<select class="layui-select" name="storage.alioss_point" lay-search>
{foreach $points as $point => $title}
{if sysconf('storage.alioss_point') eq $point}
<option selected value="{$point}">{$title} {$point} </option>
{else}
<option value="{$point}">{$title} {$point} </option>
{/if}{/foreach}
</select>
<p class="help-block">阿里云OSS存储空间所在区域需要严格对应储存所在区域才能上传文件</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.alioss_bucket">
<span class="color-green font-w7">空间名称</span><br><span class="nowrap color-desc">Bucket</span>
</label>
<div class="layui-input-block">
<input id="storage.alioss_bucket" type="text" name="storage.alioss_bucket" required value="{:sysconf('storage.alioss_bucket')}" placeholder="请输入阿里云OSS存储 Bucket (空间名称)" class="layui-input">
<p class="help-block">填写阿里云OSS存储空间名称think-admin-oss需要是全区唯一的值不存在时会自动创建</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.alioss_http_domain">
<span class="color-green font-w7">访问域名</span><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.alioss_http_domain" type="text" name="storage.alioss_http_domain" required value="{:sysconf('storage.alioss_http_domain')}" placeholder="请输入阿里云OSS存储 Domain (访问域名)" class="layui-input">
<p class="help-block">填写阿里云OSS存储外部访问域名static.thinkadmin.top</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.alioss_access_key">
<span class="color-green font-w7">访问密钥</span><br><span class="nowrap color-desc">AccessKey</span>
</label>
<div class="layui-input-block">
<input id="storage.alioss_access_key" type="text" name="storage.alioss_access_key" required value="{:sysconf('storage.alioss_access_key')}" placeholder="请输入阿里云OSS存储 AccessKey (访问密钥)" class="layui-input">
<p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到访问密钥</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.alioss_secret_key">
<span class="color-green font-w7">安全密钥</span><br><span class="nowrap color-desc">SecretKey</span>
</label>
<div class="layui-input-block">
<input id="storage.alioss_secret_key" type="text" name="storage.alioss_secret_key" required value="{:sysconf('storage.alioss_secret_key')}" maxlength="43" placeholder="请输入阿里云OSS存储 SecretKey (安全密钥)" class="layui-input">
<p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到安全密钥</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="alioss">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
<script>form.render()</script>
</div>
</form>

View File

@ -1,49 +0,0 @@
<form onsubmit="return false" data-auto="true" action="{:sysuri()}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body padding-top-20">
<div class="color-text margin-left-40 margin-bottom-20 layui-code text-center layui-bg-gray" style="border-left-width:1px">
<p class="margin-bottom-5 font-w7">文件将存储在本地服务器,默认保存在 public/upload 目录,文件以 HASH 命名。</p>
<p>文件存储的目录需要有读写权限,有足够的存储空间。<span class="color-red">特别注意,本地存储暂不支持图片压缩!</span></p>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<span class="color-green font-w7">访问协议</span><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.local_http_protocol')}{php}sysconf('storage.local_http_protocol','http');{/php}{/if}
{foreach ['follow'=>'FOLLOW','http'=>'HTTP','https'=>'HTTPS','path'=>'PATH','auto'=>'AUTO'] as $protocol=>$remark}
<label class="think-radio">
{if sysconf('storage.local_http_protocol') eq $protocol}
<input checked type="radio" name="storage.local_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{else}
<input type="radio" name="storage.local_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{/if}
</label>
{/foreach}
<p class="help-block">本地存储访问协议,其中 HTTPS 需要配置证书才能使用( FOLLOW 跟随系统PATH 文件路径AUTO 相对协议 </p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.local_http_domain">
<span class="color-green font-w7">访问域名</span><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.local_http_domain" type="text" name="storage.local_http_domain" value="{:sysconf('storage.local_http_domain')}" placeholder="请输入上传后的访问域名 (非必填项)" class="layui-input">
<p class="help-block">填写上传后的访问域名不指定时根据当前访问地址自动计算static.thinkadmin.top</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="local">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</div>
</form>

View File

@ -1,96 +0,0 @@
<form onsubmit="return false" data-auto="true" action="{:sysuri()}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body padding-top-20">
<div class="color-text margin-left-40 margin-bottom-20 layui-code text-center layui-bg-gray" style="border-left-width:1px">
<p class="margin-bottom-5 font-w7">文件将上传到七牛云存储,对象存储需要配置为公开访问的 Bucket 空间</p>
完成实名认证后可获得 10G 免费存储空间哦!<a target="_blank" href="https://portal.qiniu.com/signup?code=1hefnmobzees2">我要免费申请</a>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<span class="color-green font-w7">访问协议</span><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.qiniu_http_protocol')}{php}sysconf('storage.qiniu_http_protocol','http');{/php}{/if}
{foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
<label class="think-radio">
{if sysconf('storage.qiniu_http_protocol') eq $protocol}
<input checked type="radio" name="storage.qiniu_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{else}
<input type="radio" name="storage.qiniu_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{/if}
</label>
{/foreach}
<p class="help-block">七牛云存储访问协议,其中 HTTPS 需要配置证书才能使用( AUTO 为相对协议 </p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">
<span class="color-green font-w7">存储区域</span><br><span class="nowrap color-desc label-required">Region</span>
</label>
<div class="layui-input-block">
{foreach ['华东','华北','华南','北美'] as $area}
<label class="think-radio">
{if sysconf('storage.qiniu_region') eq $area}
<input checked type="radio" name="storage.qiniu_region" value="{$area}" lay-ignore> {$area}
{else}
<input type="radio" name="storage.qiniu_region" value="{$area}" lay-ignore> {$area}
{/if}
</label>
{/foreach}
<p class="help-block">七牛云存储空间所在区域,需要严格对应储存所在区域才能上传文件</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.qiniu_bucket">
<span class="color-green font-w7">空间名称</span><br><span class="nowrap color-desc">Bucket</span>
</label>
<div class="layui-input-block">
<input id="storage.qiniu_bucket" type="text" name="storage.qiniu_bucket" required value="{:sysconf('storage.qiniu_bucket')}" placeholder="请输入七牛云存储 Bucket (空间名称)" class="layui-input">
<p class="help-block">填写七牛云存储空间名称static</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.qiniu_http_domain">
<span class="color-green font-w7">访问域名</span><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.qiniu_http_domain" type="text" name="storage.qiniu_http_domain" required value="{:sysconf('storage.qiniu_http_domain')}" placeholder="请输入七牛云存储 Domain (访问域名)" class="layui-input">
<p class="help-block">填写七牛云存储访问域名static.thinkadmin.top</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.qiniu_access_key">
<span class="color-green font-w7">访问密钥</span><br><span class="nowrap color-desc">AccessKey</span>
</label>
<div class="layui-input-block">
<input id="storage.qiniu_access_key" type="text" name="storage.qiniu_access_key" required value="{:sysconf('storage.qiniu_access_key')}" placeholder="请输入七牛云授权 AccessKey (访问密钥)" class="layui-input">
<p class="help-block">可以在 [ 七牛云 > 个人中心 ] 设置并获取到访问密钥</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.qiniu_secret_key">
<span class="color-green font-w7">安全密钥</span><br><span class="nowrap color-desc">SecretKey</span>
</label>
<div class="layui-input-block">
<input id="storage.qiniu_secret_key" type="text" name="storage.qiniu_secret_key" required value="{:sysconf('storage.qiniu_secret_key')}" maxlength="43" placeholder="请输入七牛云授权 SecretKey (安全密钥)" class="layui-input">
<p class="help-block">可以在 [ 七牛云 > 个人中心 ] 设置并获取到安全密钥</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="qiniu">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</div>
</form>

View File

@ -1,98 +0,0 @@
<form onsubmit="return false" data-auto="true" action="{:sysuri()}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body padding-top-20">
<div class="color-text margin-left-40 margin-bottom-20 layui-code text-center layui-bg-gray" style="border-left-width:1px">
<p class="margin-bottom-5 font-w7">文件将上传到 <a target="_blank" href="https://curl.qcloud.com/4t0Mbw2K">腾讯云</a> COS 存储,需要配置 COS 公有读私有写访问权限及跨域策略</p>
<p>需要配置跨域访问 CORS 规则,设置:来源 Origin 为 *,允许 Methods 为 POST允许 Headers 为 *</p>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<span class="color-green font-w7">访问协议</span><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.txcos_http_protocol')}{php}sysconf('storage.txcos_http_protocol','http');{/php}{/if}
{foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
<label class="think-radio">
{if sysconf('storage.txcos_http_protocol') eq $protocol}
<input checked type="radio" name="storage.txcos_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{else}
<input type="radio" name="storage.txcos_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{/if}
</label>
{/foreach}
<p class="help-block">腾讯云COS存储访问协议其中 HTTPS 需要配置证书才能使用( AUTO 为相对协议 </p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">
<span class="color-green font-w7">存储区域</span><br><span class="nowrap color-desc label-required">Region</span>
</label>
<div class="layui-input-block">
<select class="layui-select" name="storage.txcos_point" lay-search>
{foreach $points as $point => $title}
{if sysconf('storage.txcos_point') eq $point}
<option selected value="{$point}">{$title} {$point} </option>
{else}
<option value="{$point}">{$title} {$point} </option>
{/if}{/foreach}
</select>
<p class="help-block">腾讯云COS存储空间所在区域需要严格对应储存所在区域才能上传文件</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.txcos_bucket">
<span class="color-green font-w7">空间名称</span><br><span class="nowrap color-desc">Bucket</span>
</label>
<div class="layui-input-block">
<input id="storage.txcos_bucket" type="text" name="storage.txcos_bucket" required value="{:sysconf('storage.txcos_bucket')}" placeholder="请输入腾讯云COS存储 Bucket" class="layui-input">
<p class="help-block">填写腾讯云COS存储空间名称thinkadmin-1251143395</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.txcos_http_domain">
<span class="color-green font-w7">访问域名</span><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.txcos_http_domain" type="text" name="storage.txcos_http_domain" required value="{:sysconf('storage.txcos_http_domain')}" placeholder="请输入腾讯云COS存储 Domain" class="layui-input">
<p class="help-block">填写腾讯云COS存储外部访问域名static.thinkadmin.top</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.txcos_access_key">
<span class="color-green font-w7">访问密钥</span><br><span class="nowrap color-desc">AccessKey</span>
</label>
<div class="layui-input-block">
<input id="storage.txcos_access_key" type="text" name="storage.txcos_access_key" required value="{:sysconf('storage.txcos_access_key')}" placeholder="请输入腾讯云COS存储 AccessKey" class="layui-input">
<p class="help-block">可以在 [ 腾讯云 > 个人中心 ] 设置并获取到访问密钥</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.txcos_secret_key">
<span class="color-green font-w7">安全密钥</span><br><span class="nowrap color-desc">SecretKey</span>
</label>
<div class="layui-input-block">
<input id="storage.txcos_secret_key" type="text" name="storage.txcos_secret_key" required value="{:sysconf('storage.txcos_secret_key')}" maxlength="43" placeholder="请输入腾讯云COS存储 SecretKey" class="layui-input">
<p class="help-block">可以在 [ 腾讯云 > 个人中心 ] 设置并获取到安全密钥</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="txcos">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
<script>form.render()</script>
</div>
</form>

View File

@ -1,79 +0,0 @@
<form onsubmit="return false" data-auto="true" action="{:sysuri()}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body padding-left-40">
<div class="layui-form-item margin-bottom-5">
<div class="help-label"><b>登录界面背景</b>BackImage</div>
<input type="hidden" value="{:sysconf('login_image')}" name="login_image">
<script>$('[name="login_image"]').uploadMultipleImage()</script>
</div>
<div class="layui-form-item">
<div class="help-label label-required-prev"><b>后台登录入口</b>LoginEntry</div>
<label class="layui-input relative block label-required-null">
<span>{:sysuri('@',[],false,true)}</span>
<input autofocus required pattern="[a-zA-Z_][a-zA-Z0-9_]*" placeholder="请输入后台登录入口" class="layui-input inline-block padding-0 border-0" style="width:auto;background:none" value="{:substr(sysuri('admin/index/index',[],false), strlen(sysuri('@')))}" name="xpath">
</label>
<span class="help-block">名称由英文字母开头且不能存在相同名称的应用,设置之后原地址不能继续访问!</span>
</div>
<div class="layui-form-item">
<div class="help-label label-required-prev"><b>浏览器小图标</b>Icon</div>
<label class="relative block label-required-null">
<input class="layui-input" required pattern="^(http|/)" placeholder="请上传浏览器图标" value="{:sysconf('site_icon')}" name="site_icon">
<a class="input-right-icon layui-icon layui-icon-upload-drag" data-file="btn" data-type="ico,png" data-field="site_icon"></a>
</label>
<span class="help-block">建议上传 <span class="color-blue">128x128</span> | <span class="color-blue">256x256</span> 的 ico 或 png 图片,可以通过 <a href="https://www.favicon-icon-generator.com" target="_blank">ICON </a>在线制作 ico 后缀文件!</span>
</div>
<div class="layui-row layui-col-space15">
<div class="layui-col-xs4 padding-bottom-0">
<label class="layui-form-item relative block">
<span class="help-label"><b>网站名称</b>SiteName</span>
<input name="site_name" required placeholder="请输入网站名称" value="{:sysconf('site_name')}" class="layui-input">
<span class="help-block">网站名称将显示在浏览器的标签上!</span>
</label>
</div>
<div class="layui-col-xs4 padding-bottom-0">
<label class="layui-form-item relative block">
<span class="help-label"><b>后台程序名称</b>AppName</span>
<input name="app_name" required placeholder="请输入程序名称" value="{:sysconf('app_name')}" class="layui-input">
<span class="help-block">管理程序名称显示在后台左上标题处!</span>
</label>
</div>
<div class="layui-col-xs4 padding-bottom-0">
<label class="layui-form-item relative block">
<span class="help-label"><b>后台程序版本</b>AppVersion</span>
<input name="app_version" placeholder="请输入程序版本" value="{:sysconf('app_version')}" class="layui-input">
<span class="help-block">管理程序版本显示在后台左上标题处!</span>
</label>
</div>
<div class="layui-col-xs4 padding-bottom-0">
<label class="relative block">
<span class="help-label"><b>公网安备号</b>Baian</span>
<input name="beian" placeholder="请输入公网安备号" value="{:sysconf('beian')}" class="layui-input">
</label>
</div>
<div class="layui-col-xs4 padding-bottom-0">
<label class="relative block">
<span class="help-label"><b>网站备案号</b>Miitbeian</span>
<input name="miitbeian" placeholder="请输入网站备案号" value="{:sysconf('miitbeian')}" class="layui-input">
</label>
</div>
<div class="layui-col-xs4 padding-bottom-0">
<label class="relative block">
<span class="help-label"><b>网站版权信息</b>Copyright</span>
<input name="site_copy" required placeholder="请输入版权信息" value="{:sysconf('site_copy')}" class="layui-input">
</label>
</div>
<div class="layui-col-xs12 help-block padding-top-0">
网站备案号和公安备案号可以在<a target="_blank" href="https://beian.miit.gov.cn">备案管理中心</a>查询并获取,网站上线时必需配置备案号,备案号会链接到信息备案管理系统!
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="layui-form-item text-center">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</form>

View File

@ -1,568 +0,0 @@
<?php
if (!function_exists('parse_padding')) {
function parse_padding($source)
{
$length = strlen(strval(count($source['source']) + $source['first']));
return 40 + ($length - 1) * 8;
}
}
if (!function_exists('parse_class')) {
function parse_class($name)
{
$names = explode('\\', $name);
return '<abbr title="' . $name . '">' . end($names) . '</abbr>';
}
}
if (!function_exists('parse_file')) {
function parse_file($file, $line)
{
return '<a class="toggle" title="' . "{$file} line {$line}" . '">' . basename($file) . " line {$line}" . '</a>';
}
}
if (!function_exists('parse_args')) {
function parse_args($args)
{
$result = [];
foreach ($args as $key => $item) {
switch (true) {
case is_object($item):
$value = sprintf('<em>object</em>(%s)', parse_class(get_class($item)));
break;
case is_array($item):
if (count($item) > 3) {
$value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3)));
} else {
$value = sprintf('[%s]', parse_args($item));
}
break;
case is_string($item):
if (strlen($item) > 20) {
$value = sprintf(
'\'<a class="toggle" title="%s">%s...</a>\'',
htmlentities($item),
htmlentities(substr($item, 0, 20))
);
} else {
$value = sprintf("'%s'", htmlentities($item));
}
break;
case is_int($item):
case is_float($item):
$value = $item;
break;
case is_null($item):
$value = '<em>null</em>';
break;
case is_bool($item):
$value = '<em>' . ($item ? 'true' : 'false') . '</em>';
break;
case is_resource($item):
$value = '<em>resource</em>';
break;
default:
$value = htmlentities(str_replace("\n", '', var_export(strval($item), true)));
break;
}
$result[] = is_int($key) ? $value : "'{$key}' => {$value}";
}
return implode(', ', $result);
}
}
if (!function_exists('echo_value')) {
function echo_value($val)
{
if (is_array($val) || is_object($val)) {
echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));
} elseif (is_bool($val)) {
echo $val ? 'true' : 'false';
} elseif (is_scalar($val)) {
echo htmlentities($val);
} else {
echo 'Resource';
}
}
}
?>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>系统发生错误</title>
<meta name="robots" content="noindex,nofollow"/>
<style>
/* Base */
body {
color: #333;
font: 16px Verdana, "Helvetica Neue", helvetica, Arial, 'Microsoft YaHei', sans-serif;
margin: 0;
padding: 0 20px 20px;
}
h1 {
margin: 10px 0 0;
font-size: 28px;
font-weight: 500;
line-height: 32px;
}
h2 {
color: #4288ce;
font-weight: 400;
padding: 6px 0;
margin: 6px 0 0;
font-size: 18px;
border-bottom: 1px solid #eee;
}
h3 {
margin: 12px;
font-size: 16px;
font-weight: bold;
}
abbr {
cursor: help;
text-decoration: underline;
text-decoration-style: dotted;
}
a {
color: #868686;
cursor: pointer;
}
a:hover {
text-decoration: underline;
}
.line-error {
background: #f8cbcb;
}
.echo table {
width: 100%;
}
.echo pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f7f7f7;
border: 0;
border-radius: 3px;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.echo pre > pre {
padding: 0;
margin: 0;
}
/* Exception Info */
.exception {
margin-top: 20px;
}
.exception .message {
padding: 12px;
border: 1px solid #ddd;
border-bottom: 0 none;
line-height: 18px;
font-size: 16px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .code {
float: left;
text-align: center;
color: #fff;
margin-right: 12px;
padding: 16px;
border-radius: 4px;
background: #999;
}
.exception .source-code {
padding: 6px;
border: 1px solid #ddd;
background: #f9f9f9;
overflow-x: auto;
}
.exception .source-code pre {
margin: 0;
}
.exception .source-code pre ol {
margin: 0;
color: #4288ce;
display: inline-block;
min-width: 100%;
box-sizing: border-box;
font-size: 14px;
font-family: "Century Gothic", Consolas, "Liberation Mono", Courier, Verdana, serif;
padding-left: < ? php echo (isset($ source) & & ! empty($ source)) ? parse_padding($ source): 40;
? > px;
}
.exception .source-code pre li {
border-left: 1px solid #ddd;
height: 18px;
line-height: 18px;
}
.exception .source-code pre code {
color: #333;
height: 100%;
display: inline-block;
border-left: 1px solid #fff;
font-size: 14px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .trace {
padding: 6px;
border: 1px solid #ddd;
border-top: 0 none;
line-height: 16px;
font-size: 14px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .trace h2:hover {
text-decoration: underline;
cursor: pointer;
}
.exception .trace ol {
margin: 12px;
}
.exception .trace ol li {
padding: 2px 4px;
}
.exception div:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
/* Exception Variables */
.exception-var table {
width: 100%;
margin: 12px 0;
box-sizing: border-box;
table-layout: fixed;
word-wrap: break-word;
}
.exception-var table caption {
text-align: left;
font-size: 16px;
font-weight: bold;
padding: 6px 0;
}
.exception-var table caption small {
font-weight: 300;
display: inline-block;
margin-left: 10px;
color: #ccc;
}
.exception-var table tbody {
font-size: 13px;
font-family: Consolas, "Liberation Mono", Courier, "微软雅黑", serif;
}
.exception-var table td {
padding: 0 6px;
vertical-align: top;
word-break: break-all;
}
.exception-var table td:first-child {
width: 28%;
font-weight: bold;
white-space: nowrap;
}
.exception-var table td pre {
margin: 0;
}
/* Copyright Info */
.copyright {
margin-top: 24px;
padding: 12px 0;
border-top: 1px solid #eee;
}
/* SPAN elements with the classes below are added by prettyprint. */
pre.prettyprint .pln {
color: #000
}
/* plain text */
pre.prettyprint .str {
color: #080
}
/* string content */
pre.prettyprint .kwd {
color: #008
}
/* a keyword */
pre.prettyprint .com {
color: #800
}
/* a comment */
pre.prettyprint .typ {
color: #606
}
/* a type name */
pre.prettyprint .lit {
color: #066
}
/* a literal value */
/* punctuation, lisp open bracket, lisp close bracket */
pre.prettyprint .pun, pre.prettyprint .opn, pre.prettyprint .clo {
color: #660
}
pre.prettyprint .tag {
color: #008
}
/* a markup tag name */
pre.prettyprint .atn {
color: #606
}
/* a markup attribute name */
pre.prettyprint .atv {
color: #080
}
/* a markup attribute value */
pre.prettyprint .dec, pre.prettyprint .var {
color: #606
}
/* a declaration; a variable name */
pre.prettyprint .fun {
color: red
}
/* a function name */
</style>
</head>
<body>
<?php if (\think\facade\App::isDebug()) { ?>
<?php foreach ($traces as $index => $trace) { ?>
<div class="exception">
<div class="message">
<div class="info">
<div>
<h2><?php echo "#{$index} [{$trace['code']}]" . sprintf('%s in %s', parse_class($trace['name']), parse_file($trace['file'], $trace['line'])); ?></h2>
</div>
<div><h1><?php echo nl2br(htmlentities($trace['message'])); ?></h1></div>
</div>
</div>
<?php if (!empty($trace['source'])) { ?>
<div class="source-code">
<pre class="prettyprint lang-php"><ol start="<?php echo $trace['source']['first']; ?>"><?php foreach ((array)$trace['source']['source'] as $key => $value) { ?><li class="line-<?php echo " {$index}-" . ($key + $trace['source']['first']) . ($trace['line'] === $key + $trace['source']['first'] ? ' line-error' : ''); ?>"><code><?php echo htmlentities($value); ?></code></li><?php } ?></ol></pre>
</div>
<?php } ?>
<div class="trace">
<h2 data-expand="<?php echo 0 === $index ? '1' : '0'; ?>">Call Stack</h2>
<ol>
<li><?php echo sprintf('in %s', parse_file($trace['file'], $trace['line'])); ?></li>
<?php foreach ((array)$trace['trace'] as $value) { ?>
<li>
<?php
// Show Function
if ($value['function']) {
echo sprintf('at %s%s%s(%s)', isset($value['class']) ? parse_class($value['class']) : '', $value['type'] ?? '', $value['function'], isset($value['args']) ? parse_args($value['args']) : '');
}
// Show line
if (isset($value['file']) && isset($value['line'])) {
echo sprintf(' in %s', parse_file($value['file'], $value['line']));
}
?>
</li>
<?php } ?>
</ol>
</div>
</div>
<?php } ?>
<?php } else { ?>
<div class="exception">
<div class="info"><h1><?php echo htmlentities($message); ?></h1></div>
</div>
<?php } ?>
<?php if (!empty($datas)) { ?>
<div class="exception-var">
<h2>Exception Datas</h2>
<?php foreach ((array)$datas as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array)$value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
<?php } ?>
</table>
<?php } ?>
</div>
<?php } ?>
<?php if (!empty($tables)) { ?>
<div class="exception-var">
<h2>Environment Variables</h2>
<?php foreach ((array)$tables as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array)$value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
<?php } ?>
</table>
<?php } ?>
</div>
<?php } ?>
<?php if (\think\facade\App::isDebug()) { ?>
<script>
function $(selector, node) {
var elements;
node = node || document;
if (document.querySelectorAll) {
elements = node.querySelectorAll(selector);
} else {
switch (selector.substr(0, 1)) {
case '#':
elements = [node.getElementById(selector.substr(1))];
break;
case '.':
if (document.getElementsByClassName) {
elements = node.getElementsByClassName(selector.substr(1));
} else {
elements = get_elements_by_class(selector.substr(1), node);
}
break;
default:
elements = node.getElementsByTagName();
}
}
return elements;
function get_elements_by_class(search_class, node, tag) {
var elements = [], eles,
pattern = new RegExp('(^|\\s)' + search_class + '(\\s|$)');
node = node || document;
tag = tag || '*';
eles = node.getElementsByTagName(tag);
for (var i = 0; i < eles.length; i++) {
if (pattern.test(eles[i].className)) {
elements.push(eles[i])
}
}
return elements;
}
}
$.getScript = function (src, func) {
var script = document.createElement('script');
script.async = 'async';
script.src = src;
script.onload = func || function () {
};
$('head')[0].appendChild(script);
}
;(function () {
var files = $('.toggle');
var ol = $('ol', $('.prettyprint')[0]);
var li = $('li', ol[0]);
// 短路径和长路径变换
for (var i = 0; i < files.length; i++) {
files[i].ondblclick = function () {
var title = this.title;
this.title = this.innerHTML;
this.innerHTML = title;
}
}
(function () {
var expand = function (dom, expand) {
var ol = $('ol', dom.parentNode)[0];
expand = undefined === expand ? dom.attributes['data-expand'].value === '0' : undefined;
if (expand) {
dom.attributes['data-expand'].value = '1';
ol.style.display = 'none';
dom.innerText = 'Call Stack (展开)';
} else {
dom.attributes['data-expand'].value = '0';
ol.style.display = 'block';
dom.innerText = 'Call Stack (折叠)';
}
};
var traces = $('.trace');
for (var i = 0; i < traces.length; i++) {
var h2 = $('h2', traces[i])[0];
expand(h2);
h2.onclick = function () {
expand(this);
};
}
})();
$.getScript('//cdn.bootcss.com/prettify/r298/prettify.min.js', function () {
prettyPrint();
});
})();
</script>
<?php } ?>
</body>
</html>

View File

@ -1,31 +0,0 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=0.4">
<link rel="shortcut icon" href="{:sysconf('site_icon')}">
<link rel="stylesheet" href="__ROOT__/static/plugs/layui/css/layui.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/theme/css/iconfont.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/theme/css/console.css?at={:date('md')}">
{block name="style"}{/block}
<script>window.tapiRoot = '{:sysuri("admin/index/index",[],false)}'</script>
<script src="__ROOT__/static/plugs/jquery/pace.min.js"></script>
</head>
<body class="layui-layout-body">
{block name='body'}
<div class="layui-layout layui-layout-admin layui-layout-left-hide">
<div class="layui-body think-bg-white margin-0 padding-0" style="top:0">{block name='content'}{/block}</div>
</div>
{/block}
<script src="__ROOT__/static/plugs/layui/layui.js"></script>
<script src="__ROOT__/static/plugs/require/require.js"></script>
<script src="__ROOT__/static/admin.js"></script>
{block name='script'}{/block}
</body>
</html>

View File

@ -1,39 +0,0 @@
<div class="layui-side notselect">
<a class="layui-logo layui-elip" href="{:sysuri('@')}" title="{:sysconf('app_name')}">
{:sysconf('app_name')} {if sysconf('app_version')}<sup>{:sysconf('app_version')}</sup>{/if}
</a>
<a class="layui-logo-mini layui-elip" href="{:sysuri('@')}" title="{:sysconf('app_name')}">
<span class="headimg headimg-xs" data-lazy-src="{:sysconf('site_icon')}"></span>
</a>
<div class="layui-side-scroll">
{foreach $menus as $one}{notempty name='one.sub'}
<ul class="layui-nav layui-nav-tree layui-hide" data-menu-layout="m-{$one.id}">
{foreach $one.sub as $two}{empty name='two.sub'}
<li class="layui-nav-item">
<a data-target-tips="{$two.title}" data-menu-node="m-{$one.id}-{$two.id}" data-open="{$two.url}">
<span class='nav-icon {$two.icon|default="layui-icon layui-icon-senior"}'></span>
<span class="nav-text">{$two.title|default=''}</span>
</a>
</li>
{else}
<li class="layui-nav-item" data-submenu-layout='m-{$one.id}-{$two.id}'>
<a data-target-tips="{$two.title}" style="background:#393D49">
<span class='nav-icon layui-hide {$two.icon|default="layui-icon layui-icon-triangle-d"}'></span>
<span class="nav-text">{$two.title|default=''}</span>
</a>
<dl class="layui-nav-child">
{foreach $two.sub as $thr}
<dd>
<a data-target-tips="{$thr.title}" data-open="{$thr.url}" data-menu-node="m-{$one.id}-{$two.id}-{$thr.id}">
<span class='nav-icon {$thr.icon|default="layui-icon layui-icon-senior"}'></span>
<span class="nav-text">{$thr.title|default=''}</span>
</a>
</dd>
{/foreach}
</dl>
</li>
{/empty}{/foreach}
</ul>
{/notempty}{/foreach}
</div>
</div>

View File

@ -1,46 +0,0 @@
<div class="layui-header notselect">
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item" lay-unselect>
<a class="text-center" data-target-menu-type>
<i class="layui-icon layui-icon-spread-left"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect>
<a class="layui-logo-hide layui-elip" href="{:sysuri('@')}" title="{:sysconf('app_name')}">
<span class="headimg headimg-xs" data-lazy-src="{:sysconf('site_icon')}"></span>
</a>
</li>
{foreach $menus as $one}
<li class="layui-nav-item">
<a data-menu-node="m-{$one.id}" data-open="{$one.url}">
{notempty name='one.icon'}<span class='{$one.icon} padding-right-5'></span>{/notempty}
<span>{$one.title|default=''}</span>
</a>
</li>
{/foreach}
</ul>
<ul class="layui-nav layui-layout-right">
<li lay-unselect class="layui-nav-item"><a data-reload><i class="layui-icon layui-icon-refresh-3"></i></a></li>
{if session('user.username')}
<li class="layui-nav-item">
<dl class="layui-nav-child">
<dd lay-unselect><a data-modal="{:sysuri('admin/index/info',['id'=>session('user.id')])}"><i class="layui-icon layui-icon-set-fill"></i> 基本资料</a></dd>
<dd lay-unselect><a data-modal="{:sysuri('admin/index/pass',['id'=>session('user.id')])}"><i class="layui-icon layui-icon-component"></i> 安全设置</a></dd>
{if isset($isSuper) and $isSuper}
<dd lay-unselect><a data-load="{:sysuri('admin/api.runtime/push')}"><i class="layui-icon layui-icon-template-1"></i> 缓存加速</a></dd>
<dd lay-unselect><a data-load="{:sysuri('admin/api.runtime/clear')}"><i class="layui-icon layui-icon-fonts-clear"></i> 清理缓存</a></dd>
{/if}
<dd lay-unselect><a data-load="{:sysuri('admin/login/out')}" data-confirm="确定要退出登录吗?"><i class="layui-icon layui-icon-release"></i> 退出登录</a></dd>
</dl>
<a class="layui-elip">
<span class="headimg" data-lazy-src="{:htmlentities(session('user.headimg'))}"></span>
<span>{:htmlentities(session('user.nickname')?:session('user.username'))}</span>
</a>
</li>
{else}
<li class="layui-nav-item">
<a data-href="{:sysuri('admin/login/index')}"><i class="layui-icon layui-icon-username"></i> 立即登录</a>
</li>
{/if}
</ul>
</div>

View File

@ -1,61 +0,0 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=0.4">
<link rel="shortcut icon" href="{:sysconf('site_icon')}">
<link rel="stylesheet" href="__ROOT__/static/plugs/layui/css/layui.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/theme/css/iconfont.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/theme/css/console.css?at={:date('md')}">
{block name="style"}{/block}
<script>window.tapiRoot = '{:sysuri("admin/index/index",[],false)}'</script>
<script src="__ROOT__/static/plugs/jquery/pace.min.js"></script>
</head>
<body class="layui-layout-body">
{block name='body'}
<div class="layui-layout layui-layout-admin layui-layout-left-hide">
<!-- 顶部菜单 开始 -->
{include file='index/index-top'}
<!-- 顶部菜单 结束 -->
<!-- 左则菜单 开始 -->
{include file="index/index-left"}
<!-- 左则菜单 结束 -->
<!-- 主体内容 开始 -->
<div class="layui-body">
<div class="think-page-body">
{block name='content'}{/block}
</div>
<!-- 页面加载动画 -->
<div class="think-page-loader layui-hide">
<div class="loader"></div>
</div>
</div>
<!-- 主体内容 结束 -->
</div>
<!-- 加载动画 开始 -->
<div class="think-page-loader">
<div class="loader"></div>
</div>
<!-- 加载动画 结束 -->
{/block}
<script src="__ROOT__/static/plugs/layui/layui.js"></script>
<script src="__ROOT__/static/plugs/require/require.js"></script>
<script src="__ROOT__/static/admin.js"></script>
{block name='script'}{/block}
</body>
</html>

View File

@ -1,58 +0,0 @@
{extend name="index/index"}
{block name="body"}
<div class="login-container" data-supersized="{$backgrounds|default='__ROOT__/static/theme/img/login/bg1.jpg,__ROOT__/static/theme/img/login/bg2.jpg'}">
<div class="header notselect layui-hide-xs">
<a href="{:url('@')}" class="title">{:sysconf('app_name')}<span>{:sysconf('app_version')}</span></a>
{notempty name='developMode'}
<a class="pull-right layui-anim layui-anim-fadein" href='https://gitee.com/zoujingli/ThinkAdmin'>
<img src='https://gitee.com/zoujingli/ThinkAdmin/widgets/widget_1.svg' alt='Fork me on Gitee'>
</a>
{/notempty}
</div>
<form data-login-form onsubmit="return false" method="post" class="layui-anim layui-anim-upbit" autocomplete="off">
<h2 class="notselect">系统管理</h2>
<ul>
<li class="username">
<label class="label-required-null">
<i class="layui-icon layui-icon-username"></i>
<input class="layui-input" required pattern="^\S{4,}$" name="username" autofocus autocomplete="off" placeholder="登录账号" title="请输入登录账号">
</label>
</li>
<li class="password">
<label class="label-required-null">
<i class="layui-icon layui-icon-password"></i>
<input class="layui-input" required pattern="^\S{4,}$" name="password" maxlength="32" type="password" autocomplete="off" placeholder="登录密码" title="请输入登录密码">
</label>
</li>
<li class="verify layui-hide">
<label class="inline-block relative label-required-null">
<i class="layui-icon layui-icon-picture-fine"></i>
<input class="layui-input" required pattern="^\S{4,}$" name="verify" maxlength="4" autocomplete="off" placeholder="验证码" title="请输入验证码">
</label>
<label data-captcha="{:url('admin/login/captcha',[],false)}" data-field-verify="verify" data-field-uniqid="uniqid" data-captcha-type="{$captchaType}" data-captcha-token="{$captchaToken}"></label>
</li>
<li class="text-center padding-top-20">
<button type="submit" class="layui-btn layui-disabled full-width" data-form-loaded="立即登入">正在载入</button>
</li>
</ul>
</form>
<div class="footer notselect">
<p class="layui-hide-xs">推荐使用 <a target="_blank" href="https://www.google.cn/chrome">Google Chrome</a><a target="_blank" href="https://www.microsoft.com/zh-cn/edge#platform">Microsoft Edge</a> 浏览器访问</p>
{:sysconf('site_copy')}
{if sysconf('beian')}<span class="padding-5">|</span><a target="_blank" href="https://beian.miit.gov.cn/">{:sysconf('beian')}</a>{/if}
{if sysconf('miitbeian')}<span class="padding-5">|</span><a target="_blank" href="https://beian.miit.gov.cn/">{:sysconf('miitbeian')}</a>{/if}
</div>
</div>
{/block}
{block name='style'}
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<script>if (location.href.indexOf('#') > -1) location.replace(location.href.split('#')[0])</script>
<link rel="stylesheet" href="__ROOT__/static/theme/css/login.css">
{/block}
{block name='script'}
<script src="__ROOT__/static/login.js"></script>
<script src="__ROOT__/static/plugs/supersized/supersized.3.2.7.min.js"></script>
{/block}

View File

@ -1,17 +0,0 @@
<div class="layui-card">
{block name='style'}{/block}
{block name='header'}
{notempty name='title'}
<div class="layui-card-header notselect">
<span class="layui-icon layui-icon-next font-s10 color-desc margin-right-5"></span>{$title|default=''}
<div class="pull-right">{block name='button'}{/block}</div>
</div>
{/notempty}
{/block}
<div class="layui-card-body">
<div class="layui-card-html">
{block name='content'}{/block}
</div>
</div>
{block name='script'}{/block}
</div>

View File

@ -1,102 +0,0 @@
<form class="layui-form layui-card" action="{:sysuri()}" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body">
<div class="layui-form-item">
<label class="layui-form-label label-required-next">上级菜单</label>
<div class="layui-input-block">
<select name='pid' class='layui-select' lay-search>
{foreach $menus as $menu}{eq name='menu.id' value='$vo.pid|default=0'}
<option selected value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
{else}
<option value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
{/eq}{/foreach}
</select>
<p class="help-block"><b>必选</b>,请选择上级菜单或顶级菜单(目前最多支持三级菜单)</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单名称</label>
<div class="layui-input-block">
<input name="title" value='{$vo.title|default=""}' required placeholder="请输入菜单名称" class="layui-input">
<p class="help-block"><b>必选</b>请填写菜单名称系统管理建议字符不要太长一般4-6个汉字</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单链接</label>
<div class="layui-input-block">
<input onblur="this.value=this.value === ''?'#':this.value" name="url" required placeholder="请输入菜单链接" value="{$vo.url|default='#'}" class="layui-input">
<p class="help-block">
<b>必选</b>请填写链接地址或选择系统节点https://domain.com/admin/user/index.html 或 admin/user/index
<br>当填写链接地址时,以下面的“权限节点”来判断菜单自动隐藏或显示,注意未填写“权限节点”时将不会隐藏该菜单哦
</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">链接参数</label>
<div class="layui-input-block">
<input name="params" placeholder="请输入链接参数" value="{$vo.params|default=''}" class="layui-input">
<p class="help-block">可选设置菜单链接的GET访问参数name=1&age=3</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">权限节点</label>
<div class="layui-input-block">
<input name="node" placeholder="请输入权限节点" value="{$vo.node|default=''}" class="layui-input">
<p class="help-block">可选请填写系统权限节点admin/user/index未填写时默认解释"菜单链接"判断是否拥有访问权限;</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单图标</label>
<div class="layui-input-block">
<div class="layui-input-inline">
<input placeholder="请输入或选择图标" name="icon" value='{$vo.icon|default=""}' class="layui-input">
</div>
<span style="padding:0 12px;min-width:45px" class='layui-btn layui-btn-primary'>
<i style="font-size:1.2em;margin:0;float:none" class='{$vo.icon|default=""}'></i>
</span>
<button data-icon='icon' type='button' class='layui-btn layui-btn-primary'>选择图标</button>
<p class="help-block">可选,设置菜单选项前置图标,目前支持 layui 字体图标及 iconfont 定制字体图标。</p>
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>
{block name='script'}
<script>
layui.form.render();
require(['jquery.autocompleter'], function () {
$('[name="icon"]').on('change', function () {
$(this).parent().next().find('i').get(0).className = this.value
});
$('input[name=url]').autocompleter({
limit: 6, highlightMatches: true, template: '{{ label }} <span> {{ title }} </span>', callback: function (node) {
$('input[name=node]').val(node);
}, source: (function (subjects, data) {
for (var i in subjects) data.push({value: subjects[i].node, label: subjects[i].node, title: subjects[i].title});
return data;
})(JSON.parse('{$nodes|raw|json_encode}'), [])
});
$('input[name=node]').autocompleter({
limit: 5, highlightMatches: true, template: '{{ label }} <span> {{ title }} </span>', source: (function (subjects, data) {
for (var i in subjects) data.push({value: subjects[i].node, label: subjects[i].node, title: subjects[i].title});
return data;
})(JSON.parse('{$auths|raw|json_encode}'), [])
});
});
</script>
{/block}

View File

@ -1,102 +0,0 @@
{extend name='main'}
{block name="button"}
<!--{if $type eq 'index' and auth("add")}-->
<button data-modal='{:url("add")}' data-title="添加菜单" class='layui-btn layui-btn-sm layui-btn-primary'>添加菜单</button>
<!--{/if}-->
<!--{if $type eq 'index' and auth("state")}-->
<button data-action='{:url("state")}' data-csrf="{:systoken('state')}" data-rule="id#{key};status#0" class='layui-btn layui-btn-sm layui-btn-primary'>禁用菜单</button>
<!--{/if}-->
<!--{if $type eq 'recycle' and auth("state")}-->
<button data-action='{:url("state")}' data-csrf="{:systoken('state')}" data-rule="id#{key};status#1" class='layui-btn layui-btn-sm layui-btn-primary'>激活菜单</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="layui-tab layui-tab-card">
<ul class="layui-tab-title">
{foreach ['index'=>'系统菜单','recycle'=>'回 收 站'] as $k=>$v}
{if isset($type) and $type eq $k}
<li class="layui-this color-green" data-open="{:url('index')}?type={$k}">{$v}</li>
{else}
<li data-open="{:url('index')}?type={$k}">{$v}</li>
{/if}{/foreach}
</ul>
<div class="layui-tab-content">
{empty name='list'}
<div class="notdata">没有记录哦</div>
{else}
<table class="layui-table" lay-skin="line">
<thead>
<tr>
<th class='list-table-check-td think-checkbox'>
<label><input data-auto-none data-check-target='.list-check-box' type='checkbox'></label>
</th>
<th class='list-table-sort-td'>
<button type="button" data-reload class="layui-btn layui-btn-xs">刷 新</button>
</th>
<th class='text-center' style="width:30px"></th>
<th style="width:230px"></th>
<th class='layui-hide-xs' style="width:180px"></th>
<th colspan="2"></th>
</tr>
</thead>
<tbody>
{foreach $list as $key=>$vo}
<tr data-dbclick class="{if ($type eq 'index' and $vo.status eq 0)}layui-hide{/if}">
<td class='list-table-check-td think-checkbox'>
<label><input class="list-check-box" value='{$vo.ids}' type='checkbox'></label>
</td>
<td class='list-table-sort-td'>
<input data-action-blur="{:sysuri()}" data-value="id#{$vo.id};action#sort;sort#{value}" data-loading="false" value="{$vo.sort}" class="list-sort-input">
</td>
<td class='text-center'><i class="{$vo.icon} font-s18"></i></td>
<td class="nowrap"><span class="color-desc">{$vo.spl|raw}</span>{$vo.title}</td>
<td class='layui-hide-xs layui-elip'>{$vo.url}</td>
<td class='text-center nowrap'>{eq name='vo.status' value='0'}<span class="color-red">已禁用</span>{else}<span class="color-green">已激活</span>{/eq}</td>
<td class='text-center nowrap notselect'>
{if isset($type) and $type eq 'index'}
{if auth("add")}
<!--{if $vo.spt < 2}-->
<a class="layui-btn layui-btn-sm layui-btn-primary" data-title="添加子菜单" data-modal='{:url("add")}?pid={$vo.id}'>添 加</a>
<!--{else}-->
<a class="layui-btn layui-btn-sm layui-btn-disabled">添 加</a>
<!--{/if}-->
{/if}
<!--{if auth("edit")}-->
<a data-dbclick class="layui-btn layui-btn-sm" data-title="编辑菜单" data-modal='{:url("edit")}?id={$vo.id}'>编 辑</a>
<!--{/if}-->
<!--{if $vo.status eq 1 and auth("state")}-->
<a class="layui-btn layui-btn-warm layui-btn-sm" data-confirm="确定要禁用菜单吗?" data-action="{:url('state')}" data-value="id#{$vo.ids};status#0" data-csrf="{:systoken('state')}">禁 用</a>
<!--{/if}-->
{else}
<!--{if auth("state")}-->
<a class="layui-btn layui-btn-warm layui-btn-sm" data-confirm="确定要激活菜单吗?" data-action="{:url('state')}" data-value="id#{$vo.ids};status#1" data-csrf="{:systoken('state')}">激 活</a>
<!--{/if}-->
<!--{if auth("remove") and ($vo.spc<1 or $vo.status<1)}-->
<a class="layui-btn layui-btn-danger layui-btn-sm" data-confirm="确定要删除菜单吗?" data-action="{:url('remove')}" data-value="id#{$vo.ids}" data-csrf="{:systoken('remove')}">删 除</a>
<!--{/if}-->
<!--{if auth("remove") and $vo.spc>0 and $vo.status>0}-->
<a class="layui-btn layui-btn-disabled layui-btn-sm">删 除</a>
<!--{/if}-->
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{/empty}
</div>
</div>
{/block}

View File

@ -1,33 +0,0 @@
<form class="layui-form layui-card" action="{:sysuri()}" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body padding-left-40">
<div class="layui-textarea border-0 font-s14 layui-bg-gray padding-top-20 padding-left-20">
<div class="layui-row margin-bottom-15">
<div class="layui-col-xs6">模块名称:<b class="color-green">{$module.name}</b></div>
<div class="layui-col-xs6">开发作者:<b class="color-green">{$module.author}</b></div>
</div>
<div class="layui-row margin-bottom-15">
<div class="layui-col-xs6">最新版本:<b class="color-green">{$module.version}</b></div>
<div class="layui-col-xs6">{if isset($current.version)}已安装版本:<b class="color-green">{$current.version}</b>{/if}</div>
</div>
<div class="margin-bottom-15">模块描述:{$module.content}</div>
</div>
<ul class="layui-timeline margin-top-30 margin-bottom-30" style="max-height:400px;overflow:auto">
{foreach $module.change as $version=>$change}
<li class="layui-timeline-item">
{if isset($current.version) and $current.version eq $version}
<i class="layui-icon layui-timeline-axis">&#xe756;</i>
{else}
<i class="layui-icon layui-timeline-axis">&#xe63f;</i>
{/if}
<div class="layui-timeline-content layui-text">
<h3 class="layui-timeline-title">
版本号 {$version} <span class="margin-left-10 font-s13 color-desc">{$change.version|default=''}</span>
</h3>
{$change.content|default=''|raw}
</div>
</li>
{/foreach}
<li class="layui-timeline-item"></li>
</ul>
</div>
</form>

View File

@ -1,42 +0,0 @@
{extend name='main'}
{block name="content"}
<div class="think-box-shadow">
<table class="layui-table margin-top-15" lay-skin="line">
{notempty name='modules'}
<thead>
<tr>
<th class='text-left nowrap'>模块名称</th>
<th class='text-left nowrap'>模块描述</th>
<th class='text-left nowrap'>当前版本</th>
<th></th>
</tr>
</thead>
{/notempty}
<tbody>
{foreach $modules as $key=>$vo}
<tr>
<td class='text-left nowrap'>{$vo.name}</td>
<td class='text-left nowrap'>{$vo.content}</td>
<td class='text-left nowrap'>
<div class="inline-block pointer" data-title="查看模块版本" data-modal="{:url('change')}?name={$vo.name}">
{if isset($vo.local)} {$vo.local.version}
{if $vo.version > $vo.local.version}
<span class="color-red margin-left-5">{$vo.version}</span>
{else}
<span class="color-desc margin-left-5">{$vo.type_desc}</span>
{/if}
{else}<span class="color-desc margin-left-5">{$vo.type_desc}</span>{/if}
</div>
</td>
<td class="text-left">
{if $vo.type_code eq 1} <a class="layui-btn layui-btn-xs" data-action="{:url('install')}" data-value="name#{$vo.name}">安 装</a>{/if}
{if $vo.type_code eq 2} <a class="layui-btn layui-btn-xs" data-action="{:url('install')}" data-value="name#{$vo.name}">更 新</a>{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{empty name='modules'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
{/block}

View File

@ -1,60 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务编号</label>
<div class="layui-input-inline">
<input name="code" value="{$get.code|default=''}" placeholder="请输入任务编号" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务名称</label>
<div class="layui-input-inline">
<input name="title" value="{$get.title|default=''}" placeholder="请输入任务名称" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务指令</label>
<div class="layui-input-inline">
<input name="command" value="{$get.command|default=''}" placeholder="请输入任务指令" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务状态</label>
<div class="layui-input-inline">
<select name="status" class="layui-select">
{foreach [''=>'-- 全部状态 --','1'=>'待处理','2'=>'处理中','3'=>'处理完成','4'=>'处理失败'] as $k=>$v}
{if input('get.status') eq $k}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">计划时间</label>
<div class="layui-input-inline">
<input data-date-range name="exec_time" value="{$get.exec_time|default=''}" placeholder="请选择计划时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">执行时间</label>
<div class="layui-input-inline">
<input data-date-range name="enter_time" value="{$get.enter_time|default=''}" placeholder="请选择执行时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
</fieldset>
<script>form.render()</script>

View File

@ -1,46 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if auth("remove")}-->
<button data-action='{:url("remove")}' data-rule="id#{id}" data-table-id="OplogData" data-confirm="确定要删除选中的日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</button>
<!--{/if}-->
<!--{if auth("clear")}-->
<button data-load='{:url("clear")}' data-confirm="确定要清空所有日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>清空日志</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file='oplog/index_search'}
<table id="OplogData" data-url="{:sysuri()}" data-target-search="form.form-search"></table>
</div>
{/block}
{block name='script'}
<script>
$(function () {
$('#OplogData').layTable({
even: true, height: 'full',
sort: {field: 'id', type: 'desc'},
cols: [[
{checkbox: true},
{field: 'id', title: 'ID', width: 80, sort: true, align: 'center'},
{field: 'username', title: '操作账号', minWidth: 100, sort: true, align: 'center'},
{field: 'node', title: '操作节点', minWidth: 120},
{field: 'action', title: '操作行为', minWidth: 120},
{field: 'content', title: '操作描述', minWidth: 120},
{field: 'geoip', title: '访问地址', minWidth: 100},
{field: 'geoisp', title: '网络服务商', minWidth: 100},
{field: 'create_at', title: '操作时间', minWidth: 170, align: 'center', sort: true},
{toolbar: '#toolbar', title: '操作面板', align: 'center', fixed: 'right'}
]]
});
});
</script>
<script type="text/html" id="toolbar">
<!--{if auth('remove')}-->
<a data-action='{:url("remove")}' data-value="id#{{d.id}}" data-confirm="确认要删除这条记录吗?" class="layui-btn layui-btn-sm layui-btn-danger">删 除</a>
<!--{/if}-->
</script>
{/block}

View File

@ -1,74 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作账号</label>
<div class="layui-input-inline">
<select name='username' lay-search class="layui-select">
<option value=''>-- 全部账号 --</option>
{foreach $users as $user}{if $user eq input('get.username')}
<option selected value="{$user}">{$user}</option>
{else}
<option value="{$user}">{$user}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作节点</label>
<label class="layui-input-inline">
<input name="node" value="{$get.node|default=''}" placeholder="请输入操作内容" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作行为</label>
<div class="layui-input-inline">
<select name="action" lay-search class="layui-select">
<option value=''>-- 全部行为 --</option>
{foreach $actions as $action}{if $action eq input('get.action')}
<option selected value="{$action}">{$action}</option>
{else}
<option value="{$action}">{$action}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作描述</label>
<label class="layui-input-inline">
<input name="content" value="{$get.content|default=''}" placeholder="请输入操作内容" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">访问地址</label>
<label class="layui-input-inline">
<input name="geoip" value="{$get.geoip|default=''}" placeholder="请输入访问地址" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作时间</label>
<label class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择操作时间" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<button type="submit" class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
<button type="button" data-form-export="{:url('index')}?type={$type|default=''}" class="layui-btn layui-btn-primary">
<i class="layui-icon layui-icon-export"></i> 导 出
</button>
</div>
</form>
</fieldset>
<script>
window.form.render();
require(['excel'], function (excel) {
excel.bind(function (data) {
data.forEach(function (item, index) {
data[index] = [item.username, item.node, item.geoip, item.geoisp, item.action, item.content, item.create_at];
});
data.unshift(['操作账号', '访问节点', '访问IP地址', '访问地理区域', '访问操作', '操作内容', '操作时间']);
return data;
}, '操作日志');
});
</script>

View File

@ -1,150 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if isset($isSuper) and $isSuper}-->
<a class="layui-btn layui-btn-sm layui-btn-primary" data-queue="{:url('admin/api.plugs/optimize')}">优化数据库</a>
<!--{if $iswin}-->
<button data-load='{:url("admin/api.queue/start")}' class='layui-btn layui-btn-sm layui-btn-primary'>开启后台服务</button>
<button data-load='{:url("admin/api.queue/stop")}' class='layui-btn layui-btn-sm layui-btn-primary'>关闭后台服务</button>
<!--{/if}-->
<!--{/if}-->
<!--{if auth("clean")}-->
<button data-queue='{:url("clean")}' class='layui-btn layui-btn-sm layui-btn-primary'>定时清理数据</button>
<!--{/if}-->
<!--{if auth("remove")}-->
<button data-action='{:url("remove")}' data-rule="id#{id}" data-table-id="QueueData" data-confirm="确定批量删除记录吗?" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除任务</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="think-box-shadow">
<div class="layui-row layui-col-space20 portal-block-container notselect">
<div class="layui-col-sm6 layui-col-md6 layui-col-lg3">
<div class="portal-block-item nowrap" style="background:linear-gradient(-125deg,#57bdbf,#2f9de2)">
<div class="font-w7 font-s16">等待处理</div>
<div>{$total.pre|default=0}</div>
<div>待处理的任务数量</div>
</div>
<i class="portal-block-icon layui-icon layui-icon-star"></i>
</div>
<div class="layui-col-sm6 layui-col-md6 layui-col-lg3">
<div class="portal-block-item nowrap" style="background:linear-gradient(-125deg,#ff7d7d,#fb2c95)">
<div class="font-w7 font-s16">正在处理</div>
<div>{$total.dos|default=0}</div>
<div>处理中的任务数量</div>
</div>
<i class="portal-block-icon layui-icon layui-icon-log"></i>
</div>
<div class="layui-col-sm6 layui-col-md6 layui-col-lg3">
<div class="portal-block-item nowrap" style="background:linear-gradient(-113deg,#c543d8,#925cc3)">
<div class="font-w7 font-s16">处理完成</div>
<div>{$total.oks|default=0}</div>
<div>处理完成的任务数量</div>
</div>
<i class="portal-block-icon layui-icon layui-icon-release"></i>
</div>
<div class="layui-col-sm6 layui-col-md6 layui-col-lg3">
<div class="portal-block-item nowrap" style="background:linear-gradient(-141deg,#ecca1b,#f39526)">
<div class="font-w7 font-s16">处理失败</div>
<div>{$total.ers|default=0}</div>
<div>处理失败的任务数量</div>
</div>
<i class="portal-block-icon layui-icon layui-icon-engine"></i>
</div>
</div>
{include file='queue/index_search'}
<table id="QueueData" data-url="{:sysuri()}" data-target-search="form.form-search"></table>
</div>
{/block}
{block name='script'}
<script>
$(function () {
$('#QueueData').layTable({
even: true,
sort: {field: 'loops_time desc,code', type: 'desc'},
cols: [[
{checkbox: true, fixed: 'left'},
{field: 'code', title: '任务编号', width: 140, sort: true},
{field: 'title', title: '任务名称', minWidth: 100},
{field: 'command', title: '任务指令', minWidth: 100},
{
field: 'exec_time', title: '计划时间', minWidth: 245, templet: function (d) {
d.exec_time = d.exec_time || 0, d.loops_time = d.loops_time || 0;
if (d.loops_time > 0) {
return d.exec_time + ' ( 每 <b class="color-blue">' + d.loops_time + '</b> 秒 ) ';
} else {
return d.exec_time + ' <span class="color-desc">( 单次任务 )</span> ';
}
}
},
{
field: 'loops_time', title: '执行时间', minWidth: 175, templet: function (d) {
d.enter_time = d.enter_time || '', d.outer_time = d.outer_time || '0.0000';
if (d.enter_time.length > 12) {
return d.enter_time.substr(12) + '<span class="color-desc"> ( 耗时 ' + d.outer_time + ' )</span>';
} else {
return '<span class="color-desc">任务未执行</span>'
}
}
},
{field: 'attempts', title: '执行次数', minWidth: 95, align: 'center', sort: true, templet: "<div>{{d.attempts||0}}</div>"},
{field: 'exec_desc', title: '执行结果', minWidth: 180},
{field: 'create_at', title: '创建时间', align: 'center', minWidth: 170},
{toolbar: '#toolbar', title: '操作面板', align: 'center', width: 260, fixed: 'right',}
]]
});
});
</script>
<script type="text/html" id="toolbar">
{{# if(d.loops_time>0){ }}
<span class="layui-badge think-bg-blue"></span>
{{# }else{ }}
<span class="layui-badge think-bg-red"></span>
{{# } }}
{{# if(d.rscript===1){ }}
<span class="layui-badge layui-bg-green"></span>
{{# }else{ }}
<span class="layui-badge think-bg-violet"></span>
{{# } }}
{{# if(d.status===1){ }}
<span class="layui-badge layui-bg-black">等待处理</span>
<span class="layui-badge think-bg-gray"><i class="layui-icon font-s12">&#xe669;</i></span>
{{# }else if(d.status===2){ }}
<span class="layui-badge layui-bg-green">正在处理</span>
<!--{if auth('redo')}-->
<span class="layui-badge think-bg-gray"><i class="layui-icon font-s12">&#xe669;</i></span>
<!--{/if}-->
{{# }else if(d.status===3){ }}
<span class="layui-badge layui-bg-blue">处理完成</span>
<!--{if auth('redo')}-->
<a class="layui-badge layui-bg-green" data-confirm="确定要重置该任务吗?" data-queue="{:url('redo')}?code={{d.code}}">
<i class="layui-icon font-s12">&#xe669;</i>
</a>
<!--{/if}-->
{{# }else if(d.status===4){ }}
<span class="layui-badge layui-bg-red">处理失败</span>
<!--{if auth('redo')}-->
<a class="layui-badge layui-bg-green" data-confirm="确定要重置该任务吗?" data-queue="{:url('redo')}?code={{d.code}}">
<i class="layui-icon font-s12">&#xe669;</i>
</a>
<!--{/if}-->
{{# } }}
<!--{if auth('remove')}-->
<a class='layui-badge layui-bg-red' data-confirm="确定要删除该任务吗?" data-action='{:url("remove")}' data-value="id#{{d.id}}">
<i class="layui-icon font-s12">&#xe640;</i>
</a>
<!--{/if}-->
<a class='layui-badge layui-bg-orange margin-0' onclick="$.loadQueue('{{d.code}}',false,this)">
<i class="layui-icon font-s12">&#xe705;</i>
</a>
</script>
{/block}

View File

@ -1,80 +0,0 @@
<!--{if isset($isSuper) and $isSuper}-->
<fieldset class="margin-bottom-15">
<legend class="notselect">服务状态</legend>
<div class="layui-code border-0 margin-top-0">
<h4 class="color-desc notselect">后台服务主进程运行状态</h4>
<div data-queue-message>Checking task process running status ...</div>
<script>$('[data-queue-message]').load('{:sysuri("admin/api.queue/status")}')</script>
<h4 class="color-desc margin-top-10 notselect">配置定时任务来检查并启动进程(建议每分钟执行)</h4>
<div>{$command|default='--'}</div>
</div>
</fieldset>
<!--{/if}-->
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务编号</label>
<label class="layui-input-inline">
<input name="code" value="{$get.code|default=''}" placeholder="请输入任务编号" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务名称</label>
<label class="layui-input-inline">
<input name="title" value="{$get.title|default=''}" placeholder="请输入任务名称" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务指令</label>
<label class="layui-input-inline">
<input name="command" value="{$get.command|default=''}" placeholder="请输入任务指令" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务状态</label>
<label class="layui-input-inline">
<select name="status" class="layui-select">
<option value=''>-- 全部任务 --</option>
{foreach ['1'=>'等待处理','2'=>'正在处理','3'=>'处理完成','4'=>'处理失败'] as $k=>$v}
{if input('get.status') eq $k}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}{/foreach}
</select>
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">计划时间</label>
<label class="layui-input-inline">
<input data-date-range name="exec_time" value="{$get.exec_time|default=''}" placeholder="请选择计划时间" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">执行时间</label>
<label class="layui-input-inline">
<input data-date-range name="enter_time" value="{$get.enter_time|default=''}" placeholder="请选择执行时间" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">创建时间</label>
<label class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
</fieldset>
<script>form.render()</script>

View File

@ -1,15 +0,0 @@
<div class="layui-card">
{block name='style'}{/block}
{block name='header'}{notempty name='title'}
<div class="layui-card-header notselect">
<span class="layui-icon layui-icon-next font-s10 color-desc margin-right-5"></span>{$title|default=''}
<div class="pull-right">{block name='button'}{/block}</div>
</div>
{/notempty}{/block}
<div class="layui-card-body">
<div class="layui-card-table">
{block name='content'}{/block}
</div>
</div>
{block name='script'}{/block}
</div>

View File

@ -1,121 +0,0 @@
<form class="layui-form layui-card" action="{:sysuri()}" id="UserForm" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body padding-left-40">
<fieldset>
<legend><b class="layui-badge think-bg-violet">用户账号</b></legend>
<div class="layui-row layui-col-space15">
<div class="layui-row layui-col-space15">
<div class="layui-col-xs2 text-center">
<input type="hidden" name="headimg" value="{$vo.headimg|default=''}">
<script>$('[name=headimg]').uploadOneImage();</script>
</div>
<div class="layui-col-xs5">
<label class="block relative">
<span class="help-label"><b>登录账号</b>Login Username</span>
{if isset($vo) and isset($vo.username)}
<input disabled value='{$vo.username|default=""}' required class="layui-input think-bg-gray">
{else}
<input name="username" value='{$vo.username|default=""}' required pattern="^.{4,}$" placeholder="请输入登录账号" class="layui-input">
{/if}
<span class="help-block">登录账号不能重复并且创建后不能再次修改哦。</span>
</label>
</div>
<div class="layui-col-xs5">
<label class="block relative">
<span class="help-label"><b>用户名称</b>User Nickname</span>
<input name="nickname" value='{$vo.nickname|default=""}' required placeholder="请输入用户名称" class="layui-input">
<span class="help-block">用于区分用户数据的用户名称,请尽量不要重复。</span>
</label>
</div>
</div>
</div>
</fieldset>
{if !empty($bases) || !empty($authorizes)}
<fieldset>
<legend><b class="layui-badge think-bg-violet">用户权限</b></legend>
{if !empty($bases)}
<div class="layui-form-item">
<div class="help-label"><b>角色身份</b>Role Identity</div>
<div class="layui-textarea" style="min-height:auto">
{foreach $bases as $base}
<label class="think-checkbox">
{if isset($vo.usertype) and $vo.usertype eq $base.code}
<input type="radio" checked name="usertype" value="{$base.code}" lay-ignore>{$base.name}
{else}
<input type="radio" name="usertype" value="{$base.code}" lay-ignore>{$base.name}
{/if}
</label>
{/foreach}
</div>
</div>
{/if}
{if !empty($authorizes)}
<div class="layui-form-item">
<div class="help-label"><b>访问权限</b>Role Permission</div>
<div class="layui-textarea" style="min-height:auto">
{if isset($vo.username) and $vo.username eq $superName}
<span class="color-desc">超级用户拥所有访问权限,不需要配置权限。</span>
{else}{foreach $authorizes as $authorize}
<label class="think-checkbox">
{if in_array($authorize.id, $vo.authorize)}
<input type="checkbox" checked name="authorize[]" value="{$authorize.id}" lay-ignore>{$authorize.title}
{else}
<input type="checkbox" name="authorize[]" value="{$authorize.id}" lay-ignore>{$authorize.title}
{/if}
</label>
{/foreach}{/if}
</div>
</div>
{/if}
</fieldset>
{/if}
<fieldset>
<legend><b class="layui-badge think-bg-violet">用户资料</b></legend>
<div class="layui-row layui-col-space15">
<div class="layui-col-xs4">
<label class="relative block">
<span class="help-label"><b>联系邮箱</b>Contact Email</span>
<input name="contact_mail" pattern="^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$" value='{$vo.contact_mail|default=""}' placeholder="请输入联系电子邮箱" class="layui-input">
<span class="color-desc">可选,请填写用户常用的电子邮箱</span>
</label>
</div>
<div class="layui-col-xs4">
<label class="relative block">
<span class="help-label"><b>联系手机</b>Contact Mobile</span>
<input type="tel" maxlength="11" name="contact_phone" value='{$vo.contact_phone|default=""}' pattern="^1[3-9][0-9]{9}$" placeholder="请输入用户联系手机" class="layui-input">
<span class="color-desc">可选,请填写用户常用的联系手机号</span>
</label>
</div>
<div class="layui-col-xs4">
<label class="relative block">
<span class="help-label"><b>联系QQ</b>Contact QQ</span>
<input name="contact_qq" pattern="^\d{6,}$" value='{$vo.contact_qq|default=""}' placeholder="请输入常用的联系QQ" class="layui-input">
<span class="color-desc">可选,请填写用户常用的联系QQ号</span>
</label>
</div>
</div>
<label class="layui-form-item block relative margin-top-10">
<span></span>
<b class="color-green">用户描述</b><span class="color-desc margin-left-5">User Remark</span>
<textarea placeholder="请输入用户描述" class="layui-textarea" name="describe">{$vo.describe|default=""}</textarea>
</label>
</fieldset>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>
<script>
$(function () {
layui.form.render();
});
</script>

View File

@ -1,107 +0,0 @@
{extend name="../../admin/view/table"}
{block name="button"}
{if isset($type) and $type eq 'index'}
<!--{if auth("add")}-->
<button data-modal='{:url("add")}' data-title="添加用户" class='layui-btn layui-btn-sm layui-btn-primary'>添加用户</button>
<!--{/if}-->
<!--{if auth("state")}-->
<a data-confirm="确定要启用该用户吗?" data-table-id="UserData" data-action="{:url('state')}" data-rule="id#{id};status#0" class='layui-btn layui-btn-sm layui-btn-primary'>批量禁用</a>
<!--{/if}-->
{else}
<!--{if auth("state")}-->
<a data-confirm="确定要恢复这些账号吗?" data-table-id="UserData" data-action="{:url('state')}" data-rule="id#{id};status#1" class='layui-btn layui-btn-sm layui-btn-primary'>批量恢复</a>
<!--{/if}-->
<!--{if auth("remove")}-->
<a data-confirm="确定永久删除这些账号吗?" data-table-id="UserData" data-action='{:url("remove")}' data-rule="id#{id}" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</a>
<!--{/if}-->
{/if}
{/block}
{block name="content"}
<div class="layui-tab layui-tab-card">
<ul class="layui-tab-title">
{foreach ['index'=>'系统用户','recycle'=>'回 收 站'] as $k=>$v}{if isset($type) and $type eq $k}
<li data-open="{:url('index')}?type={$k}" class="layui-this color-green">{$v}</li>
{else}
<li data-open="{:url('index')}?type={$k}">{$v}</li>
{/if}{/foreach}
</ul>
<div class="layui-tab-content">
{include file='user/index_search'}
<table id="UserData" data-url="{:sysuri('index')}" data-target-search="form.form-search"></table>
</div>
</div>
<script>
$(function () {
$('#UserData').layTable({
even: true, height: 'full',
sort: {field: 'sort desc,id', type: 'desc'},
where: {type: '{$type|default="index"}'},
cols: [[
{checkbox: true, fixed: true},
{field: 'sort', title: '排序权重', width: 100, align: 'center', sort: true, templet: '#SortInputTpl'},
{field: 'username', title: '登录账号', minWidth: 110, templet: '<div>{{d.username||"-"}}</div>'},
{field: 'nickname', title: '用户名称', minWidth: 110, templet: '<div>{{d.nickname||"-"}}</div>'},
/* {notempty name='bases'} */
{
field: 'usertype', title: '角色身份', minWidth: 140, sort: true, templet: function (d) {
d.userinfo = d.userinfo || {};
return d.userinfo.code ? (d.userinfo.name + ' ( ' + d.userinfo.code + ' ) ') : '';
}
},
/* {/notempty} */
// {field: 'contact_mail', title: '联系邮箱', minWidth: 80, templet: '<div>{{d.contact_mail||"-"}}</div>'},
// {field: 'contact_phone', title: '联系电话', minWidth: 80, templet: '<div>{{d.contact_phone||"-"}}</div>'},
{field: 'status', title: '账号状态', align: 'center', minWidth: 110, templet: '#StatusSwitchTpl'},
{field: 'login_num', title: '登录次数', align: 'center', minWidth: 80, sort: true},
{field: 'login_at', title: '最后登录', align: 'center', minWidth: 170, sort: true},
{field: 'create_at', title: '创建时间', align: 'center', minWidth: 170, sort: true},
{toolbar: '#toolbar', title: '操作面板', align: 'center', minWidth: 160, fixed: 'right'}
]]
});
// 数据状态切换操作
layui.form.on('switch(StatusSwitch)', function (obj) {
$.form.load("{:url('state')}", {id: obj.value, status: obj.elem.checked > 0 ? 1 : 0}, 'post', function (ret) {
if (ret.code < 1) $.msg.error(ret.info, 3, function () {
$('#UserData').trigger('reload'); // 操作异常时重载数据
});
return false;
}, false);
});
});
</script>
<!-- 数据状态切换模板 -->
<script type="text/html" id="StatusSwitchTpl">
<!--{if auth("state")}-->
<input type="checkbox" value="{{d.id}}" lay-skin="switch" lay-text="已激活|已禁用" lay-filter="StatusSwitch" {{d.status>0?'checked':''}}>
<!--{else}-->
{{d.status ? '<b class="color-green">已启用</b>' : '<b class="color-red">已禁用</b>'}}
<!--{/if}-->
</script>
<!-- 列表排序权重模板 -->
<script type="text/html" id="SortInputTpl">
<input min="0" type="number" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
</script>
<script type="text/html" id="toolbar">
{if isset($type) and $type eq 'index'}
<!--{if auth("edit")}-->
<a class="layui-btn layui-btn-sm" data-title="编辑用户" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
<!--{/if}-->
<!--{if auth("pass")}-->
<a class="layui-btn layui-btn-sm layui-btn-normal" data-title="设置密码" data-modal='{:url("pass")}?id={{d.id}}'>密 码</a>
<!--{/if}-->
{else}
<!--{if auth("edit")}-->
<a class="layui-btn layui-btn-sm" data-title="编辑用户" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
<!--{/if}-->
<!--{if auth("remove")}-->
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要永久删除此账号吗?" data-action="{:url('remove')}" data-value="id#{{d.id}}">删 除</a>
<!--{/if}-->
{/if}
</script>
{/block}

View File

@ -1,69 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">用户名称</label>
<label class="layui-input-inline">
<input name="nickname" value="{$get.nickname|default=''}" placeholder="请输入用户名称" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">登录账号</label>
<label class="layui-input-inline">
<input name="username" value="{$get.username|default=''}" placeholder="请输入登录账号" class="layui-input">
</label>
</div>
<!--{notempty name='bases'}-->
<div class="layui-form-item layui-inline">
<label class="layui-form-label">角色身份</label>
<div class="layui-input-inline">
<select name="usertype" lay-search class="layui-select">
<option value=''>-- 全部 --</option>
{foreach $bases as $base}{if $base.code eq input('get.usertype')}
<option selected value="{$base.code|default=''}">{$base.name|default=''} ( {$base.code|default=''} )</option>
{else}
<option value="{$base.code|default=''}">{$base.name|default=''} ( {$base.code|default=''} )</option>
{/if}{/foreach}
</select>
</div>
</div>
<!--{/notempty}-->
<div class="layui-form-item layui-inline layui-hide">
<label class="layui-form-label">联系手机</label>
<label class="layui-input-inline">
<input name="phone" value="{$get.phone|default=''}" placeholder="请输入联系手机" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline layui-hide">
<label class="layui-form-label">联系邮箱</label>
<label class="layui-input-inline">
<input name="mail" value="{$get.mail|default=''}" placeholder="请输入联系邮箱" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">最后登录</label>
<div class="layui-input-inline">
<input data-date-range name="login_at" value="{$get.login_at|default=''}" placeholder="请选择登录时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<input type="hidden" name="type" value="{$type|default='index'}">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
<script>form.render()</script>
</fieldset>

View File

@ -1,49 +0,0 @@
<form class="layui-form layui-card" action="{:sysuri()}" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body padding-left-40">
<div class="layui-form-item">
<label class="relative block">
<span class="help-label"><b>登录用户账号</b>Username</span>
<!--{if isset($vo) and isset($vo.username)}-->
<input disabled value='{$vo.username|default=""}' class="layui-input think-bg-gray">
<!--{else}-->
<input name="username" value='{$vo.username|default=""}' required pattern="^.{4,}$" placeholder="请输入4位及以上字符登录用户账号" class="layui-input">
<!--{/if}-->
</label>
<p class="help-block">登录用户账号创建后,不允许再次修改。</p>
</div>
<!--{if $verify}-->
<div class="layui-form-item">
<label class="relative block">
<span class="help-label"><b>旧的登录密码</b>Old Password</span>
<input type="password" autofocus name="oldpassword" value='' pattern="^\S{1,}$" required placeholder="请输入旧的登录密码" class="layui-input">
</label>
<p class="color-desc">请输入旧密码来验证修改权限,旧密码不限制格式。</p>
</div>
<!--{/if}-->
<div class="layui-form-item">
<label class="relative block">
<span class="help-label"><b>新的登录密码</b>New Password</span>
<input type="password" name="password" maxlength="32" pattern="^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$" required placeholder="请输入新的登录密码" class="layui-input">
</label>
<p class="color-desc">密码必需包含大小写字母、数字、符号的任意两者组合。</p>
</div>
<div class="layui-form-item">
<label class="relative block">
<span class="help-label"><b>重复登录密码</b>Repeat Password</span>
<input type="password" name="repassword" maxlength="32" pattern="^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$" required placeholder="请重复输入登录密码" class="layui-input">
</label>
<p class="color-desc">密码必需包含大小写字母、数字、符号的任意两者组合。</p>
</div>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>

View File

@ -1,81 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\ShopOrder;
use app\data\model\ShopOrderItem;
use app\data\service\OrderService;
use think\admin\Command;
use think\admin\Exception;
use think\console\Input;
use think\console\Output;
use think\Model;
/**
* 商城订单自动清理
* Class OrderClean
* @package app\data\command
*/
class OrderClean extends Command
{
protected function configure()
{
$this->setName('xdata:OrderClean');
$this->setDescription('批量清理商城订单数据');
}
/**
* 业务指令执行
* @param Input $input
* @param Output $output
* @return void
* @throws Exception
*/
protected function execute(Input $input, Output $output)
{
$this->_autoCancelOrder();
$this->_autoRemoveOrder();
}
/**
* 自动取消30分钟未支付的订单
* @throws Exception
*/
private function _autoCancelOrder()
{
try {
$map = [['status', '<', 3], ['payment_status', '=', 0]];
$map[] = ['create_at', '<', date('Y-m-d H:i:s', strtotime('-30 minutes'))];
[$count, $total] = [0, ($result = ShopOrder::mk()->where($map)->select())->count()];
$result->map(function (Model $item) use ($total, &$count) {
$this->queue->message($total, ++$count, "开始取消未支付的订单 {$item['order_no']}");
$item->save(['status' => 0, 'cancel_status' => 1, 'cancel_datetime' => date('Y-m-d H:i:s'), 'cancel_remark' => '自动取消30分钟未完成支付']);
OrderService::instance()->stock($item['order_no']);
$this->queue->message($total, $count, "完成取消未支付的订单 {$item['order_no']}", 1);
});
} catch (\Exception $exception) {
$this->queue->error($exception->getMessage());
}
}
/**
* 自动清理已经取消的订单
* @throws Exception
*/
private function _autoRemoveOrder()
{
try {
$map = [['status', '=', 0], ['payment_status', '=', 0]];
$map[] = ['create_at', '<', date('Y-m-d H:i:s', strtotime('-3 days'))];
[$count, $total] = [0, ($result = ShopOrder::mk()->where($map)->select())->count()];
$result->map(function (Model $item) use ($total, &$count) {
$this->queue->message($total, ++$count, "开始清理已取消的订单 {$item['order_no']}");
ShopOrder::mk()->where(['order_no' => $item['order_no']])->delete();
ShopOrderItem::mk()->where(['order_no' => $item['order_no']])->delete();
$this->queue->message($total, $count, "完成清理已取消的订单 {$item['order_no']}", 1);
});
} catch (\Exception $exception) {
$this->queue->error($exception->getMessage());
}
}
}

View File

@ -1,79 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\DataUser;
use app\data\service\UserUpgradeService;
use think\admin\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
/**
* 更新用户代理关系
* Class UserAgent
* @package app\data\command
*/
class UserAgent extends Command
{
protected function configure()
{
$this->setName('xdata:UserAgent');
$this->addArgument('uuid', Argument::OPTIONAL, '目标用户', '');
$this->addArgument('puid', Argument::OPTIONAL, '上级代理', '');
$this->setDescription('重新设置用户上级代理, 参数UUID PUID');
}
/**
* @param Input $input
* @param Output $output
* @return void
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function execute(Input $input, Output $output)
{
[$uuid, $puid] = [$input->getArgument('uuid'), $input->getArgument('puid')];
if (empty($uuid)) $this->setQueueError("参数UID无效请传入正确的参数!");
if (empty($puid)) $this->setQueueError("参数PID无效请传入正确的参数!");
// 检查当前用户资料
$user = DataUser::mk()->where(['id' => $uuid])->find();
if (empty($user)) $this->setQueueError("读取用户数据失败!");
// 检查上级代理用户
$parant = DataUser::mk()->where(['id' => $puid])->find();
if (empty($parant)) $this->setQueueError('读取代理数据失败!');
// 检查异常关系处理
if (stripos($parant['path'], "-{$user['id']}-")) {
$this->setQueueError('不能把下级设置为代理!');
}
// 更新自己的代理关系
$path1 = rtrim($parant['path'] ?: '-', '-') . "-{$parant['id']}-";
DataUser::mk()->where(['id' => $user['id']])->update([
'path' => $path1, 'layer' => substr_count($path1, '-'),
'pid0' => $parant['id'], 'pid1' => $parant['id'], 'pid2' => $parant['pid1'],
]);
UserUpgradeService::instance()->upgrade($user['id'], true);
$this->setQueueMessage(1, 1, "更新指定用户[{$user['id']}]代理绑定成功!");
// 更新下级的代理关系
$path2 = "{$user['path']}{$user['id']}-";
[$total, $count] = [DataUser::mk()->whereLike('path', "{$path2}%")->count(), 0];
foreach (DataUser::mk()->whereLike('path', "{$path2}%")->order('layer desc')->select() as $vo) {
$this->setQueueMessage($total, ++$count, "开始更新下级用户[{$vo['id']}]代理绑定!");
// 更新下级用户代理数据
$path3 = preg_replace("#^{$path2}#", "{$path1}{$user['id']}-", $vo['path']);
$attrs = array_reverse(str2arr($path3, '-'));
DataUser::mk()->where(['id' => $vo['id']])->update([
'path' => $path3, 'layer' => substr_count($path3, '-'),
'pid0' => $attrs[0] ?? 0, 'pid1' => $attrs[0] ?? 0, 'pid2' => $attrs[1] ?? 0,
]);
$this->setQueueMessage($total, $count, "完成更新下级用户[{$vo['id']}]代理绑定!", 1);
}
}
}

View File

@ -1,46 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\DataUser;
use app\data\service\UserBalanceService;
use app\data\service\UserRebateService;
use think\admin\Command;
use think\admin\Exception;
use think\console\Input;
use think\console\Output;
/**
* 用户余额及返利重算处理
* Class UserBalance
* @package app\data\command
*/
class UserAmount extends Command
{
protected function configure()
{
$this->setName('xdata:UserAmount');
$this->setDescription('批量重新计算余额返利');
}
/**
* @param Input $input
* @param Output $output
* @return void
* @throws Exception
*/
protected function execute(Input $input, Output $output)
{
[$total, $count, $error] = [DataUser::mk()->count(), 0, 0];
foreach (DataUser::mk()->field('id')->cursor() as $user) try {
$this->queue->message($total, ++$count, "刷新用户 [{$user['id']}] 余额及返利开始");
UserRebateService::instance()->amount($user['id']);
UserBalanceService::instance()->amount($user['id']);
$this->queue->message($total, $count, "刷新用户 [{$user['id']}] 余额及返利完成", 1);
} catch (\Exception $exception) {
$error++;
$this->queue->message($total, $count, "刷新用户 [{$user['id']}] 余额及返利失败, {$exception->getMessage()}", 1);
}
$this->setQueueSuccess("此次共处理 {$total} 个刷新操作, 其中有 {$error} 个刷新失败。");
}
}

View File

@ -1,262 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\DataUser;
use app\data\model\DataUserTransfer;
use app\data\service\UserRebateService;
use think\admin\Command;
use think\admin\Exception;
use think\admin\storage\LocalStorage;
use think\console\Input;
use think\console\Output;
use WePay\Transfers;
use WePay\TransfersBank;
/**
* 用户提现处理
* Class UserTransfer
* @package app\data\command
*/
class UserTransfer extends Command
{
protected function configure()
{
$this->setName('xdata:UserTransfer');
$this->setDescription('批量执行线上打款操作');
}
/**
* 执行微信提现操作
* @param Input $input
* @param Output $output
* @return void
* @throws \think\admin\Exception
*/
protected function execute(Input $input, Output $output)
{
$map = [['type', 'in', ['wechat_banks', 'wechat_wallet']], ['status', 'in', [3, 4]]];
[$total, $count, $error] = [DataUserTransfer::mk()->where($map)->count(), 0, 0];
foreach (DataUserTransfer::mk()->where($map)->cursor() as $vo) try {
$this->queue->message($total, ++$count, "开始处理订单 {$vo['code']} 提现");
if ($vo['status'] === 3) {
$this->queue->message($total, $count, "尝试处理订单 {$vo['code']} 打款", 1);
if ($vo['type'] === 'wechat_banks') {
[$config, $result] = $this->createTransferBank($vo);
} else {
[$config, $result] = $this->createTransferWallet($vo);
}
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
DataUserTransfer::mk()->where(['code' => $vo['code']])->update([
'status' => 4,
'appid' => $config['appid'],
'openid' => $config['openid'],
'trade_no' => $result['partner_trade_no'],
'trade_time' => $result['payment_time'] ?? date('Y-m-d H:i:s'),
'change_time' => date('Y-m-d H:i:s'),
'change_desc' => '创建微信提现成功',
]);
} else {
DataUserTransfer::mk()->where(['code' => $vo['code']])->update([
'change_time' => date('Y-m-d H:i:s'), 'change_desc' => $result['err_code_des'] ?? '线上提现失败',
]);
}
} elseif ($vo['status'] === 4) {
$this->queue->message($total, $count, "刷新提现订单 {$vo['code']} 状态", 1);
if ($vo['type'] === 'wechat_banks') {
$this->queryTransferBank($vo);
} else {
$this->queryTransferWallet($vo);
}
}
} catch (\Exception $exception) {
$error++;
$this->queue->message($total, $count, "处理提现订单 {$vo['code']} 失败, {$exception->getMessage()}", 1);
DataUserTransfer::mk()->where(['code' => $vo['code']])->update([
'change_time' => date('Y-m-d H:i:s'), 'change_desc' => $exception->getMessage(),
]);
}
$this->setQueueSuccess("此次共处理 {$total} 笔提现操作, 其中有 {$error} 笔处理失败。");
}
/**
* 尝试提现转账到银行卡
* @param array $item
* @return array [config, result]
* @throws \WeChat\Exceptions\InvalidDecryptException
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function createTransferBank(array $item): array
{
$config = $this->getConfig($item['uuid']);
return [$config, TransfersBank::instance($config)->create([
'partner_trade_no' => $item['code'],
'enc_bank_no' => $item['bank_code'],
'enc_true_name' => $item['bank_user'],
'bank_code' => $item['bank_wseq'],
'amount' => intval($item['amount'] - $item['charge_amount']) * 100,
'desc' => '微信银行卡提现',
])];
}
/**
* 获取微信提现参数
* @param int $uuid
* @return array
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getConfig(int $uuid): array
{
$data = sysdata('TransferWxpay');
if (empty($data)) throw new Exception('未配置微信提现商户');
// 商户证书文件处理
$local = LocalStorage::instance();
if (!$local->has($file1 = "{$data['wechat_mch_id']}_key.pem", true)) {
$local->set($file1, $data['wechat_mch_key_text'], true);
}
if (!$local->has($file2 = "{$data['wechat_mch_id']}_cert.pem", true)) {
$local->set($file2, $data['wechat_mch_cert_text'], true);
}
// 获取用户支付信息
$result = $this->getWechatInfo($uuid, $data['wechat_type']);
if (empty($result)) throw new Exception('无法读取打款数据');
return [
'appid' => $result[0],
'openid' => $result[1],
'mch_id' => $data['wechat_mch_id'],
'mch_key' => $data['wechat_mch_key'],
'ssl_key' => $local->path($file1),
'ssl_cer' => $local->path($file2),
'cache_path' => $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . 'wechat',
];
}
/**
* 根据配置获取用户OPENID
* @param int $uuid
* @param string $type
* @return mixed|null
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getWechatInfo(int $uuid, string $type): ?array
{
$user = DataUser::mk()->where(['id' => $uuid])->find();
if (empty($user)) return null;
$appid1 = sysconf('data.wxapp_appid');
if (strtolower(sysconf('wechat.type')) === 'api') {
$appid2 = sysconf('wechat.appid');
} else {
$appid2 = sysconf('wechat.thr_appid');
}
if ($type === 'normal') {
if (!empty($user['openid1'])) return [$appid1, $user['openid1']];
if (!empty($user['openid2'])) return [$appid2, $user['openid2']];
}
if ($type === 'wxapp' && !empty($user['openid1'])) {
return [$appid1, $user['openid1']];
}
if ($type === 'wechat' && !empty($user['openid2'])) {
return [$appid2, $user['openid2']];
}
return null;
}
/**
* 尝试提现转账到微信钱包
* @param array $item
* @return array [config, result]
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function createTransferWallet(array $item): array
{
$config = $this->getConfig($item['uuid']);
return [$config, Transfers::instance($config)->create([
'openid' => $config['openid'],
'amount' => intval($item['amount'] - $item['charge_amount']) * 100,
'partner_trade_no' => $item['code'],
'spbill_create_ip' => '127.0.0.1',
'check_name' => 'NO_CHECK',
'desc' => '微信余额提现',
])];
}
/**
* 查询更新提现打款状态
* @param array $item
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function queryTransferBank(array $item)
{
$config = $this->getConfig($item['uuid']);
[$config['appid'], $config['openid']] = [$item['appid'], $item['openid']];
$result = TransfersBank::instance($config)->query($item['trade_no']);
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
if ($result['status'] === 'SUCCESS') {
DataUserTransfer::mk()->where(['code' => $item['code']])->update([
'status' => 5,
'appid' => $config['appid'],
'openid' => $config['openid'],
'trade_time' => $result['pay_succ_time'] ?: date('Y-m-d H:i:s'),
'change_time' => date('Y-m-d H:i:s'),
'change_desc' => '微信提现打款成功',
]);
}
if (in_array($result['status'], ['FAILED', 'BANK_FAIL'])) {
DataUserTransfer::mk()->where(['code' => $item['code']])->update([
'status' => 0,
'change_time' => date('Y-m-d H:i:s'),
'change_desc' => '微信提现打款失败',
]);
// 刷新用户可提现余额
UserRebateService::instance()->amount($item['uuid']);
}
}
}
/**
* 查询更新提现打款状态
* @param array $item
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function queryTransferWallet(array $item)
{
$config = $this->getConfig($item['uuid']);
[$config['appid'], $config['openid']] = [$item['appid'], $item['openid']];
$result = Transfers::instance($config)->query($item['trade_no']);
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
DataUserTransfer::mk()->where(['code' => $item['code']])->update([
'status' => 5,
'appid' => $config['appid'],
'openid' => $config['openid'],
'trade_time' => $result['payment_time'],
'change_time' => date('Y-m-d H:i:s'),
'change_desc' => '微信提现打款成功',
]);
}
}
}

View File

@ -1,47 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\DataUser;
use app\data\service\UserUpgradeService;
use think\admin\Command;
use think\admin\Exception;
use think\console\Input;
use think\console\Output;
/**
* 用户等级重算处理
* Class UserLevel
* @package app\data\command
*/
class UserUpgrade extends Command
{
protected function configure()
{
$this->setName('xdata:UserUpgrade');
$this->setDescription('批量重新计算用户等级');
}
/**
* @param Input $input
* @param Output $output
* @return void
* @throws Exception
*/
protected function execute(Input $input, Output $output)
{
try {
[$total, $count] = [DataUser::mk()->count(), 0];
foreach (DataUser::mk()->field('id')->cursor() as $user) {
$this->queue->message($total, ++$count, "正在计算用户 [{$user['id']}] 的等级");
UserUpgradeService::instance()->upgrade($user['id']);
$this->queue->message($total, $count, "完成计算用户 [{$user['id']}] 的等级", 1);
}
$this->setQueueSuccess("此次共重新计算 {$total} 个用户等级。");
} catch (Exception $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->setQueueError($exception->getMessage());
}
}
}

View File

@ -1,95 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\service\UserAdminService;
use app\data\service\UserTokenService;
use think\admin\Controller;
use think\exception\HttpResponseException;
/**
* 接口授权认证基类
* Class Auth
* @package app\data\controller\api
*/
abstract class Auth extends Controller
{
/**
* 当前接口请求终端类型
* --- 手机浏览器访问 wap
* --- 电脑浏览器访问 web
* --- 微信小程序访问 wxapp
* --- 微信服务号访问 wechat
* --- 苹果应用接口访问 isoapp
* --- 安卓应用接口访问 android
* @var string
*/
protected $type;
/**
* 当前用户编号
* @var integer
*/
protected $uuid;
/**
* 当前用户数据
* @var array
*/
protected $user;
/**
* 控制器初始化
*/
protected function initialize()
{
// 接收接口类型
$this->type = $this->request->request('api');
$this->type = $this->type ?: $this->request->header('api-name');
$this->type = $this->type ?: $this->request->header('api-type');
// 检查接口类型
if (empty($this->type)) {
$this->error("未获取到接口类型字段!");
}
if (!isset(UserAdminService::TYPES[$this->type])) {
$this->error("接口类型[{$this->type}]未定义!");
}
// 获取用户数据
$this->user = $this->getUser();
$this->uuid = $this->user['id'] ?? '';
if (empty($this->uuid)) {
$this->error('用户登录失败!', '{-null-}', 401);
}
}
/**
* 获取用户数据
* @return array
*/
protected function getUser(): array
{
try {
if (empty($this->uuid)) {
$token = input('token') ?: $this->request->header('api-token');
if (empty($token)) $this->error('登录认证TOKEN不能为空');
[$state, $info, $this->uuid] = UserTokenService::instance()->check($this->type, $token);
if (empty($state)) $this->error($info, '{-null-}', 401);
}
return UserAdminService::instance()->get($this->uuid, $this->type);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 显示用户禁用提示
*/
protected function checkUserStatus()
{
if (empty($this->user['status'])) {
$this->error('账户已被冻结!');
}
}
}

View File

@ -1,53 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\model\BaseUserMessage;
use think\admin\Controller;
/**
* 基础数据接口
* Class Data
* @package app\data\controller\api
*/
class Data extends Controller
{
/**
* 获取指定数据对象
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getData()
{
$data = $this->_vali(['name.require' => '数据名称不能为空!']);
$this->success('获取数据对象', sysdata($data['name']));
}
/**
* 获取轮播图片数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getSlider()
{
$data = sysdata(input('keys', 'slider'));
$this->success('获取轮播图片', $data);
}
/**
* 获取系统通知数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getNotify()
{
$model = BaseUserMessage::mQuery()->where(['status' => 1, 'deleted' => 0]);
$result = $model->equal('id')->order('sort desc,id desc')->page(true, false, false, 20);
if (($id = input('id')) > 0) BaseUserMessage::mk()->where(['id' => $id])->inc('num_read')->update([]);
$this->success('获取系统通知', $result);
}
}

View File

@ -1,61 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\model\ShopGoods;
use app\data\service\ExpressService;
use app\data\service\GoodsService;
use think\admin\Controller;
/**
* 商品数据接口
* Class Goods
* @package app\data\controller\api
*/
class Goods extends Controller
{
/**
* 获取分类数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getCate()
{
$this->success('获取分类成功', GoodsService::instance()->getCateTree());
}
/**
* 获取标签数据
*/
public function getMark()
{
$this->success('获取标签成功', GoodsService::instance()->getMarkData());
}
/**
* 获取商品数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getGoods()
{
// 更新访问统计
$map = $this->_vali(['code.default' => '']);
if ($map['code']) ShopGoods::mk()->where($map)->inc('num_read')->update([]);
// 商品数据处理
$query = ShopGoods::mQuery()->like('name,marks,cateids,payment')->equal('code,vip_entry');
$result = $query->where(['deleted' => 0, 'status' => 1])->order('sort desc,id desc')->page(true, false, false, 10);
if (count($result['list']) > 0) GoodsService::instance()->bindData($result['list']);
$this->success('获取商品数据', $result);
}
/**
* 获取配送区域
*/
public function getRegion()
{
$this->success('获取区域成功', ExpressService::instance()->region(3, 1));
}
}

View File

@ -1,111 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\model\DataUser;
use app\data\service\MessageService;
use app\data\service\UserAdminService;
use think\admin\Controller;
/**
* 用户登录注册接口
* Class Login
* @package app\data\controller\api
*/
class Login extends Controller
{
/**
* 接口认证类型
* @var string
*/
private $type;
/**
* 控制器初始化
*/
protected function initialize()
{
// 接收接口类型
$this->type = $this->request->request('api');
$this->type = $this->type ?: $this->request->header('api-name');
$this->type = $this->type ?: $this->request->header('api-type');
$this->type = $this->type ?: UserAdminService::API_TYPE_WAP;
if (empty(UserAdminService::TYPES[$this->type])) {
$this->error("接口支付[{$this->type}]未定义规则!");
}
}
/**
* 用户登录接口
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function in()
{
$data = $this->_vali([
'phone.mobile' => '手机号码格式错误!',
'phone.require' => '手机号码不能为空!',
'password.require' => '登录密码不能为空!',
]);
$map = ['deleted' => 0, 'phone' => $data['phone']];
$user = DataUser::mk()->where($map)->find();
if (empty($user)) $this->error('该手机号还没有注册哦!');
if (empty($user['status'])) $this->error('该用户账号状态异常!');
if (md5($data['password']) === $user['password']) {
$this->success('手机登录成功!', UserAdminService::instance()->set($map, [], $this->type, true));
} else {
$this->error('账号登录失败,请稍候再试!');
}
}
/**
* 用户统一注册入口
* @throws \think\admin\Exception
* @throws \think\db\exception\DbException
*/
public function register()
{
$data = $this->_vali([
'region_province.default' => '',
'region_city.default' => '',
'region_area.default' => '',
'username.default' => '',
'phone.mobile' => '手机号码格式错误!',
'phone.require' => '手机号码不能为空!',
// 'verify.require' => '验证码不能为空!',
'password.require' => '登录密码不能为空!',
]);
// if (MessageService::instance()->checkVerifyCode($data['verify'], $data['phone'])) {
// @验证码验证能完
// } else {
// $this->error('验证失败!');
// }
$map = ['phone' => $data['phone'], 'deleted' => 0];
if (DataUser::mk()->where($map)->count() > 0) {
$this->error('手机号已注册,请使用其它手机号!');
}
$data['password'] = md5($data['password']);
$user = UserAdminService::instance()->set($map, $data, $this->type, true);
empty($user) ? $this->error('手机注册失败!') : $this->success('用户注册成功!', $user);
}
/**
* 发送短信验证码
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function sendsms()
{
$data = $this->_vali([
'phone.mobile' => '手机号格式错误!',
'phone.require' => '手机号不能为空!',
'secure.require' => '安全码不能为空!',
]);
if ($data['secure'] !== sysconf('zt.secure_code')) $this->error('接口安全码错误!');
[$state, $message, $data] = MessageService::instance()->sendVerifyCode($data['phone']);
$state ? $this->success($message, $data) : $this->error($message, $data);
}
}

View File

@ -1,69 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\model\DataNewsItem;
use app\data\model\DataNewsMark;
use app\data\model\DataNewsXCollect;
use app\data\service\NewsService;
use think\admin\Controller;
/**
* 文章接口控制器
* Class News
* @package app\data\controller\api
*/
class News extends Controller
{
/**
* 获取文章标签列表
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getMark()
{
$query = DataNewsMark::mQuery()->like('name');
$query->where(['status' => 1, 'deleted' => 0])->withoutField('sort,status,deleted');
$this->success('获取文章标签', $query->order('sort desc,id desc')->page(false, false));
}
/**
* 获取文章内容列表
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getItem()
{
if ($code = input('code', '')) {
DataNewsItem::mk()->where(['code' => $code])->inc('num_read')->update([]);
if (($uuid = input('uuid', 0)) > 0) {
$data = ['uuid' => $uuid, 'code' => $code, 'type' => 3, 'status' => 2];
DataNewsXCollect::mk()->where($data)->delete();
DataNewsXCollect::mk()->insert($data);
}
}
$query = DataNewsItem::mQuery()->like('name,mark')->equal('id,code');
$query->where(['deleted' => 0, 'status' => 1])->withoutField('sort,status,deleted');
$result = $query->order('sort desc,id desc')->page(true, false, false, 15);
NewsService::instance()->buildData($result['list'], input('uuid', 0));
$this->success('获取文章内容', $result);
}
/**
* 获取文章评论
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getComment()
{
$map = $this->_vali(['code.require' => '文章不能为空!']);
$query = DataNewsXCollect::mQuery()->where(['type' => 4, 'status' => 2]);
$result = $query->where($map)->order('id desc')->page(true, false, false, 15);
NewsService::instance()->buildListByUidAndCode($result['list']);
$this->success('获取评论成功', $result);
}
}

View File

@ -1,76 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\service\payment\AlipayPaymentService;
use app\data\service\payment\JoinpayPaymentService;
use app\data\service\payment\WechatPaymentService;
use think\admin\Controller;
/**
* 异步通知处理
* Class Notify
* @package app\data\controller\api
*/
class Notify extends Controller
{
/**
* 微信支付通知
* @param string $scene 支付场景
* @param string $param 支付参数
* @return string
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function wxpay(string $scene = 'order', string $param = ''): string
{
if (strtolower($scene) === 'order') {
return WechatPaymentService::instance($param)->notify();
} else {
return 'success';
}
}
/**
* 支付宝支付通知
* @param string $scene 支付场景
* @param string $param 支付参数
* @return string
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function alipay(string $scene = 'order', string $param = ''): string
{
if (strtolower($scene) === 'order') {
return AlipayPaymentService::instance($param)->notify();
} else {
return 'success';
}
}
/**
* 汇聚支付通知
* @param string $scene 支付场景
* @param string $param 支付参数
* @return string
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function joinpay(string $scene = 'order', string $param = ''): string
{
if (strtolower($scene) === 'order') {
return JoinpayPaymentService::instance($param)->notify();
} else {
return 'success';
}
}
}

View File

@ -1,137 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\service\UserAdminService;
use app\wechat\service\WechatService;
use think\admin\Controller;
use think\Response;
/**
* 微信服务号入口
* Class Wechat
* @package app\data\controller\api
* @example 域名请修改为自己的地址,放到网页代码合适位置
* <meta name="referrer" content="always">
* <script referrerpolicy="unsafe-url" src="https://your.domain.com/data/api.wechat/oauth?mode=1"></script>
*
* 授权模式支持两种模块,参数 mode=0 时为静默授权mode=1 时为完整授权
* 注意:回跳地址默认从 Header 中的 http_referer 获取,也可以传 source 参数
*/
class Wechat extends Controller
{
/**
* 接口认证类型
* @var string
*/
private $type = UserAdminService::API_TYPE_WECHAT;
/**
* 唯一绑定字段
* @var string
*/
private $field;
/**
* 控制器初始化
* @return $this
*/
protected function initialize(): Wechat
{
if (empty(UserAdminService::TYPES[$this->type]['auth'])) {
$this->error("接口类型[{$this->type}]没有定义规则");
} else {
$this->field = UserAdminService::TYPES[$this->type]['auth'];
}
return $this;
}
/**
* 获取 JSSDK 签名
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function jssdk()
{
$url = input('source') ?: $this->request->server('http_referer');
$this->success('获取签名参数', WechatService::instance()->getWebJssdkSign($url));
}
/**
* 加载网页授权数据
* @return Response
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function oauth(): Response
{
$source = input('source') ?: $this->request->server('http_referer');
[$mode, $script, $wechat] = [input('mode', 1), [], WechatService::instance()];
$result = $wechat->getWebOauthInfo($source ?: $this->request->url(true), $mode, false);
if (empty($result['openid'])) {
$script[] = 'alert("Wechat WebOauth failed.")';
} else {
$data = $result['fansinfo'] ?? [];
$data[$this->field] = $data['openid'];
$data['base_sex'] = ['未知', '男', '女'][$data['sex']] ?? '未知';
if (isset($result['unionid'])) $data['unionid'] = $result['unionid'];
if (isset($data['headimgurl'])) $data['headimg'] = $data['headimgurl'];
$map = UserAdminService::instance()->getUserUniMap($this->field, $data[$this->field], $data['unionid'] ?? '');
$result['userinfo'] = UserAdminService::instance()->set($map, array_merge($map, $data), $this->type, true);
$script[] = "window.WeChatOpenid='{$result['openid']}'";
$script[] = 'window.WeChatFansInfo=' . json_encode($result['fansinfo'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
$script[] = 'window.WeChatUserInfo=' . json_encode($result['userinfo'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
$script[] = '';
return Response::create(join(";\n", $script))->contentType('application/x-javascript');
}
/**
* 网页授权测试
* 使用网页直接访问此链接
* @return string
*/
public function otest(): string
{
return <<<EOL
<html lang="zh">
<head>
<meta charset="utf-8">
<title>微信网页授权测试</title>
<meta name="referrer" content="always">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
<style>pre{padding:20px;overflow:auto;margin-top:10px;background:#ccc;border-radius:6px;}</style>
</head>
<body>
<div>当前链接</div>
<pre>{$this->request->scheme()}://{$this->request->host()}/data/api.wechat/oauth?mode=1</pre>
<div style="margin-top:30px">粉丝数据</div>
<pre id="fansdata">待网页授权,加载粉丝数据...</pre>
<div style="margin-top:30px">用户数据</div>
<pre id="userdata">待网页授权,加载用户数据...</pre>
<script referrerpolicy="unsafe-url" src="//{$this->request->host()}/data/api.wechat/oauth?mode=1"></script>
<script>
if(typeof window.WeChatFansInfo === 'object'){
document.getElementById('fansdata').innerText = JSON.stringify(window.WeChatFansInfo, null, 2);
}
if(typeof window.WeChatUserInfo === 'object'){
document.getElementById('userdata').innerText = JSON.stringify(window.WeChatUserInfo, null, 2);
}
</script>
</body>
</html>
EOL;
}
}

View File

@ -1,194 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\service\UserAdminService;
use think\admin\Controller;
use think\exception\HttpResponseException;
use think\Response;
use WeMini\Crypt;
use WeMini\Live;
use WeMini\Qrcode;
/**
* 微信小程序入口
* Class Wxapp
* @package app\data\controller\api
*/
class Wxapp extends Controller
{
/**
* 接口认证类型
* @var string
*/
private $type = UserAdminService::API_TYPE_WXAPP;
/**
* 唯一绑定字段
* @var string
*/
private $field;
/**
* 小程序配置参数
* @var array
*/
private $config;
/**
* 接口服务初始化
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function initialize()
{
$this->config = [
'appid' => sysconf('data.wxapp_appid'),
'appsecret' => sysconf('data.wxapp_appkey'),
'cache_path' => $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . 'wechat',
];
if (empty(UserAdminService::TYPES[$this->type]['auth'])) {
$this->error("接口类型[{$this->type}]没有定义规则");
} else {
$this->field = UserAdminService::TYPES[$this->type]['auth'];
}
}
/**
* 授权Code换取会话信息
* @throws \think\admin\Exception
* @throws \think\db\exception\DbException
*/
public function session()
{
$input = $this->_vali(['code.require' => '登录凭证CODE不能为空']);
[$openid, $unionid, $session] = $this->_getSessionKey($input['code']);
$map = UserAdminService::instance()->getUserUniMap($this->field, $openid, $unionid);
$data = [$this->field => $openid, 'session_key' => $session];
if (!empty($unionid)) $data['unionid'] = $unionid;
$this->success('授权换取成功!', UserAdminService::instance()->set($map, $data, $this->type, true));
}
/**
* 小程序数据解密
*/
public function decode()
{
try {
$input = $this->_vali([
'iv.require' => '解密向量不能为空!',
'code.require' => '授权CODE不能为空',
'encrypted.require' => '加密内容不能为空!',
]);
[$openid, $unionid, $input['session_key']] = $this->_getSessionKey($input['code']);
$result = Crypt::instance($this->config)->decode($input['iv'], $input['session_key'], $input['encrypted']);
if (is_array($result) && isset($result['avatarUrl']) && isset($result['nickName'])) {
$data = [$this->field => $openid, 'nickname' => $result['nickName'], 'headimg' => $result['avatarUrl']];
$data['base_sex'] = ['-', '男', '女'][$result['gender']] ?? '-';
if (!empty($unionid)) $data['unionid'] = $unionid;
$map = UserAdminService::instance()->getUserUniMap($this->field, $openid, $unionid);
$this->success('数据解密成功!', UserAdminService::instance()->set($map, $data, $this->type, true));
} elseif (is_array($result)) {
$this->success('数据解密成功!', $result);
} else {
$this->error('数据处理失败,请稍候再试!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error("数据处理失败,{$exception->getMessage()}");
}
}
/**
* 授权CODE换取会话信息
* @param string $code 换取授权CODE
* @return array [openid, sessionkey]
*/
private function _getSessionKey(string $code): array
{
try {
$cache = $this->app->cache->get($code, []);
if (isset($cache['openid']) && isset($cache['session_key'])) {
return [$cache['openid'], $cache['unionid'] ?? '', $cache['session_key']];
}
$result = Crypt::instance($this->config)->session($code);
if (isset($result['openid']) && isset($result['session_key'])) {
$this->app->cache->set($code, $result, 60);
return [$result['openid'], $result['unionid'] ?? '', $result['session_key']];
} elseif (isset($result['errmsg'])) {
$this->error($result['errmsg']);
} else {
$this->error("授权换取失败,请稍候再试!");
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error("授权换取失败,{$exception->getMessage()}");
}
}
/**
* 获取小程序码
*/
public function qrcode(): Response
{
try {
$data = $this->_vali([
'size.default' => 430,
'type.default' => 'base64',
'path.require' => '跳转路径不能为空!',
]);
$result = Qrcode::instance($this->config)->createMiniPath($data['path'], $data['size']);
if ($data['type'] === 'base64') {
$this->success('生成小程序码成功!', [
'base64' => 'data:image/png;base64,' . base64_encode($result),
]);
} else {
return response($result)->contentType('image/png');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 获取直播列表
*/
public function getLiveList()
{
try {
$data = $this->_vali(['start.default' => 0, 'limit.default' => 10]);
$list = Live::instance($this->config)->getLiveList($data['start'], $data['limit']);
$this->success('获取直播列表成功!', $list);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 获取回放源视频
*/
public function getLiveInfo()
{
try {
$data = $this->_vali([
'start.default' => 0,
'limit.default' => 10,
'action.default' => 'get_replay',
'room_id.require' => '直播间不能为空',
]);
$result = Live::instance($this->config)->getLiveInfo($data);
$this->success('获取回放视频成功!', $result);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
}

View File

@ -1,142 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\DataUserAddress;
use think\admin\extend\CodeExtend;
/**
* 用户收货地址管理
* Class Address
* @package app\data\controller\api\auth
*/
class Address extends Auth
{
/**
* 添加收货地址
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function set()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.default' => 0,
'code.default' => '',
'idcode.default' => '', // 身份证号码
'idimg1.default' => '', // 身份证正面
'idimg2.default' => '', // 身份证反面
'type.in:0,1' => '地址状态不在范围!',
'name.require' => '收货姓名不能为空!',
'phone.mobile' => '收货手机格式错误!',
'phone.require' => '收货手机不能为空!',
'province.require' => '地址省份不能为空!',
'city.require' => '地址城市不能为空!',
'area.require' => '地址区域不能为空!',
'address.require' => '详情地址不能为空!',
'deleted.value' => 0,
]);
if (empty($data['code'])) {
unset($data['code']);
$count = DataUserAddress::mk()->where($data)->count();
if ($count > 0) $this->error('抱歉,该地址已经存在!');
$data['code'] = CodeExtend::uniqidDate(20, 'A');
if (DataUserAddress::mk()->insert($data) === false) {
$this->error('添加地址失败!');
}
} else {
$map = ['uuid' => $this->uuid, 'code' => $data['code']];
$addr = DataUserAddress::mk()->where($map)->find();
if (empty($addr)) $this->error('修改地址不存在!');
DataUserAddress::mk()->where($map)->update($data);
}
// 去除其它默认选项
if (isset($data['type']) && $data['type'] > 0) {
$map = [['uuid', '=', $this->uuid], ['code', '<>', $data['code']]];
DataUserAddress::mk()->where($map)->update(['type' => 0]);
}
$this->success('地址保存成功!', $this->_getAddress($data['code']));
}
/**
* 获取收货地址
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function get()
{
$query = DataUserAddress::mQuery()->withoutField('deleted');
$query->equal('code')->where(['uuid' => $this->uuid, 'deleted' => 0]);
$result = $query->order('type desc,id desc')->page(false, false, false, 15);
$this->success('获取地址数据!', $result);
}
/**
* 修改地址状态
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function state()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.in:0,1' => '地址状态不在范围!',
'type.require' => '地址状态不能为空!',
'code.require' => '地址编号不能为空!',
]);
// 检查地址是否存在
$map = ['uuid' => $data['uuid'], 'code' => $data['code']];
if (DataUserAddress::mk()->where($map)->count() < 1) {
$this->error('修改的地址不存在!');
}
// 更新默认地址状态
$data['type'] = intval($data['type']);
DataUserAddress::mk()->where($map)->update(['type' => $data['type']]);
// 去除其它默认选项
if ($data['type'] > 0) {
$map = [['uuid', '=', $this->uuid], ['code', '<>', $data['code']]];
DataUserAddress::mk()->where($map)->update(['type' => 0]);
}
$this->success('默认设置成功!', $this->_getAddress($data['code']));
}
/**
* 删除收货地址
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function remove()
{
$map = $this->_vali([
'uuid.value' => $this->uuid,
'code.require' => '地址不能为空!',
]);
$data = DataUserAddress::mk()->where($map)->find();
if (empty($data)) $this->error('需要删除的地址不存在!');
if ($data->save(['deleted' => 1]) !== false) {
$this->success('删除地址成功!');
} else {
$this->error('删除地址失败!');
}
}
/**
* 获取指定的地址
* @param string $code
* @return null|array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function _getAddress(string $code): array
{
$map = ['code' => $code, 'uuid' => $this->uuid, 'deleted' => 0];
$data = DataUserAddress::mk()->withoutField('deleted')->where($map)->find();
return empty($data) ? [] : $data->toArray();
}
}

View File

@ -1,27 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\DataUserBalance;
/**
* 用户余额转账
* Class Balance
* @package app\data\controller\api\auth
*/
class Balance extends Auth
{
/**
* 获取用户余额记录
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function get()
{
$query = DataUserBalance::mQuery()->withoutField('deleted,create_by');
$query->where(['uuid' => $this->uuid, 'deleted' => 0])->like('create_at#date');
$this->success('获取数据成功', $query->order('id desc')->page(true, false, false, 10));
}
}

View File

@ -1,152 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\DataUser;
use app\data\service\RebateService;
use app\data\service\UserAdminService;
use app\data\service\UserUpgradeService;
use think\admin\Storage;
use think\exception\HttpResponseException;
/**
* 用户资料管理
* Class Center
* @package app\data\controller\api\auth
*/
class Center extends Auth
{
/**
* 更新用户资料
*/
public function set()
{
$data = $this->_vali([
'headimg.default' => '',
'username.default' => '',
'base_age.default' => '',
'base_sex.default' => '',
'base_height.default' => '',
'base_weight.default' => '',
'base_birthday.default' => '',
]);
foreach ($data as $key => $vo) if ($vo === '') unset($data[$key]);
if (empty($data)) $this->error('没有修改的数据!');
if (DataUser::mk()->where(['id' => $this->uuid])->update($data) !== false) {
$this->success('更新资料成功!', $this->getUser());
} else {
$this->error('更新资料失败!');
}
}
/**
* 获取用户资料
*/
public function get()
{
$this->success('获取用户资料', $this->getUser());
}
/**
* Base64 图片上传
*/
public function image()
{
try {
$data = $this->_vali(['base64.require' => '图片内容不为空!']);
if (preg_match('|^data:image/(.*?);base64,|i', $data['base64'])) {
[$ext, $img] = explode('|||', preg_replace('|^data:image/(.*?);base64,|i', '$1|||', $data['base64']));
$info = Storage::instance()->set(Storage::name($img, $ext ?: 'png', 'image/'), base64_decode($img));
$this->success('图片上传成功!', ['url' => $info['url']]);
} else {
$this->error('解析内容失败!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 二进制文件上传
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function upload()
{
$file = $this->request->file('file');
if (empty($file)) $this->error('文件上传异常!');
$extension = strtolower($file->getOriginalExtension());
if (in_array($extension, ['php', 'sh'])) $this->error('禁止上传此类文件!');
$bina = file_get_contents($file->getRealPath());
$name = Storage::name($file->getPathname(), $extension, '', 'md5_file');
$info = Storage::instance()->set($name, $bina, false, $file->getOriginalName());
if (is_array($info) && isset($info['url'])) {
$this->success('文件上传成功!', $info);
} else {
$this->error('文件上传失败!');
}
}
/**
* 获取用户等级
*/
public function levels()
{
$levels = UserUpgradeService::instance()->levels();
foreach ($levels as &$level) {
$level['prizes'] = [];
foreach (str2arr($level['rebate_rule']) as $code) {
$level['prizes'][$code] = RebateService::instance()->name($code);
}
}
$this->success('获取用户等级', array_values($levels));
}
/**
* 获取我邀请的朋友
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getFrom()
{
$map = [];
$map[] = ['deleted', '=', 0];
$map[] = ['path', 'like', "%-{$this->uuid}-%"];
// 查询邀请的朋友
$query = $this->_query(DataUser::class);
$query->like('nickname|username#nickname')->equal('vip_code,pids,pid1,id#uuid');
$query->field('id,pid0,pid1,pid2,pids,username,nickname,headimg,order_amount_total,teams_amount_total,teams_amount_direct,teams_amount_indirect,teams_users_total,teams_users_direct,teams_users_indirect,rebate_total,rebate_used,rebate_lock,create_at');
$result = $query->where($map)->order('id desc')->page(true, false, false, 15);
// 统计当前用户所有下属数
$total = DataUser::mk()->where($map)->count();
// 统计当前用户本月下属数
$map[] = ['create_at', 'like', date('Y-m-%')];
$month = DataUser::mk()->where($map)->count();
// 返回结果列表数据及统计
$result['total'] = ['user_total' => $total, 'user_month' => $month];
$this->success('获取我邀请的朋友', $result);
}
/**
* 绑定用户邀请人
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function bindFrom()
{
$data = $this->_vali(['from.require' => '邀请人不能为空']);
[$state, $message] = UserUpgradeService::instance()->bindAgent($this->uuid, $data['from'], 0);
if ($state) {
$this->success($message, UserAdminService::instance()->total($this->uuid));
} else {
$this->error($message, UserAdminService::instance()->total($this->uuid));
}
}
}

View File

@ -1,215 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\DataNewsXCollect;
use app\data\service\NewsService;
/**
* 文章评论内容
* Class News
* @package app\data\controller\api\auth
*/
class News extends Auth
{
/**
* 用户评论内容
* @throws \think\db\exception\DbException
*/
public function addComment()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 4,
'status.value' => 1,
'code.require' => '文章不能为空!',
'reply.require' => '评论不能为空!',
]);
if (DataNewsXCollect::mk()->insert($data) !== false) {
NewsService::instance()->syncNewsTotal($data['code']);
$this->success('添加评论成功!');
} else {
$this->error('添加评论失败!');
}
}
/**
* 获取我的评论
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getComment()
{
$query = DataNewsXCollect::mQuery()->where(['uuid' => $this->uuid, 'type' => 4]);
$result = $query->whereIn('status', [1, 2])->order('id desc')->page(true, false);
NewsService::instance()->buildListByUidAndCode($result);
$this->success('获取评论列表成功', $result);
}
/**
* 删除内容评论
*/
public function delComment()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 4,
'id.require' => '评论编号不能为空!',
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->delete() !== false) {
$this->success('评论删除成功!');
} else {
$this->error('认证删除失败!');
}
}
/**
* 添加内容收藏
* @throws \think\db\exception\DbException
*/
public function addCollect()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 1,
'status.value' => 2,
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->count() > 0) {
$this->success('您已收藏!');
}
if (DataNewsXCollect::mk()->insert($data) !== false) {
NewsService::instance()->syncNewsTotal($data['code']);
$this->success('收藏成功!');
} else {
$this->error('收藏失败!');
}
}
/**
* 取消收藏文章
* @throws \think\db\exception\DbException
*/
public function delCollect()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 1,
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->delete() !== false) {
NewsService::instance()->syncNewsTotal($data['code']);
$this->success('取消收藏成功!');
} else {
$this->error('取消收藏失败!');
}
}
/**
* 获取用户收藏的资讯
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getCollect()
{
$map = ['uuid' => $this->uuid, 'type' => 1];
$query = DataNewsXCollect::mQuery()->where($map);
$result = $query->order('id desc')->page(true, false, false, 15);
NewsService::instance()->buildListByUidAndCode($result['list']);
$this->success('获取收藏记录成功!', $result);
}
/**
* 添加内容点赞
* @throws \think\db\exception\DbException
*/
public function addLike()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 2,
'status.value' => 2,
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->count() > 0) {
$this->success('您已点赞!');
}
if (DataNewsXCollect::mk()->insert($data) !== false) {
NewsService::instance()->syncNewsTotal($data['code']);
$this->success('点赞成功!');
} else {
$this->error('点赞失败!');
}
}
/**
* 取消内容点赞
* @throws \think\db\exception\DbException
*/
public function delLike()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 2,
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->delete() !== false) {
NewsService::instance()->syncNewsTotal($data['code']);
$this->success('取消点赞成功!');
} else {
$this->error('取消点赞失败!');
}
}
/**
* 获取用户收藏的资讯
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getLike()
{
$query = DataNewsXCollect::mQuery();
$query->where(['uuid' => $this->uuid, 'type' => 2, 'status' => 2]);
$result = $query->order('id desc')->page(true, false, false, 15);
NewsService::instance()->buildListByUidAndCode($result['list']);
$this->success('获取点赞记录成功!', $result);
}
/**
* 添加用户的浏览历史
* @throws \think\db\exception\DbException
*/
public function addHistory()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 2,
'status.value' => 2,
'code.require' => '文章编号不能为空!',
]);
DataNewsXCollect::mk()->where($data)->delete();
DataNewsXCollect::mk()->insert($data);
$this->success('添加浏览历史成功!');
}
/**
* 获取用户的浏览历史
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getHistory()
{
$query = DataNewsXCollect::mQuery();
$query->where(['uuid' => $this->uuid, 'type' => 3, 'status' => 2]);
$result = $query->order('id desc')->page(true, false, false, 15);
NewsService::instance()->buildListByUidAndCode($result['list']);
$this->success('获取浏览历史成功!', $result);
}
}

View File

@ -1,493 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\BaseUserPayment;
use app\data\model\DataUser;
use app\data\model\DataUserAddress;
use app\data\model\ShopGoods;
use app\data\model\ShopGoodsItem;
use app\data\model\ShopOrder;
use app\data\model\ShopOrderItem;
use app\data\model\ShopOrderSend;
use app\data\service\ExpressService;
use app\data\service\GoodsService;
use app\data\service\OrderService;
use app\data\service\PaymentService;
use app\data\service\UserAdminService;
use think\admin\extend\CodeExtend;
use think\exception\HttpResponseException;
/**
* 用户订单数据接口
* Class Order
* @package app\data\controller\api\auth
*/
class Order extends Auth
{
/**
* 控制器初始化
*/
protected function initialize()
{
parent::initialize();
if (empty($this->user['status'])) {
$this->error('账户已被冻结,不能操作订单数据哦!');
}
}
/**
* 获取订单列表
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function get()
{
$map = ['uuid' => $this->uuid, 'deleted_status' => 0];
$query = ShopOrder::mQuery()->in('status')->equal('order_no');
$result = $query->where($map)->order('id desc')->page(true, false, false, 20);
if (count($result['list']) > 0) OrderService::instance()->buildData($result['list']);
$this->success('获取订单数据成功!', $result);
}
/**
* 用户创建订单
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add()
{
// 检查用户状态
$this->checkUserStatus();
// 商品规则
$rules = $this->request->post('items', '');
if (empty($rules)) $this->error('商品不能为空');
// 订单数据
[$items, $order, $truckType, $allowPayments] = [[], [], -1, null];
$order['uuid'] = $this->uuid;
$order['order_no'] = CodeExtend::uniqidDate(18, 'N');
// 代理处理
$order['puid1'] = input('from', $this->user['pid1']);
if ($order['puid1'] == $this->uuid) $order['puid1'] = 0;
if ($order['puid1'] > 0) {
$map = ['id' => $order['puid1'], 'status' => 1];
$order['puid2'] = DataUser::mk()->where($map)->value('pid2');
if (is_null($order['puid2'])) $this->error('代理异常');
}
// 订单商品处理
foreach (explode('||', $rules) as $rule) {
[$code, $spec, $count] = explode('@', $rule);
// 商品信息检查
$goodsInfo = ShopGoods::mk()->where(['code' => $code, 'status' => 1, 'deleted' => 0])->find();
$goodsItem = ShopGoodsItem::mk()->where(['status' => 1, 'goods_code' => $code, 'goods_spec' => $spec])->find();
if (empty($goodsInfo) || empty($goodsItem)) $this->error('商品查询异常');
// 商品类型检查
if ($truckType < 0) $truckType = $goodsInfo['truck_type'];
if ($truckType !== $goodsInfo['truck_type']) $this->error('不能混合下单');
// 限制购买数量
if (isset($goods['limit_max_num']) && $goods['limit_max_num'] > 0) {
$map = [['a.uuid', '=', $this->uuid], ['a.status', 'in', [2, 3, 4, 5]], ['b.goods_code', '=', $goods['code']]];
$buys = ShopOrder::mk()->alias('a')->join('store_order_item b', 'a.order_no=b.order_no')->where($map)->sum('b.stock_sales');
if ($buys + $count > $goods['limit_max_num']) $this->error('超过限购数量');
}
// 限制购买身份
if ($goodsInfo['limit_low_vip'] > $this->user['vip_code']) $this->error('用户等级不够');
// 商品库存检查
if ($goodsItem['stock_sales'] + $count > $goodsItem['stock_total']) $this->error('商品库存不足');
// 支付支付处理
$_allowPayments = [];
foreach (str2arr($goodsInfo['payment']) as $code) {
if (is_null($allowPayments) || in_array($code, $allowPayments)) $_allowPayments[] = $code;
}
if (empty($_allowPayments)) {
$this->error('订单无法统一支付');
} else {
$allowPayments = $_allowPayments;
}
// 商品折扣处理
[$discountId, $discountRate] = OrderService::instance()->discount($goodsInfo['discount_id'], $this->user['vip_code']);
// 订单详情处理
$items[] = [
'uuid' => $order['uuid'],
'order_no' => $order['order_no'],
// 商品信息字段
'goods_name' => $goodsInfo['name'],
'goods_cover' => $goodsInfo['cover'],
'goods_payment' => $goodsInfo['payment'],
'goods_sku' => $goodsItem['goods_sku'],
'goods_code' => $goodsItem['goods_code'],
'goods_spec' => $goodsItem['goods_spec'],
// 库存数量处理
'stock_sales' => $count,
// 快递发货数据
'truck_type' => $goodsInfo['truck_type'],
'truck_code' => $goodsInfo['truck_code'],
'truck_number' => $goodsInfo['rebate_type'] > 0 ? $goodsItem['number_express'] * $count : 0,
// 商品费用字段
'price_market' => $goodsItem['price_market'],
'price_selling' => $goodsItem['price_selling'],
'total_market' => $goodsItem['price_market'] * $count,
'total_selling' => $goodsItem['price_selling'] * $count,
// 奖励金额积分
'reward_balance' => $goodsItem['reward_balance'] * $count,
'reward_integral' => $goodsItem['reward_integral'] * $count,
// 绑定用户等级
'vip_name' => $this->user['vip_name'],
'vip_code' => $this->user['vip_code'],
// 是否入会礼包
'vip_entry' => $goodsInfo['vip_entry'],
'vip_upgrade' => $goodsInfo['vip_upgrade'],
// 是否参与返利
'rebate_type' => $goodsInfo['rebate_type'],
'rebate_amount' => $goodsInfo['rebate_type'] > 0 ? $goodsItem['price_selling'] * $count : 0,
// 等级优惠方案
'discount_id' => $discountId,
'discount_rate' => $discountRate,
'discount_amount' => $discountRate * $goodsItem['price_selling'] * $count / 100,
];
}
try {
$order['payment_allow'] = arr2str($allowPayments);
$order['rebate_amount'] = array_sum(array_column($items, 'rebate_amount'));
$order['reward_balance'] = array_sum(array_column($items, 'reward_balance'));
// 订单发货类型
$order['status'] = $truckType ? 1 : 2;
$order['truck_type'] = $truckType;
// 统计商品数量
$order['number_goods'] = array_sum(array_column($items, 'stock_sales'));
$order['number_express'] = array_sum(array_column($items, 'truck_number'));
// 统计商品金额
$order['amount_goods'] = array_sum(array_column($items, 'total_selling'));
// 优惠后的金额
$order['amount_discount'] = array_sum(array_column($items, 'discount_amount'));
// 订单随机免减
$order['amount_reduct'] = OrderService::instance()->getReduct();
if ($order['amount_reduct'] > $order['amount_goods']) {
$order['amount_reduct'] = $order['amount_goods'];
}
// 统计订单金额
$order['amount_real'] = $order['amount_discount'] - $order['amount_reduct'];
$order['amount_total'] = $order['amount_goods'];
// 写入商品数据
$this->app->db->transaction(function () use ($order, $items) {
ShopOrder::mk()->insert($order);
ShopOrderItem::mk()->insertAll($items);
});
// 同步商品库存销量
foreach (array_unique(array_column($items, 'goods_code')) as $code) {
GoodsService::instance()->stock($code);
}
// 触发订单创建事件
$this->app->event->trigger('ShopOrderCreate', $order['order_no']);
// 组装订单商品数据
$order['items'] = $items;
// 返回处理成功数据
$this->success('商品下单成功', $order);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error("商品下单失败,{$exception->getMessage()}");
}
}
/**
* 获取用户折扣
*/
public function discount()
{
$data = $this->_vali(['discount.require' => '折扣编号不能为空!']);
[, $rate] = OrderService::instance()->discount(intval($data['discount']), $this->user['vip_code']);
$this->success('获取用户折扣', ['rate' => $rate]);
}
/**
* 模拟计算订单运费
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function express()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'code.require' => '地址不能为空',
'order_no.require' => '单号不能为空',
]);
// 用户收货地址
$map = ['uuid' => $this->uuid, 'code' => $data['code']];
$addr = DataUserAddress::mk()->where($map)->find();
if (empty($addr)) $this->error('收货地址异常');
// 订单状态检查
$map = ['uuid' => $this->uuid, 'order_no' => $data['order_no']];
$tCount = ShopOrderItem::mk()->where($map)->sum('truck_number');
// 根据地址计算运费
$map = ['status' => 1, 'deleted' => 0, 'order_no' => $data['order_no']];
$tCode = ShopOrderItem::mk()->where($map)->column('truck_code');
[$amount, , , $remark] = ExpressService::instance()->amount($tCode, $addr['province'], $addr['city'], $tCount);
$this->success('计算运费成功', ['amount' => $amount, 'remark' => $remark]);
}
/**
* 订单信息完成
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function perfect()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'code.require' => '地址不能为空',
'order_no.require' => '单号不能为空',
]);
// 用户收货地址
$map = ['uuid' => $this->uuid, 'code' => $data['code'], 'deleted' => 0];
$addr = DataUserAddress::mk()->where($map)->find();
if (empty($addr)) $this->error('收货地址异常');
// 订单状态检查
$map1 = ['uuid' => $this->uuid, 'order_no' => $data['order_no']];
$order = ShopOrder::mk()->where($map1)->whereIn('status', [1, 2])->find();
if (empty($order)) $this->error('不能修改地址');
if (empty($order['truck_type'])) $this->success('无需快递配送', ['order_no' => $order['order_no']]);
// 根据地址计算运费
$map2 = ['status' => 1, 'deleted' => 0, 'order_no' => $data['order_no']];
$tCount = ShopOrderItem::mk()->where($map1)->sum('truck_number');
$tCodes = ShopOrderItem::mk()->where($map2)->column('truck_code');
[$amount, $tCount, $tCode, $remark] = ExpressService::instance()->amount($tCodes, $addr['province'], $addr['city'], $tCount);
// 创建订单发货信息
$express = [
'template_code' => $tCode, 'template_count' => $tCount, 'uuid' => $this->uuid,
'template_remark' => $remark, 'template_amount' => $amount, 'status' => 1,
];
$express['order_no'] = $data['order_no'];
$express['address_code'] = $data['code'];
$express['address_datetime'] = date('Y-m-d H:i:s');
// 收货人信息
$express['address_name'] = $addr['name'];
$express['address_phone'] = $addr['phone'];
$express['address_idcode'] = $addr['idcode'];
$express['address_idimg1'] = $addr['idimg1'];
$express['address_idimg2'] = $addr['idimg2'];
// 收货地址信息
$express['address_province'] = $addr['province'];
$express['address_city'] = $addr['city'];
$express['address_area'] = $addr['area'];
$express['address_content'] = $addr['address'];
ShopOrderSend::mUpdate($express, 'order_no');
data_save(ShopOrderSend::class, $express, 'order_no');
// 组装更新订单数据
$update = ['status' => 2, 'amount_express' => $express['template_amount']];
// 重新计算订单金额
$update['amount_real'] = $order['amount_discount'] + $amount - $order['amount_reduct'];
$update['amount_total'] = $order['amount_goods'] + $amount;
// 支付金额不能为零
if ($update['amount_real'] <= 0) $update['amount_real'] = 0.00;
if ($update['amount_total'] <= 0) $update['amount_total'] = 0.00;
// 更新用户订单数据
$map = ['uuid' => $this->uuid, 'order_no' => $data['order_no']];
if (ShopOrder::mk()->where($map)->update($update) !== false) {
// 触发订单确认事件
$this->app->event->trigger('ShopOrderPerfect', $order['order_no']);
// 返回处理成功数据
$this->success('订单确认成功', ['order_no' => $order['order_no']]);
} else {
$this->error('订单确认失败');
}
}
/**
* 获取支付支付数据
*/
public function channel()
{
$data = $this->_vali(['uuid.value' => $this->uuid, 'order_no.require' => '单号不能为空']);
$payments = ShopOrder::mk()->where($data)->value('payment_allow');
if (empty($payments)) $this->error('获取订单支付参数失败');
// 读取支付通道配置
$query = BaseUserPayment::mk()->where(['status' => 1, 'deleted' => 0]);
$query->whereIn('code', str2arr($payments))->whereIn('type', PaymentService::getTypeApi($this->type));
$result = $query->order('sort desc,id desc')->column('type,code,name,cover,content,remark', 'code');
foreach ($result as &$vo) $vo['content'] = ['voucher_qrcode' => json_decode($vo['content'])->voucher_qrcode ?? ''];
$this->success('获取支付参数数据', array_values($result));
}
/**
* 获取订单支付状态
* @throws \think\db\exception\DbException
*/
public function payment()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'order_no.require' => '单号不能为空',
'order_remark.default' => '',
'payment_code.require' => '支付不能为空',
'payment_back.default' => '', # 支付回跳地址
'payment_image.default' => '', # 支付凭证图片
]);
[$map, $order] = $this->getOrderData();
if ($order['status'] !== 2) $this->error('不能发起支付');
if ($order['payment_status'] > 0) $this->error('已经完成支付');
// 更新订单备注
if (!empty($data['order_remark'])) {
ShopOrder::mk()->where($map)->update([
'order_remark' => $data['order_remark'],
]);
}
// 自动处理用户字段
$openid = '';
if (in_array($this->type, [UserAdminService::API_TYPE_WXAPP, UserAdminService::API_TYPE_WECHAT])) {
$openid = $this->user[UserAdminService::TYPES[$this->type]['auth']] ?? '';
if (empty($openid)) $this->error("发起支付失败");
}
try {
// 返回订单数据及支付发起参数
$type = $order['amount_real'] <= 0 ? 'empty' : $data['payment_code'];
$param = PaymentService::instance($type)->create($openid, $order['order_no'], $order['amount_real'], '商城订单支付', '', $data['payment_back'], $data['payment_image']);
$this->success('获取支付参数', ['order' => ShopOrder::mk()->where($map)->find() ?: new \stdClass(), 'param' => $param]);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 主动取消未支付的订单
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function cancel()
{
[$map, $order] = $this->getOrderData();
if (in_array($order['status'], [1, 2, 3])) {
$result = ShopOrder::mk()->where($map)->update([
'status' => 0,
'cancel_status' => 1,
'cancel_remark' => '用户主动取消订单',
'cancel_datetime' => date('Y-m-d H:i:s'),
]);
if ($result !== false && OrderService::instance()->stock($order['order_no'])) {
// 触发订单取消事件
$this->app->event->trigger('ShopOrderCancel', $order['order_no']);
// 返回处理成功数据
$this->success('订单取消成功');
} else {
$this->error('订单取消失败');
}
} else {
$this->error('订单不可取消');
}
}
/**
* 用户主动删除已取消的订单
* @throws \think\db\exception\DbException
*/
public function remove()
{
[$map, $order] = $this->getOrderData();
if (empty($order)) $this->error('读取订单失败');
if (in_array($order['status'], [0])) {
$result = ShopOrder::mk()->where($map)->update([
'status' => 0,
'deleted_status' => 1,
'deleted_remark' => '用户主动删除订单',
'deleted_datetime' => date('Y-m-d H:i:s'),
]);
if ($result !== false) {
// 触发订单删除事件
$this->app->event->trigger('ShopOrderRemove', $order['order_no']);
// 返回处理成功数据
$this->success('订单删除成功');
} else {
$this->error('订单删除失败');
}
} else {
$this->error('订单不可删除');
}
}
/**
* 订单确认收货
* @throws \think\db\exception\DbException
*/
public function confirm()
{
[$map, $order] = $this->getOrderData();
if (in_array($order['status'], [5])) {
if (ShopOrder::mk()->where($map)->update(['status' => 6]) !== false) {
// 触发订单确认事件
$this->app->event->trigger('ShopOrderConfirm', $order['order_no']);
// 返回处理成功数据
$this->success('订单确认成功');
} else {
$this->error('订单确认失败');
}
} else {
$this->error('订单确认失败');
}
}
/**
* 获取输入订单
* @return array [map, order]
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getOrderData(): array
{
$map = $this->_vali([
'uuid.value' => $this->uuid,
'order_no.require' => '单号不能为空',
]);
$order = ShopOrder::mk()->where($map)->find();
if (empty($order)) $this->error('读取订单失败');
return [$map, $order];
}
/**
* 订单状态统计
*/
public function total()
{
$data = ['t0' => 0, 't1' => 0, 't2' => 0, 't3' => 0, 't4' => 0, 't5' => 0, 't6' => 0];
$query = ShopOrder::mk()->where(['uuid' => $this->uuid, 'deleted_status' => 0]);
foreach ($query->field('status,count(1) count')->group('status')->cursor() as $item) {
$data["t{$item['status']}"] = $item['count'];
}
$this->success('获取订单统计', $data);
}
/**
* 物流追踪查询
*/
public function track()
{
try {
$data = $this->_vali(['code.require' => '快递不能为空', 'number.require' => '单号不能为空']);
$result = ExpressService::instance()->query($data['code'], $data['number']);
empty($result['code']) ? $this->error($result['info']) : $this->success('快递追踪信息', $result);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
}

View File

@ -1,58 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\BaseUserUpgrade;
use app\data\model\DataUserRebate;
use app\data\service\RebateService;
/**
* 用户返利管理
* Class Rebate
* @package app\data\controller\api\auth
*/
class Rebate extends Auth
{
/**
* 获取用户返利记录
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function get()
{
$date = trim(input('date', date('Y-m')), '-');
[$map, $year] = [['uuid' => $this->uuid], substr($date, 0, 4)];
$query = DataUserRebate::mQuery()->where($map)->equal('type,status')->whereLike('date', "{$date}%");
$this->success('获取返利统计', array_merge($query->order('id desc')->page(true, false, false, 10), [
'total' => [
'年度' => DataUserRebate::mQuery()->where($map)->equal('type,status')->whereLike('date', "{$year}%")->db()->sum('amount'),
'月度' => DataUserRebate::mQuery()->where($map)->equal('type,status')->whereLike('date', "{$date}%")->db()->sum('amount'),
],
]));
}
/**
* 获取我的奖励
*/
public function prize()
{
[$map, $data] = [['number' => $this->user['vip_code']], []];
$prizes = DataUserRebate::mk()->group('name')->column('name');
$rebate = BaseUserUpgrade::mk()->where($map)->value('rebate_rule', '');
$codemap = array_merge($prizes, str2arr($rebate));
foreach (RebateService::PRIZES as $prize) {
if (in_array($prize['code'], $codemap)) $data[] = $prize;
}
$this->success('获取我的奖励', $data);
}
/**
* 获取奖励配置
*/
public function prizes()
{
$this->success('获取系统奖励', array_values(RebateService::PRIZES));
}
}

View File

@ -1,162 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\DataUserTransfer;
use app\data\service\UserRebateService;
use app\data\service\UserTransferService;
use think\admin\extend\CodeExtend;
/**
* 用户提现接口
* Class Transfer
* @package app\data\controller\api\auth
*/
class Transfer extends Auth
{
/**
* 提交提现处理
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add()
{
// 检查用户状态
$this->checkUserStatus();
// 接收输入数据
$data = $this->_vali([
'type.require' => '提现方式不能为空!',
'amount.require' => '提现金额不能为空!',
'remark.default' => '用户提交提现申请!',
]);
$state = UserTransferService::instance()->config('status');
if (empty($state)) $this->error('提现还没有开启!');
$transfers = UserTransferService::instance()->config('transfer');
if (empty($transfers[$data['type']]['state'])) $this->error('提现方式已停用!');
// 提现数据补充
$data['uuid'] = $this->uuid;
$data['date'] = date('Y-m-d');
$data['code'] = CodeExtend::uniqidDate(20, 'T');
// 提现状态处理
if (empty($transfers[$data['type']]['state']['audit'])) {
$data['status'] = 1;
$data['audit_status'] = 0;
} else {
$data['status'] = 3;
$data['audit_status'] = 1;
$data['audit_remark'] = '提现免审核';
$data['audit_datetime'] = date('Y-m-d H:i:s');
}
// 扣除手续费
$chargeRate = floatval(UserTransferService::instance()->config('charge'));
$data['charge_rate'] = $chargeRate;
$data['charge_amount'] = $chargeRate * $data['amount'] / 100;
// 检查可提现余额
[$total, $count] = UserRebateService::instance()->amount($this->uuid);
if ($total - $count < $data['amount']) $this->error('可提现余额不足!');
// 提现方式处理
if (in_array($data['type'], ['alipay_account'])) {
$data = array_merge($data, $this->_vali([
'alipay_user.require' => '开户姓名不能为空!',
'alipay_code.require' => '支付账号不能为空!',
]));
} elseif (in_array($data['type'], ['wechat_qrcode', 'alipay_qrcode'])) {
$data = array_merge($data, $this->_vali([
'qrcode.require' => '收款码不能为空!',
]));
} elseif (in_array($data['type'], ['wechat_banks', 'transfer_banks'])) {
$data = array_merge($data, $this->_vali([
'bank_wseq.require' => '银行编号不能为空!',
'bank_name.require' => '银行名称不能为空!',
'bank_user.require' => '开户账号不能为空!',
'bank_bran.require' => '银行分行不能为空!',
'bank_code.require' => '银行卡号不能为空!',
]));
} elseif (!in_array($data['type'], ['wechat_wallet'])) {
$this->error('转账方式不存在!');
}
// 当日提现次数限制
$map = ['uuid' => $this->uuid, 'type' => $data['type'], 'date' => $data['date']];
$count = DataUserTransfer::mk()->where($map)->count();
if ($count >= $transfers[$data['type']]['dayNumber']) $this->error("当日提现次数受限");
// 提现金额范围控制
if ($transfers[$data['type']]['minAmount'] > $data['amount']) {
$this->error("不能少于{$transfers[$data['type']]['minAmount']}");
}
if ($transfers[$data['type']]['maxAmount'] < $data['amount']) {
$this->error("不能大于{$transfers[$data['type']]['maxAmount']}");
}
// 写入用户提现数据
if (DataUserTransfer::mk()->insert($data) !== false) {
UserRebateService::instance()->amount($this->uuid);
$this->success('提现申请成功');
} else {
$this->error('提现申请失败');
}
}
/**
* 用户提现记录
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function get()
{
$query = DataUserTransfer::mQuery()->where(['uuid' => $this->uuid]);
$result = $query->like('date,code')->in('status')->order('id desc')->page(true, false, false, 10);
// 统计历史数据
$map = [['uuid', '=', $this->uuid], ['status', '>', 0]];
[$total, $count, $locks] = UserRebateService::instance()->amount($this->uuid);
$this->success('获取提现成功', array_merge($result, [
'total' => [
'锁定' => $locks,
'可提' => $total - $count,
'上月' => DataUserTransfer::mk()->where($map)->whereLike('date', date("Y-m-%", strtotime('-1 month')))->sum('amount'),
'本月' => DataUserTransfer::mk()->where($map)->whereLike('date', date("Y-m-%"))->sum('amount'),
'全年' => DataUserTransfer::mk()->where($map)->whereLike('date', date("Y-%"))->sum('amount'),
],
]));
}
/**
* 用户取消提现
*/
public function cancel()
{
$data = $this->_vali(['uuid.value' => $this->uuid, 'code.require' => '单号不能为空!']);
DataUserTransfer::mk()->where($data)->whereIn('status', [1, 2, 3])->update([
'status' => 0, 'change_time' => date("Y-m-d H:i:s"), 'change_desc' => '用户主动取消提现',
]);
UserRebateService::instance()->amount($this->uuid);
$this->success('取消提现成功');
}
/**
* 用户确认提现
*/
public function confirm()
{
$data = $this->_vali(['uuid.value' => $this->uuid, 'code.require' => '单号不能为空!']);
DataUserTransfer::mk()->where($data)->whereIn('status', [4])->update([
'status' => 5, 'change_time' => date("Y-m-d H:i:s"), 'change_desc' => '用户主动确认收款',
]);
UserRebateService::instance()->amount($this->uuid);
$this->success('确认收款成功');
}
/**
* 获取用户提现配置
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function config()
{
$data = UserTransferService::instance()->config();
$data['banks'] = UserTransferService::instance()->banks();
$this->success('获取用户提现配置', $data);
}
}

View File

@ -1,153 +0,0 @@
<?php
namespace app\data\controller\base;
use think\admin\Controller;
/**
* 应用参数配置
* Class Config
* @package app\data\controller\base
*/
class Config extends Controller
{
/**
* 页面类型
* @var array
*/
protected $pageTypes = [
'关于我们' => '关于我们',
'用户协议' => '用户协议',
];
/**
* 微信小程序配置
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function wxapp()
{
$this->title = '微信小程序配置';
$this->__sysconf('wxapp');
}
/**
* 邀请二维码设置
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function cropper()
{
$this->title = '邀请二维码设置';
$this->skey = 'cropper';
$this->__sysdata('cropper');
}
/**
* 内容页面管理
* @auth true
* @menu true
*/
public function pageHome()
{
$this->title = '内容页面管理';
$this->fetch('page_home');
}
/**
* 内容页面编辑
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function pageEdit()
{
$this->skey = input('type') ?: $this->pageTypes[0];
$this->title = '编辑' . $this->pageTypes[$this->skey] ?? '';
$this->__sysdata('page_form', 'javascript:history.back()');
}
/**
* 首页推荐位管理
* @menu true
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function iconHome()
{
$this->skey = 'IconHome';
$this->title = '首页推荐位管理';
$this->__sysdata('slider');
}
/**
* 首页轮播图片
* @menu true
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function sliderHome()
{
$this->skey = 'SliderHome';
$this->title = '首页轮播图片';
$this->__sysdata('slider');
}
/**
* 显示并保存配置
* @param string $template 模板文件名称
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function __sysconf(string $template)
{
if ($this->request->isGet()) {
$this->fetch($template);
}
if ($this->request->isPost()) {
$data = $this->request->post();
foreach ($data as $k => $v) sysconf($k, $v);
$this->success('配置保存成功!');
}
}
/**
* 显示并保存数据
* @param string $template 模板文件
* @param string $history 跳转处理
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function __sysdata(string $template, $history = '')
{
if ($this->request->isGet()) {
$this->data = sysdata($this->skey);
$this->fetch($template);
}
if ($this->request->isPost()) {
if (is_string(input('data'))) {
$data = json_decode(input('data'), true) ?: [];
} else {
$data = $this->request->post();
}
if (sysdata($this->skey, $data) !== false) {
$this->success('内容保存成功!', $history);
} else {
$this->error('内容保存失败,请稍候再试!');
}
}
}
}

View File

@ -1,107 +0,0 @@
<?php
namespace app\data\controller\base;
use app\data\model\BaseUserDiscount;
use app\data\service\UserUpgradeService;
use think\admin\Controller;
/**
* 折扣方案管理
* Class Discount
* @package app\data\controller\base
*/
class Discount extends Controller
{
/**
* 折扣方案管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '折扣方案管理';
$query = BaseUserDiscount::mQuery();
$query->where(['deleted' => 0])->order('sort desc,id desc')->page();
}
/**
* 数据列表处理
* @param array $data
*/
protected function _page_filter(array &$data)
{
foreach ($data as &$vo) {
$vo['items'] = json_decode($vo['items'], true);
}
}
/**
* 添加折扣方案
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add()
{
BaseUserDiscount::mForm('form');
}
/**
* 编辑折扣方案
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function edit()
{
BaseUserDiscount::mForm('form');
}
/**
* 表单数据处理
* @param array $vo
*/
protected function _form_filter(array &$vo)
{
if ($this->request->isPost()) {
$rule = [];
foreach ($vo as $k => $v) if (stripos($k, '_level_') !== false) {
[, $level] = explode('_level_', $k);
$rule[] = ['level' => $level, 'discount' => $v];
}
$vo['items'] = json_encode($rule, JSON_UNESCAPED_UNICODE);
} else {
$this->levels = UserUpgradeService::instance()->levels();
if (empty($this->levels)) $this->error('未配置用户等级!');
if (!empty($vo['items'])) foreach (json_decode($vo['items'], true) as $item) {
$vo["_level_{$item['level']}"] = $item['discount'];
}
}
}
/**
* 修改折扣方案状态
* @auth true
* @throws \think\db\exception\DbException
*/
public function state()
{
BaseUserDiscount::mSave();
}
/**
* 删除折扣方案配置
* @auth true
* @throws \think\db\exception\DbException
*/
public function remove()
{
BaseUserDiscount::mDelete();
}
}

View File

@ -1,80 +0,0 @@
<?php
namespace app\data\controller\base;
use app\data\model\BaseUserMessage;
use think\admin\Controller;
/**
* 系统通知管理
* Class Message
* @package app\data\controller\base
*/
class Message extends Controller
{
/**
* 系统通知管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '系统通知管理';
$query = BaseUserMessage::mQuery();
$query->like('name')->equal('status')->dateBetween('create_at');
$query->where(['deleted' => 0])->order('sort desc,id desc')->page();
}
/**
* 添加系统通知
* @auth true
*/
public function add()
{
BaseUserMessage::mForm('form');
}
/**
* 编辑系统通知
* @auth true
*/
public function edit()
{
BaseUserMessage::mForm('form');
}
/**
* 表单结果处理
* @param boolean $state
*/
protected function _form_result(bool $state)
{
if ($state) {
$this->success('内容保存成功!', 'javascript:history.back()');
}
}
/**
* 修改通知状态
* @auth true
*/
public function state()
{
BaseUserMessage::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除系统通知
* @auth true
*/
public function remove()
{
BaseUserMessage::mDelete();
}
}

View File

@ -1,118 +0,0 @@
<?php
namespace app\data\controller\base;
use app\data\model\BaseUserPayment;
use app\data\service\PaymentService;
use app\data\service\UserAdminService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
/**
* 支付通道管理
* Class Payment
* @package app\data\controller\base
*/
class Payment extends Controller
{
/**
* 支付通道类型
* @var array
*/
protected $types = PaymentService::TYPES;
/**
* 支付通道管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '支付通道管理';
$query = BaseUserPayment::mQuery();
$query->where(['deleted' => 0])->order('sort desc,id desc');
$query->like('name,code')->equal('type,status')->dateBetween('create_at')->page();
}
/**
* 添加支付通道
* @auth true
*/
public function add()
{
$this->title = '添加支付通道';
BaseUserPayment::mForm('form');
}
/**
* 编辑支付通道
* @auth true
*/
public function edit()
{
$this->title = '编辑支付通道';
BaseUserPayment::mForm('form');
}
/**
* 数据表单处理
* @param array $data
*/
protected function _form_filter(array &$data)
{
if (empty($data['code'])) {
$data['code'] = CodeExtend::uniqidNumber(20, 'M');
}
if ($this->request->isGet()) {
$this->payments = [];
foreach ($this->types as $k => $vo) {
$allow = [];
foreach ($vo['bind'] as $api) if (isset(UserAdminService::TYPES[$api])) {
$allow[$api] = UserAdminService::TYPES[$api]['name'];
}
if (empty($allow)) continue;
$this->payments[$k] = array_merge($vo, ['allow' => join('、', $allow)]);
}
$data['content'] = json_decode($data['content'] ?? '[]', true) ?: [];
} else {
if (empty($data['type'])) $this->error('请选择支付通道并配置参数!');
if (empty($data['cover'])) $this->error('请上传支付方式图标!');
$data['content'] = json_encode($this->request->post() ?: [], JSON_UNESCAPED_UNICODE);
}
}
/**
* 表单结果处理
* @param boolean $state
*/
protected function _form_result(bool $state)
{
if ($state) {
$this->success('支付通道保存成功!', 'javascript:history.back()');
}
}
/**
* 修改通道状态
* @auth true
*/
public function state()
{
BaseUserPayment::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除支付通道
* @auth true
*/
public function remove()
{
BaseUserPayment::mDelete();
}
}

View File

@ -1,165 +0,0 @@
<?php
namespace app\data\controller\base;
use app\data\model\BaseUserUpgrade;
use app\data\service\RebateService;
use think\admin\Controller;
/**
* 用户等级管理
* Class Upgrade
* @package app\data\controller\base
*/
class Upgrade extends Controller
{
/**
* 用户等级管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '用户等级管理';
BaseUserUpgrade::mQuery()->order('number asc')->page();
}
/**
* 数据列表处理
* @param array $data
*/
protected function _page_filter(array &$data)
{
foreach ($data as &$vo) {
$vo['rebate_rule'] = str2arr($vo['rebate_rule']);
foreach ($vo['rebate_rule'] as &$v) {
$v = RebateService::instance()->name($v);
}
}
}
/**
* 添加用户等级
* @auth true
*/
public function add()
{
BaseUserUpgrade::mForm('form');
}
/**
* 编辑用户等级
* @auth true
*/
public function edit()
{
BaseUserUpgrade::mForm('form');
}
/**
* 表单数据处理
* @param array $vo
*/
protected function _form_filter(array &$vo)
{
if ($this->request->isGet()) {
$this->prizes = RebateService::PRIZES;
if (!isset($vo['number'])) {
$vo['number'] = BaseUserUpgrade::mk()->order('number desc')->value('number', -1) + 1;
}
$vo['rebate_rule'] = str2arr($vo['rebate_rule'] ?? '');
} else {
$vo['utime'] = time();
$vo['rebate_rule'] = arr2str($vo['rebate_rule'] ?? []);
// 用户升级条件开关
$vo['goods_vip_status'] = isset($vo['goods_vip_status']) ? 1 : 0;
$vo['teams_users_status'] = isset($vo['teams_users_status']) ? 1 : 0;
$vo['teams_direct_status'] = isset($vo['teams_direct_status']) ? 1 : 0;
$vo['teams_indirect_status'] = isset($vo['teams_indirect_status']) ? 1 : 0;
$vo['order_amount_status'] = isset($vo['order_amount_status']) ? 1 : 0;
// 根据数量判断状态
$vo['teams_users_status'] = intval($vo['teams_users_status'] && $vo['teams_users_number'] > 0);
$vo['teams_direct_status'] = intval($vo['teams_direct_status'] && $vo['teams_direct_number'] > 0);
$vo['teams_indirect_status'] = intval($vo['teams_indirect_status'] && $vo['teams_indirect_number'] > 0);
$vo['order_amount_status'] = intval($vo['order_amount_status'] && $vo['order_amount_number'] > 0);
// 检查升级条件配置
$count = 0;
foreach ($vo as $k => $v) if (is_numeric(stripos($k, '_status'))) $count += $v;
if (empty($count) && $vo['number'] > 0) $this->error('升级条件不能为空!');
}
}
/**
* 表单结果处理
* @param boolean $state
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function _form_result(bool $state)
{
if ($state) {
if (input('old_number', 100) <= input('number', 0)) {
$order = 'number asc,utime asc';
} else {
$order = 'number asc,utime desc';
}
foreach (BaseUserUpgrade::mk()->order($order)->select() as $number => $upgrade) {
$upgrade->save(['number' => $number]);
}
}
}
/**
* 重算用户等级
* @auth true
*/
public function sync()
{
$this->_queue('重新计算所有用户等级', 'xdata:UserUpgrade');
}
/**
* 修改等级状态
* @auth true
*/
public function state()
{
BaseUserUpgrade::mSave();
}
/**
* 删除用户等级
* @auth true
*/
public function remove()
{
BaseUserUpgrade::mDelete();
}
/**
* 状态变更处理
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _save_result()
{
$this->_form_result(true);
}
/**
* 删除结果处理
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _delete_result()
{
$this->_form_result(true);
}
}

View File

@ -1,102 +0,0 @@
<?php
namespace app\data\controller\base\postage;
use app\data\model\BasePostageCompany;
use app\data\service\ExpressService;
use think\admin\Controller;
use think\exception\HttpResponseException;
/**
* 快递公司管理
* Class Company
* @package app\data\controller\base\postage
*/
class Company extends Controller
{
/**
* 快递公司管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '快递公司管理';
// 加载对应数据
$map = ['deleted' => 0];
$this->type = input('get.type', 'index');
if ($this->type === 'index') $map['status'] = 1;
if ($this->type === 'recycle') $map['status'] = 0;
// 列表显示分页
$query = BasePostageCompany::mQuery();
$query->like('name,code')->equal('status')->dateBetween('craete_at');
$query->where($map)->order('sort desc,id desc')->page();
}
/**
* 添加快递公司
* @auth true
*/
public function add()
{
$this->title = '添加快递公司';
BasePostageCompany::mForm('form');
}
/**
* 编辑快递公司
* @auth true
*/
public function edit()
{
$this->title = '编辑快递公司';
BasePostageCompany::mForm('form');
}
/**
* 修改快递公司状态
* @auth true
*/
public function state()
{
BasePostageCompany::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除快递公司
* @auth true
*/
public function remove()
{
BasePostageCompany::mDelete();
}
/**
* 同步快递公司
* @auth true
*/
public function sync()
{
try {
$result = ExpressService::instance()->company();
if (empty($result['code'])) $this->error($result['info']);
foreach ($result['data'] as $vo) data_save(BasePostageCompany::class, [
'code_1' => $vo['code_1'], 'code_2' => $vo['code_2'],
'code_3' => $vo['code_3'], 'name' => $vo['title'], 'deleted' => 0,
], 'code_1');
$this->success('同步快递公司成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error('同步快递公司数据失败!');
}
}
}

View File

@ -1,117 +0,0 @@
<?php
namespace app\data\controller\base\postage;
use app\data\model\BasePostageRegion;
use app\data\model\BasePostageTemplate;
use app\data\service\ExpressService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
/**
* 邮费模板管理
* Class Template
* @package app\data\controller\base\postage
*/
class Template extends Controller
{
/**
* 快递邮费模板
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '快递邮费模板';
$query = BasePostageTemplate::mQuery();
$query->like('code,name')->equal('status')->dateBetween('create_at');
$query->where(['deleted' => 0])->order('sort desc,id desc')->page();
}
/**
* 配送区域管理
* @auth true
*/
public function region()
{
if ($this->request->isGet()) {
$this->title = '配送区域管理';
$this->citys = ExpressService::instance()->region(3, null);
$this->fetch('form_region');
} else {
$data = $this->_vali(['nos.default' => '', 'oks.default' => '']);
if ($data['nos']) BasePostageRegion::mk()->whereIn('id', str2arr($data['nos']))->update(['status' => 0]);
if ($data['oks']) BasePostageRegion::mk()->whereIn('id', str2arr($data['oks']))->update(['status' => 1]);
$this->success('修改配送区域成功!', 'javascript:history.back()');
}
}
/**
* 添加配送邮费模板
* @auth true
*/
public function add()
{
$this->title = '添加配送邮费模板';
BasePostageTemplate::mForm('form', 'code');
}
/**
* 编辑配送邮费模板
* @auth true
*/
public function edit()
{
$this->title = '编辑配送邮费模板';
BasePostageTemplate::mForm('form', 'code');
}
/**
* 表单数据处理
* @param array $data
*/
protected function _form_filter(array &$data)
{
if (empty($data['code'])) {
$data['code'] = CodeExtend::uniqidDate(12, 'T');
}
if ($this->request->isGet()) {
$this->citys = ExpressService::instance()->region(2, 1);
}
}
/**
* 表单结果处理
* @param boolean $result
*/
protected function _form_result(bool $result)
{
if ($result && $this->request->isPost()) {
$this->success('邮费模板保存成功!', 'javascript:history.back()');
}
}
/**
* 启用或禁用邮费模板
* @auth true
*/
public function state()
{
BasePostageTemplate::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]), 'code');
}
/**
* 删除邮费模板
* @auth true
*/
public function remove()
{
BasePostageTemplate::mDelete('code');
}
}

View File

@ -1,129 +0,0 @@
<?php
namespace app\data\controller\news;
use app\data\model\DataNewsItem;
use app\data\model\DataNewsMark;
use app\data\service\NewsService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
/**
* 文章内容管理
* Class Item
* @package app\data\controller\news
*/
class Item extends Controller
{
/**
* 文章内容管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '文章内容管理';
$query = DataNewsItem::mQuery();
$query->like('mark,name')->dateBetween('create_at');
$query->where(['deleted' => 0])->order('sort desc,id desc')->page();
}
/**
* 文章内容选择器
* @login true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function select()
{
$query = DataNewsItem::mQuery();
$query->equal('status')->like('name')->dateBetween('create_at');
$query->where(['deleted' => 0])->order('sort desc,id desc')->page();
}
/**
* 列表数据处理
* @param array $data
*/
protected function _page_filter(array &$data)
{
NewsService::instance()->buildData($data);
}
/**
* 添加文章内容
* @auth true
*/
public function add()
{
$this->title = '添加文章内容';
DataNewsItem::mForm('form');
}
/**
* 编辑文章内容
* @auth true
*/
public function edit()
{
$this->title = '编辑文章内容';
DataNewsItem::mForm('form');
}
/**
* 表单数据处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _form_filter(array &$data)
{
if (empty($data['code'])) {
$data['code'] = CodeExtend::uniqidNumber(20, 'A');
}
if ($this->request->isGet()) {
$model = DataNewsMark::mk()->where(['status' => 1, 'deleted' => 0]);
$this->marks = $model->order('sort desc,id desc')->select()->toArray();
$data['mark'] = str2arr($data['mark'] ?? '');
} else {
$data['mark'] = arr2str($data['mark'] ?? []);
}
}
/**
* 表单结果处理
* @param boolean $state
*/
protected function _form_result(bool $state)
{
if ($state) {
$this->success('文章内容保存成功!', 'javascript:history.back()');
}
}
/**
* 修改文章状态
* @auth true
*/
public function state()
{
DataNewsItem::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除文章内容
* @auth true
*/
public function remove()
{
DataNewsItem::mDelete();
}
}

View File

@ -1,68 +0,0 @@
<?php
namespace app\data\controller\news;
use app\data\model\DataNewsMark;
use think\admin\Controller;
/**
* 文章标签管理
* Class Mark
* @package app\data\controller\news
*/
class Mark extends Controller
{
/**
* 文章标签管理
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '文章标签管理';
$query = DataNewsMark::mQuery();
$query->like('name')->equal('status')->dateBetween('create_at');
$query->where(['deleted' => 0])->order('sort desc,id desc')->page();
}
/**
* 添加文章标签
* @auth true
*/
public function add()
{
DataNewsMark::mForm('form');
}
/**
* 编辑文章标签
* @auth true
*/
public function edit()
{
DataNewsMark::mForm('form');
}
/**
* 修改文章标签状态
* @auth true
*/
public function state()
{
DataNewsMark::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除文章标签
* @auth true
*/
public function remove()
{
DataNewsMark::mDelete();
}
}

View File

@ -1,101 +0,0 @@
<?php
namespace app\data\controller\shop;
use app\data\model\ShopGoodsCate;
use think\admin\Controller;
use think\admin\extend\DataExtend;
/**
* 商品分类管理
* Class Cate
* @package app\data\controller\shop
*/
class Cate extends Controller
{
/**
* 商品分类管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = "商品分类管理";
$query = ShopGoodsCate::mQuery()->like('name')->dateBetween('create_at');
$query->equal('status')->where(['deleted' => 0])->order('sort desc,id desc')->page(false);
}
/**
* 列表数据处理
* @param array $data
*/
protected function _index_page_filter(array &$data)
{
foreach ($data as &$vo) {
$vo['ids'] = join(',', DataExtend::getArrSubIds($data, $vo['id']));
}
$data = DataExtend::arr2table($data);
}
/**
* 添加商品分类
* @auth true
*/
public function add()
{
ShopGoodsCate::mForm('form');
}
/**
* 编辑商品分类
* @auth true
*/
public function edit()
{
ShopGoodsCate::mForm('form');
}
/**
* 表单数据处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _form_filter(array &$data)
{
if ($this->request->isGet()) {
$data['pid'] = intval($data['pid'] ?? input('pid', '0'));
$cates = ShopGoodsCate::mk()->where(['deleted' => 0])->order('sort desc,id desc')->select()->toArray();
$this->cates = DataExtend::arr2table(array_merge($cates, [['id' => '0', 'pid' => '-1', 'name' => '顶部分类']]));
if (isset($data['id'])) foreach ($this->cates as $cate) if ($cate['id'] === $data['id']) $data = $cate;
foreach ($this->cates as $key => $cate) if ((isset($data['spt']) && $data['spt'] <= $cate['spt'])) {
unset($this->cates[$key]);
}
}
}
/**
* 修改商品分类状态
* @auth true
*/
public function state()
{
ShopGoodsCate::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除商品分类
* @auth true
*/
public function remove()
{
ShopGoodsCate::mDelete();
}
}

View File

@ -1,258 +0,0 @@
<?php
namespace app\data\controller\shop;
use app\data\model\BaseUserDiscount;
use app\data\model\BaseUserPayment;
use app\data\model\ShopGoods;
use app\data\model\ShopGoodsItem;
use app\data\model\ShopGoodsStock;
use app\data\service\ExpressService;
use app\data\service\GoodsService;
use app\data\service\UserUpgradeService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
/**
* 商品数据管理
* Class Goods
* @package app\data\controller\shop
*/
class Goods extends Controller
{
/**
* 最大分类等级
* @var integer
*/
protected $cateLevel;
/**
* 商品数据管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '商品数据管理';
$query = ShopGoods::mQuery();
// 加载对应数据
$this->type = $this->request->get('type', 'index');
if ($this->type === 'index') $query->where(['deleted' => 0]);
elseif ($this->type === 'recycle') $query->where(['deleted' => 1]);
else $this->error("无法加载 {$this->type} 数据列表!");
// 列表排序并显示
$query->like('code,name')->like('marks,cateids', ',');
$query->equal('status,vip_entry,truck_type,rebate_type')->order('sort desc,id desc')->page();
}
/**
* 商品选择器
* @login true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function select()
{
$query = ShopGoods::mQuery();
$query->equal('status')->like('code,name,marks')->in('cateids');
$query->where(['deleted' => 0])->order('sort desc,id desc')->page();
}
/**
* 数据列表处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _page_filter(array &$data)
{
$this->marks = GoodsService::instance()->getMarkData();
$this->cates = GoodsService::instance()->getCateTree('arr2table');
GoodsService::instance()->bindData($data, false);
}
/**
* 添加商品数据
* @auth true
*/
public function add()
{
$this->mode = 'add';
$this->title = '添加商品数据';
ShopGoods::mForm('form', 'code');
}
/**
* 编辑商品数据
* @auth true
*/
public function edit()
{
$this->mode = 'edit';
$this->title = '编辑商品数据';
ShopGoods::mForm('form', 'code');
}
/**
* 复制编辑商品
* @auth true
*/
public function copy()
{
$this->mode = 'copy';
$this->title = '复制编辑商品';
ShopGoods::mForm('form', 'code');
}
/**
* 表单数据处理
* @param array $data
*/
protected function _copy_form_filter(array &$data)
{
if ($this->request->isPost()) {
$data['code'] = CodeExtend::uniqidNumber(20, 'G');
}
}
/**
* 表单数据处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _form_filter(array &$data)
{
if (empty($data['code'])) {
$data['code'] = CodeExtend::uniqidNumber(20, 'G');
}
if ($this->request->isGet()) {
$data['marks'] = str2arr($data['marks'] ?? '');
$data['payment'] = str2arr($data['payment'] ?? '');
$data['cateids'] = str2arr($data['cateids'] ?? '');
// 其他表单数据
$this->marks = GoodsService::instance()->getMarkData();
$this->cates = GoodsService::instance()->getCateData();
$this->trucks = ExpressService::instance()->templates();
$this->upgrades = UserUpgradeService::instance()->levels();
$this->payments = BaseUserPayment::mk()->where(['status' => 1, 'deleted' => 0])->order('sort desc,id desc')->column('type,code,name', 'code');
$this->discounts = BaseUserDiscount::mk()->where(['status' => 1, 'deleted' => 0])->order('sort desc,id desc')->column('id,name,items', 'id');
// 商品规格处理
$fields = 'goods_sku `sku`,goods_code,goods_spec `key`,price_selling `selling`,price_market `market`,number_virtual `virtual`,number_express `express`,reward_balance `balance`,reward_integral `integral`,status';
$data['data_items'] = json_encode(ShopGoodsItem::mk()->where(['goods_code' => $data['code']])->column($fields, 'goods_spec'), JSON_UNESCAPED_UNICODE);
} elseif ($this->request->isPost()) {
if (empty($data['cover'])) $this->error('商品图片不能为空!');
if (empty($data['slider'])) $this->error('轮播图片不能为空!');
if (empty($data['payment'])) $this->error('支付方式不能为空!');
// 商品规格保存
[$data['price_market'], $data['price_selling']] = [0, 0];
[$count, $items] = [0, array_column(json_decode($data['data_items'], true), 0)];
foreach ($items as $item) if ($item['status'] > 0) {
if ($data['price_market'] === 0 || $data['price_market'] > $item['market']) $data['price_market'] = $item['market'];
if ($data['price_selling'] === 0 || $data['price_selling'] > $item['selling']) $data['price_selling'] = $item['selling'];
$count++;
}
if (empty($count)) $this->error('无效的的商品价格信息!');
$data['marks'] = arr2str($data['marks'] ?? []);
$data['payment'] = arr2str($data['payment'] ?? []);
ShopGoodsItem::mk()->where(['goods_code' => $data['code']])->update(['status' => 0]);
foreach ($items as $item) data_save(ShopGoodsItem::class, [
'goods_sku' => $item['sku'],
'goods_spec' => $item['key'],
'goods_code' => $data['code'],
'price_market' => $item['market'],
'price_selling' => $item['selling'],
'number_virtual' => $item['virtual'],
'number_express' => $item['express'],
'reward_balance' => $item['balance'],
'reward_integral' => $item['integral'],
'status' => $item['status'] ? 1 : 0,
], 'goods_spec', [
'goods_code' => $data['code'],
]);
}
}
/**
* 表单结果处理
* @param boolean $result
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _form_result(bool $result)
{
if ($result && $this->request->isPost()) {
GoodsService::instance()->stock(input('code'));
$this->success('商品编辑成功!', 'javascript:history.back()');
}
}
/**
* 商品库存入库
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function stock()
{
$map = $this->_vali(['code.require' => '商品编号不能为空哦!']);
if ($this->request->isGet()) {
$list = ShopGoods::mk()->where($map)->select()->toArray();
if (empty($list)) $this->error('无效的商品数据,请稍候再试!');
[$this->vo] = GoodsService::instance()->bindData($list);
$this->fetch();
} else {
[$data, $post, $batch] = [[], $this->request->post(), CodeExtend::uniqidDate(12, 'B')];
if (isset($post['goods_code']) && is_array($post['goods_code'])) {
foreach (array_keys($post['goods_code']) as $key) {
if ($post['goods_stock'][$key] > 0) $data[] = [
'batch_no' => $batch,
'goods_code' => $post['goods_code'][$key],
'goods_spec' => $post['goods_spec'][$key],
'goods_stock' => $post['goods_stock'][$key],
];
}
if (!empty($data)) {
ShopGoodsStock::mk()->insertAll($data);
GoodsService::instance()->stock($map['code']);
$this->success('商品数据入库成功!');
}
}
$this->error('没有需要商品入库的数据!');
}
}
/**
* 商品上下架
* @auth true
*/
public function state()
{
ShopGoods::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]), 'code');
}
/**
* 删除商品数据
* @auth true
*/
public function remove()
{
ShopGoods::mSave($this->_vali([
'deleted.in:0,1' => '状态值范围异常!',
'deleted.require' => '状态值不能为空!',
]), 'code');
}
}

View File

@ -1,77 +0,0 @@
<?php
namespace app\data\controller\shop;
use app\data\model\ShopGoodsMark;
use think\admin\Controller;
/**
* 商品标签管理
* Class Mark
* @package app\data\controller\shop
*/
class Mark extends Controller
{
/**
* 商品标签管理
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '商品标签管理';
$query = ShopGoodsMark::mQuery();
$query->like('name')->dateBetween('create_at');
$query->equal('status')->order('sort desc,id desc')->page();
}
/**
* 商品标签选择
* @login true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function select()
{
ShopGoodsMark::mQuery()->order('sort desc,id desc')->page();
}
/**
* 添加商品标签
* @auth true
*/
public function add()
{
ShopGoodsMark::mForm('form');
}
/**
* 编辑商品标签
* @auth true
*/
public function edit()
{
ShopGoodsMark::mForm('form');
}
/**
* 修改商品标签状态
* @auth true
*/
public function state()
{
ShopGoodsMark::mSave();
}
/**
* 删除商品标签
* @auth true
*/
public function remove()
{
ShopGoodsMark::mDelete();
}
}

View File

@ -1,188 +0,0 @@
<?php
namespace app\data\controller\shop;
use app\data\model\DataUser;
use app\data\model\ShopOrder;
use app\data\model\ShopOrderSend;
use app\data\service\OrderService;
use app\data\service\PaymentService;
use app\data\service\UserAdminService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
use think\exception\HttpResponseException;
/**
* 订单数据管理
* Class Order
* @package app\data\controller\shop
*/
class Order extends Controller
{
/**
* 支付方式
* @var array
*/
protected $payments = [];
/**
* 控制器初始化
*/
protected function initialize()
{
parent::initialize();
$this->payments = PaymentService::getTypeAll();
}
/**
* 订单数据管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '订单数据管理';
// 状态数据统计
$this->total = ['t0' => 0, 't1' => 0, 't2' => 0, 't3' => 0, 't4' => 0, 't5' => 0, 't6' => 0, 'ta' => 0];
foreach (ShopOrder::mk()->field('status,count(1) total')->group('status')->cursor() as $vo) {
[$this->total["t{$vo['status']}"] = $vo['total'], $this->total["ta"] += $vo['total']];
}
// 订单列表查询
$query = ShopOrder::mQuery();
$query->like('order_no,truck_name,truck_phone,truck_province|truck_area|truck_address#address,truck_send_no,truck_send_name');
$query->equal('status,payment_type,payment_status')->dateBetween('create_at,payment_datetime,cancel_datetime,truck_datetime,truck_send_datetime');
// 发货信息搜索
$db = ShopOrderSend::mQuery()->like('address_name#truck_address_name,address_phone#truck_address_phone,address_province|address_city|address_area|address_content#truck_address_content')->db();
if ($db->getOptions('where')) $query->whereRaw("order_no in {$db->field('order_no')->buildSql()}");
// 用户搜索查询
$db = DataUser::mQuery()->like('phone#user_phone,nickname#user_nickname')->db();
if ($db->getOptions('where')) $query->whereRaw("uuid in {$db->field('id')->buildSql()}");
// 代理搜索查询
$db = DataUser::mQuery()->like('phone#from_phone,nickname#from_nickname')->db();
if ($db->getOptions('where')) $query->whereRaw("puid1 in {$db->field('id')->buildSql()}");
// 列表选项卡
if (is_numeric($this->type = trim(input('type', 'ta'), 't'))) {
$query->where(['status' => $this->type]);
}
// 分页排序处理
$query->where(['deleted_status' => 0])->order('id desc')->page();
}
/**
* 订单列表处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _index_page_filter(array &$data)
{
UserAdminService::instance()->buildByUid($data);
UserAdminService::instance()->buildByUid($data, 'puid1', 'from');
OrderService::instance()->buildData($data);
foreach ($data as &$vo) $vo['payment_name'] = PaymentService::name($vo['payment_type']);
}
/**
* 单据凭证支付审核
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function audit()
{
if ($this->request->isGet()) {
ShopOrder::mForm('', 'order_no');
} else {
$data = $this->_vali([
'order_no.require' => '订单单号不能为空!',
'status.in:0,1' => '审核状态数值异常!',
'status.require' => '审核状态不能为空!',
'remark.default' => '',
]);
if (empty($data['status'])) {
$data['status'] = 0;
$data['cancel_status'] = 1;
$data['cancel_remark'] = $data['remark'] ?: '后台审核驳回并取消订单';
$data['cancel_datetime'] = date('Y-m-d H:i:s');
} else {
$data['status'] = 4;
$data['payment_code'] = CodeExtend::uniqidDate(20, 'T');
$data['payment_status'] = 1;
$data['payment_remark'] = $data['remark'] ?: '后台审核支付凭证通过';
$data['payment_datetime'] = date('Y-m-d H:i:s');
}
$order = ShopOrder::mk()->where(['order_no' => $data['order_no']])->find();
if (empty($order) || $order['status'] !== 3) $this->error('不允许操作审核!');
// 无需发货时的处理
if ($data['status'] === 4 && empty($order['truck_type'])) $data['status'] = 6;
// 更新订单支付状态
$map = ['status' => 3, 'order_no' => $data['order_no']];
if (ShopOrder::mk()->strict(false)->where($map)->update($data) !== false) {
if (in_array($data['status'], [4, 5, 6])) {
$this->app->event->trigger('ShopOrderPayment', $data['order_no']);
$this->success('订单审核通过成功!');
} else {
$this->app->event->trigger('ShopOrderCancel');
OrderService::instance()->stock($data['order_no']);
$this->success('审核驳回并取消成功!');
}
} else {
$this->error('订单审核失败!');
}
}
}
/**
* 清理订单数据
* @auth true
*/
public function clean()
{
$this->_queue('定时清理无效订单数据', "xdata:OrderClean", 0, [], 0, 60);
}
/**
* 取消未支付的订单
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function cancel()
{
$map = $this->_vali(['order_no.require' => '订单号不能为空!',]);
$order = ShopOrder::mk()->where($map)->find();
if (empty($order)) $this->error('订单查询异常!');
if (!in_array($order['status'], [1, 2, 3])) $this->error('订单不能取消!');
try {
$result = $order->save([
'status' => 0,
'cancel_status' => 1,
'cancel_remark' => '后台取消未支付的订单',
'cancel_datetime' => date('Y-m-d H:i:s'),
]);
if ($result !== false) {
OrderService::instance()->stock($order['order_no']);
$this->app->event->trigger('ShopOrderCancel', $order['order_no']);
$this->success('取消未支付的订单成功!');
} else {
$this->error('取消支付的订单失败!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
}

View File

@ -1,161 +0,0 @@
<?php
namespace app\data\controller\shop;
use app\data\model\BasePostageCompany;
use app\data\model\DataUser;
use app\data\model\ShopOrder;
use app\data\model\ShopOrderSend;
use app\data\service\ExpressService;
use app\data\service\OrderService;
use think\admin\Controller;
use think\exception\HttpResponseException;
/**
* 订单发货管理
* Class Send
* @package app\data\controller\shop
*/
class Send extends Controller
{
/**
* 订单发货管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '订单发货管理';
// 发货地址数据
$this->address = sysdata('ordersend');
// 状态数据统计
$this->total = ['t0' => 0, 't1' => 0, 't2' => 0, 'ta' => 0];
$db = ShopOrder::mk()->whereIn('status', [4, 5, 6])->where(['truck_type' => 1]);
$query = ShopOrderSend::mk()->whereRaw("order_no in {$db->field('order_no')->buildSql()}");
foreach ($query->fieldRaw('status,count(1) total')->group('status')->cursor() as $vo) {
$this->total["t{$vo['status']}"] = $vo['total'];
$this->total["ta"] += $vo['total'];
}
// 订单列表查询
$query = ShopOrderSend::mQuery();
$query->dateBetween('address_datetime,send_datetime')->equal('status')->like('send_number#truck_number,order_no');
$query->like('address_phone,address_name,address_province|address_city|address_area|address_content#address_content');
// 用户搜索查询
$db = DataUser::mQuery()->like('phone#user_phone,nickname#user_nickname')->db();
if ($db->getOptions('where')) $query->whereRaw("uuid in {$db->field('id')->buildSql()}");
// 订单搜索查询
$db = ShopOrder::mk()->whereIn('status', [4, 5, 6])->where(['truck_type' => 1]);
$query->whereRaw("order_no in {$db->field('order_no')->buildSql()}");
// 列表选项卡状态
if (is_numeric($this->type = trim(input('type', 'ta'), 't'))) {
$query->where(['status' => $this->type]);
}
// 列表排序显示
$query->order('id desc')->page();
}
/**
* 订单列表处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _index_page_filter(array &$data)
{
OrderService::instance()->buildData($data, false);
$orders = array_unique(array_column($data, 'order_no'));
$orderList = ShopOrder::mk()->whereIn('order_no', $orders)->column('*', 'order_no');
foreach ($data as &$vo) $vo['order'] = $orderList[$vo['order_no']] ?? [];
}
/**
* 快递发货地址
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function config()
{
if ($this->request->isGet()) {
$this->vo = sysdata('ordersend');
$this->fetch();
} else {
sysdata('ordersend', $this->request->post());
$this->success('发货地址保存成功');
}
}
/**
* 修改快递管理
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function truck()
{
if ($this->request->isGet()) {
$query = BasePostageCompany::mk()->where(['deleted' => 0, 'status' => 1]);
$this->items = $query->order('sort desc,id desc')->select()->toArray();
}
ShopOrderSend::mForm('truck_form', 'order_no');
}
/**
* 快递表单处理
* @param array $vo
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _truck_form_filter(array &$vo)
{
if ($this->request->isPost()) {
$map = ['order_no' => $vo['order_no']];
$order = ShopOrder::mk()->where($map)->find();
if (empty($order)) $this->error('订单查询异常,请稍候再试!');
// 配送快递公司填写
$map = ['code_1|code_2|code_3' => $vo['company_code']];
$company = BasePostageCompany::mk()->where($map)->find();
if (empty($company)) $this->error('配送快递公司异常,请重新选择快递公司!');
$vo['status'] = 2;
$vo['company_name'] = $company['name'];
$vo['send_datetime'] = $vo['send_datetime'] ?? date('Y-m-d H:i:s');
if ($order['status'] === 3) {
$map = ['order_no' => $vo['order_no']];
// 更新订单发货状态
ShopOrder::mk()->where($map)->update(['status' => 4]);
}
}
}
/**
* 快递追踪查询
* @auth true
*/
public function query()
{
try {
$data = $this->_vali(['code.require' => '快递不能为空!', 'number.require' => '单号不能为空!']);
$this->result = ExpressService::instance()->query($data['code'], $data['number']);
if (empty($this->result['code'])) $this->error($this->result['info']);
$this->fetch('truck_query');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
}

View File

@ -1,57 +0,0 @@
<?php
namespace app\data\controller\total;
use app\data\model\BaseUserUpgrade;
use app\data\model\DataUser;
use app\data\model\DataUserBalance;
use app\data\model\DataUserRebate;
use app\data\model\ShopGoods;
use app\data\model\ShopOrder;
use think\admin\Controller;
/**
* 商城数据报表
* Class Portal
* @package app\data\controller\total
*/
class Portal extends Controller
{
/**
* 商城数据报表
* @auth true
* @menu true
*/
public function index()
{
$this->usersTotal = DataUser::mk()->cache(true, 60)->count();
$this->goodsTotal = ShopGoods::mk()->cache(true, 60)->where(['deleted' => 0])->count();
$this->orderTotal = ShopOrder::mk()->cache(true, 60)->whereRaw('status >= 4')->count();
$this->amountTotal = ShopOrder::mk()->cache(true, 60)->whereRaw('status >= 4')->sum('amount_total');
// 近十天的用户及交易趋势
$this->days = $this->app->cache->get('portals', []);
if (empty($this->days)) {
for ($i = 15; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-{$i}days"));
$this->days[] = [
'当天日期' => date('m-d', strtotime("-{$i}days")),
'增加用户' => DataUser::mk()->whereLike('create_at', "{$date}%")->count(),
'订单数量' => ShopOrder::mk()->whereLike('create_at', "{$date}%")->whereRaw('status>=4')->count(),
'订单金额' => ShopOrder::mk()->whereLike('create_at', "{$date}%")->whereRaw('status>=4')->sum('amount_total'),
'返利金额' => DataUserRebate::mk()->whereLike('create_at', "{$date}%")->sum('amount'),
'剩余余额' => DataUserBalance::mk()->whereRaw("create_at<='{$date} 23:59:59' and deleted=0")->sum('amount'),
'充值余额' => DataUserBalance::mk()->whereLike('create_at', "{$date}%")->whereRaw('amount>0 and deleted=0')->sum('amount'),
'消费余额' => DataUserBalance::mk()->whereLike('create_at', "{$date}%")->whereRaw('amount<0 and deleted=0')->sum('amount'),
];
}
$this->app->cache->set('portals', $this->days, 60);
}
// 会员级别分布统计
$levels = BaseUserUpgrade::mk()->where(['status' => 1])->order('number asc')->column('number code,name,0 count', 'number');
foreach (DataUser::mk()->field('count(1) count,vip_code level')->group('vip_code')->cursor() as $vo) {
$levels[$vo['level']]['count'] = isset($levels[$vo['level']]) ? $vo['count'] : 0;
}
$this->levels = array_values($levels);
$this->fetch();
}
}

View File

@ -1,184 +0,0 @@
<?php
namespace app\data\controller\user;
use app\data\model\DataUser;
use app\data\service\UserAdminService;
use app\data\service\UserUpgradeService;
use think\admin\Controller;
/**
* 普通用户管理
* Class Admin
* @package app\data\controller\user
*/
class Admin extends Controller
{
/**
* 普通用户管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
// 用户等级分组
[$ts, $ls] = [[], UserUpgradeService::instance()->levels()];
$ts['ta'] = ['vip' => '', 'name' => '全部用户', 'count' => 0];
foreach ($ls as $k => $v) $ts["t{$k}"] = ['vip' => $k, 'name' => $v['name'], 'count' => 0,];
$ts['to'] = ['vip' => '', 'name' => '其他用户', 'count' => 0];
// 等级分组统计
foreach (DataUser::mk()->field('vip_code vip,count(1) count')->group('vip_code')->cursor() as $v) {
[$name, $count] = ["t{$v['vip']}", $v['count'], $ts['ta']['count'] += $v['count']];
isset($ts[$name]) ? $ts[$name]['count'] += $count : $ts['to']['count'] += $count;
}
if (empty($ts['to']['count'])) unset($ts['to']);
$this->total = $ts;
// 设置页面标题
$this->title = '普通用户管理';
// 创建查询对象
$query = DataUser::mQuery()->order('id desc');
// 数据筛选选项
$this->type = ltrim(input('type', 'ta'), 't');
if (is_numeric($this->type)) $query->where(['vip_code' => $this->type]);
elseif ($this->type === 'o') $query->whereNotIn('vip_code', array_keys($ls));
// 用户搜索查询
$db = DataUser::mQuery()->equal('vip_code#from_vipcode')->like('phone#from_phone,username|nickname#from_username')->db();
if ($db->getOptions('where')) $query->whereRaw("pid1 in {$db->field('id')->buildSql()}");
// 数据查询分页
$query->like('phone,username|nickname#username')->equal('status,vip_code')->dateBetween('create_at')->page();
}
/**
* 数据列表处理
* @param array $data
*/
protected function _page_filter(array &$data)
{
$this->upgrades = UserUpgradeService::instance()->levels();
UserAdminService::instance()->buildByUid($data, 'pid1', 'from');
}
/**
* 用户团队关系
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function teams()
{
$this->title = '用户团队关系';
$map = ['pid1' => input('from', 0)];
DataUser::mQuery()->where($map)->page(false);
}
/**
* 数据列表处理
* @param array $data
*/
protected function _teams_page_filter(array &$data)
{
$uids = array_unique(array_column($data, 'id'));
$subCount = DataUser::mk()->whereIn('pid1', $uids)->group('pid1')->column('count(1) count', 'pid1');
foreach ($data as &$vo) $vo['subCount'] = $subCount[$vo['id']] ?? 0;
}
/**
* 永久绑定代理
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function forever()
{
$map = $this->_vali(['id.require' => '用户ID不能为空']);
$user = DataUser::mk()->where($map)->find();
if (empty($user) || empty($user['pid0'])) $this->error('用户不符合操作要求!');
[$status, $message] = UserUpgradeService::instance()->bindAgent($user['id'], $user['pid0']);
$status && sysoplog('前端用户管理', "修改用户[{$map['id']}]的代理为永久状态");
empty($status) ? $this->error($message) : $this->success($message);
}
/**
* 设为总部用户
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function unbind()
{
$map = $this->_vali(['id.require' => '用户ID不能为空']);
$user = DataUser::mk()->where($map)->find();
if (empty($user)) $this->error('用户不符合操作要求!');
// 修改指定用户代理数据
$user->save(['pid0' => 0, 'pid1' => 0, 'pid2' => 0, 'pids' => 1, 'path' => '-', 'layer' => 1]);
// 刷新用户等级及上级等级
UserUpgradeService::instance()->upgrade($user['id'], true);
sysoplog('前端用户管理', "设置用户[{$map['id']}]为总部用户");
$this->success('设为总部用户成功!');
}
/**
* 绑定上级代理
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function parent()
{
if ($this->request->isGet()) {
$this->upgrades = UserUpgradeService::instance()->levels();
$data = $this->_vali(['uuid.require' => '待操作UID不能为空']);
// 排除下级用户
$path = DataUser::mk()->where(['id' => $data['uuid']])->value('path', '-');
$subids = DataUser::mk()->whereLike('path', "{$path}{$data['uuid']}-%")->column('id');
$query = DataUser::mQuery()->order('id desc')->whereNotIn('id', array_merge($subids, array_values($data)));
// 用户搜索查询
$db = DataUser::mQuery()->equal('vip_code#from_vipcode')->like('phone#from_phone,username|nickname#from_username')->db();
if ($db->getOptions('where')) $query->whereRaw("pid1 in {$db->field('id')->buildSql()}");
// 数据查询分页
$query->like('phone,username|nickname#username')->whereRaw('vip_code>0')->equal('status,vip_code')->dateBetween('create_at')->page();
} else {
$data = $this->_vali(['pid.require' => '待绑定代理不能为空!', 'uuid.require' => '待操作用户不能为空!']);
[$status, $message] = UserUpgradeService::instance()->bindAgent($data['uuid'], $data['pid'], 2);
$status && sysoplog('前端用户管理', "修改用户[{$data['uuid']}]的代理为用户[{$data['pid']}]");
empty($status) ? $this->error($message) : $this->success($message);
}
}
/**
* 重算用户余额返利
* @auth true
*/
public function sync()
{
$this->_queue('重新计算用户余额返利', 'xdata:UserAmount');
}
/**
* 修改用户状态
* @auth true
*/
public function state()
{
DataUser::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
}

View File

@ -1,135 +0,0 @@
<?php
namespace app\data\controller\user;
use app\data\model\DataUser;
use app\data\model\DataUserBalance;
use app\data\service\UserAdminService;
use app\data\service\UserBalanceService;
use app\data\service\UserUpgradeService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
use think\admin\model\SystemUser;
use think\admin\service\AdminService;
/**
* 余额充值记录
* Class Balance
* @package app\data\controller\user
*/
class Balance extends Controller
{
/**
* 余额充值管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '余额充值记录';
// 统计用户余额
$this->balance = UserBalanceService::instance()->amount(0);
// 现有余额类型
$this->names = DataUserBalance::mk()->group('name')->column('name');
// 创建查询对象
$query = DataUserBalance::mQuery()->equal('name,upgrade');
// 用户搜索查询
$db = DataUser::mQuery()->like('phone#user_phone,nickname#user_nickname')->db();
if ($db->getOptions('where')) $query->whereRaw("uuid in {$db->field('id')->buildSql()}");
// 数据查询分页
$query->where(['deleted' => 0])->like('code,remark')->dateBetween('create_at')->order('id desc')->page();
}
/**
* 数据列表处理
* @param array $data
*/
protected function _index_page_filter(array &$data)
{
UserAdminService::instance()->buildByUid($data);
$uids = array_unique(array_column($data, 'create_by'));
$users = SystemUser::mk()->whereIn('id', $uids)->column('username', 'id');
$this->upgrades = UserUpgradeService::instance()->levels();
foreach ($data as &$vo) {
$vo['upgradeinfo'] = $this->upgrades[$vo['upgrade']] ?? [];
$vo['create_byname'] = $users[$vo['create_by']] ?? '';
}
}
/**
* 添加余额充值
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add()
{
$data = $this->_vali(['uuid.require' => '用户UID不能为空']);
$this->user = DataUser::mk()->where(['id' => $data['uuid']])->find();
if (empty($this->user)) $this->error('待充值的用户不存在!');
DataUserBalance::mForm('form');
}
/**
* 表单数据处理
* @param array $data
*/
protected function _form_filter(array &$data)
{
if (empty($data['code'])) {
$data['code'] = CodeExtend::uniqidDate('20', 'B');
}
if ($this->request->isGet()) {
$this->upgrades = UserUpgradeService::instance()->levels();
}
if ($this->request->isPost()) {
$data['create_by'] = AdminService::instance()->getUserId();
if (empty(floatval($data['amount'])) && empty($data['upgrade'])) {
$this->error('金额为零并且没有升级行为!');
}
}
}
/**
* 表单结果处理
* @param bool $state
* @param array $data
* @throws \think\db\exception\DbException
*/
protected function _form_result(bool $state, array $data)
{
if ($state && isset($data['uuid'])) {
UserBalanceService::instance()->amount($data['uuid']);
UserUpgradeService::instance()->upgrade($data['uuid']);
}
}
/**
* 删除充值记录
* @auth true
*/
public function remove()
{
DataUserBalance::mDelete('', [['code', 'like', 'B%']]);
}
/**
* 删除结果处理
* @param bool $state
* @throws \think\db\exception\DbException
*/
protected function _delete_result(bool $state)
{
if ($state) {
$map = [['id', 'in', str2arr(input('id', ''))]];
foreach (DataUserBalance::mk()->where($map)->cursor() as $vo) {
UserBalanceService::instance()->amount($vo['uuid']);
UserUpgradeService::instance()->upgrade($vo['uuid']);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More