初始化

master
wangxinglong 2021-11-18 17:57:04 +08:00
commit 82f5a8f3f5
5603 changed files with 694899 additions and 0 deletions

19
.env.bak Normal file
View File

@ -0,0 +1,19 @@
APP_DEBUG = true
APP_TRACE = true
[APP]
DEFAULT_TIMEZONE = Asia/Shanghai
[DATABASE]
TYPE = mysql
HOSTNAME = 211.149.245.223
DATABASE = dev_bee_cms
USERNAME = dev_bee_cms
PASSWORD = dT7yH5fmd28JG6ER
HOSTPORT = 3306
CHARSET = utf8mb4
DEBUG = true
PREFIX = bee_
[LANG]
default_lang = zh-cn

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
.env
/.idea
/.vscode
backup/data/*
/config/extra
*.log
runtime/*
storage/*
public/storage/*
.DS_Store
/Test.php
nginx.htaccess
dump.rdb
/app/controller/api/Test.php

32
LICENSE.txt Normal file
View File

@ -0,0 +1,32 @@
ThinkPHP遵循Apache2开源协议发布并提供免费使用。
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
Apache Licence是著名的非盈利开源组织Apache采用的协议。
该协议和BSD类似鼓励代码共享和尊重原作者的著作权
允许代码修改,再作为开源或商业软件发布。需要满足
的条件:
1 需要给代码的用户一份Apache Licence
2 如果你修改了代码,需要在被修改的文件中说明;
3 在延伸的代码中(修改和有源代码衍生的代码中)需要
带有原来代码中的协议,商标,专利声明和其他原来作者规
定需要包含的说明;
4 如果再发布的产品中包含一个Notice文件则在Notice文
件中需要带有本协议内容。你可以在Notice中增加自己的
许可但不可以表现为对Apache Licence构成更改。
具体的协议参考http://www.apache.org/licenses/LICENSE-2.0
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

31
README.md Normal file
View File

@ -0,0 +1,31 @@
## 本CMS基于ThinkPHP 6.0.9开发
> - 运行环境要求 PHP7.4+
> - MySql版本限制 5.7.*需要支持json函数
> - [富文本编辑器选择wangEditorv3.1.1](https://github.com/wangfupeng1988/wangEditor)
> - [上传插件选择filepond4.7.1](https://github.com/pqina/filepond)
> - 默认上传插件修改为使用layui组件库自带的
>
<hr /><br />
**PHP扩展依赖列表**
> - fileinfo
> - exif 需要安装在mbsting扩展之后
> - gd
<hr /><br />
**PHP组件列表**
> -
<hr /><br />
**前端组件列表**
> -
<hr /><br />

1
app/.htaccess Normal file
View File

@ -0,0 +1 @@
deny from all

645
app/common.php Normal file
View File

@ -0,0 +1,645 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\Collection;
use think\db\exception\DbException;
use think\exception\ClassNotFoundException;
use think\Model;
use think\Paginator;
// 应用公共文件
if (!function_exists('widget')) {
/**
* 渲染输出Widget
* @param string $name Widget名称
* @param array $data 传入的参数
* @return mixed
* milo 2019-05-08 从TP5.1代码中拿来修改的
*/
function widget($name, $data = [])
{
return action($name, $data, 'widget');
}
}
if (!function_exists('action')) {
/**
* 调用模块的操作方法 参数格式 [模块/控制器/]操作
* @param string $url 调用地址
* @param string|array $vars 调用参数 支持字符串和数组
* @param string $layer 要调用的控制层名称
* @param bool $appendSuffix 是否添加类名后缀
* @return mixed
* milo 2019-05-08 从TP5.1代码中拿来修改的
*/
function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
{
$info = pathinfo($url);
$action = $info['basename'];
$module = '.' != $info['dirname'] ? $info['dirname'] : request()->controller();
$class = controller($module, $layer);
if (is_scalar($vars)) {
if (strpos($vars, '=')) {
parse_str($vars, $vars);
} else {
$vars = [$vars];
}
}
return app()->invokeMethod([$class, $action . config('route.action_suffix')], $vars);
}
}
if (!function_exists('controller')) {
/**
* 实例化(分层)控制器 格式:[模块名/]控制器名
* @access public
* @param string $name 资源地址
* @param string $layer 控制层名称
* @param bool $appendSuffix 是否添加类名后缀
* @param string $empty 空控制器名称
* @return object
* @throws ClassNotFoundException
*
* milo 2019-05-08 从TP5.1代码中拿来修改的
*/
function controller($name, $layer = 'controller', $empty = '')
{
$class = parseClass($name, $layer);
if (class_exists($class)) {
return app()->make($class);
} elseif ($empty && class_exists($emptyClass = app()->parseClass($layer, $empty))) {
return app()->make($emptyClass);
}
throw new ClassNotFoundException('class not exists:' . $class, $class);
}
}
if (!function_exists('parseClass')) {
/**
* 解析模块和类名
* @access protected
* @param string $name 资源地址
* @param string $layer 验证层名称
* @param bool $appendSuffix 是否添加类名后缀
* @return array
*
* milo 2019-05-08 从TP5.1代码中拿来修改的
*/
function parseClass($name, $layer)
{
if (false !== strpos($name, '\\')) {
$class = $name;
} else {
if (strpos($name, '/')) {
$names = explode('/', $name, 2);
$name = $names[1];
}
$class = app()->parseClass($layer, $name);
}
return $class;
}
}
if (!function_exists('randomStr')) {
/**
* 获取随机字符串
* @param int $type 0:数字(默认)1全部2:小写字母;3:大写字母4字母
* @param int $len 字符串长度
* @return string
*/
function randomStr($type = 0, $len = 5)
{
$strPol = "0123456789";
if ($type == 1) {
$strPol = "ABCDEFGHIJKLMOPQRSTUVWYZ0123456789abcdefghijklmopqrstuvwyz";
} elseif ($type == 2) {
$strPol = "abcdefghijklmopqrstuvwyz";
} elseif ($type == 3) {
$strPol = "ABCDEFGHIJKLMOPQRSTUVWYZ";
} elseif ($type == 4) {
$strPol = "ABCDEFGHIJKLMOPQRSTUVWYZabcdefghijklmopqrstuvwyz";
}
$max = strlen($strPol) - 1;
$str = '';
for ($i = 0; $i < $len; $i++) {
$str .= $strPol[rand(0, $max)];
}
return $str;
}
}
if (!function_exists('isMobile')) {
//判断访问终端是否为移动端
function isMobile()
{
// 如果有HTTP_X_WAP_PROFILE则一定是移动设备
if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
return true;
}
// 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
if (isset($_SERVER['HTTP_VIA'])) {
// 找不到为flase,否则为true
return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;
}
// 脑残法,判断手机发送的客户端标志,兼容性有待提高。其中'MicroMessenger'是电脑微信
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$clientkeywords = [
'nokia', 'sony', 'ericsson', 'mot', 'samsung', 'htc', 'sgh', 'lg', 'sharp', 'sie-', 'philips',
'panasonic', 'alcatel', 'lenovo', 'iphone', 'ipod', 'blackberry', 'meizu', 'android', 'netfront',
'symbian', 'ucweb', 'windowsce', 'palm', 'operamini', 'operamobi', 'openwave', 'nexusone', 'cldc',
'midp', 'wap', 'mobile', 'MicroMessenger'
];
// 从HTTP_USER_AGENT中查找手机浏览器的关键字
if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
return true;
}
}
// 协议法,因为有可能不准确,放到最后判断
if (isset ($_SERVER['HTTP_ACCEPT'])) {
// 如果只支持wml并且不支持html那一定是移动设备
// 如果支持wml和html但是wml在html之前则是移动设备
if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'],
'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'],
'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
return true;
}
}
return false;
}
}
//根据栏目获取路径
if (!function_exists('getUri')) {
function getUri($cate)
{
$url = '';
if (!empty($cate)) {
if ($cate['is_index']) {
$url = '/';
} elseif (!empty($cate['url'])) {
$url = $cate['url'];
} else {
$url = url($cate['template'] . '/index', ['category_id' => $cate['id']]);
}
}
return $url;
}
}
//根据文件大小转换为文字
if (!function_exists('sizeToStr')) {
function sizeToStr($size)
{
if (!is_numeric($size) || $size <= 0) {
return '';
}
$size = $size / 1024;
if ($size < 1024) {
return sprintf("%.2fK", $size);
}
$size = $size / 1024;
if ($size < 1024) {
return sprintf("%.2fM", $size);
}
$size = $size / 1024;
return sprintf("%.2fG", $size);
}
}
//根据路径获取文件名
if (!function_exists('getKeyByPath')) {
function getKeyByPath($path)
{
return substr($path, strrpos($path, '/') + 1);
}
}
//富文本中提取图片路径
if (!function_exists('getImageUrlFromText')) {
function getImageUrlFromText($content)
{
preg_match_all('/<img.*?src="(.*?)".*?>/is', $content, $imgs);
$data = [];
if (!empty($imgs) && !empty($imgs[1])) {
foreach ($imgs[1] as $img) {
if (substr($img, 0, 4) != 'http') {
$key = getKeyByPath($img);
$data[$key] = $img;
}
}
}
return $data;
}
}
//富文本中提取视频路径
if (!function_exists('getVideoUrlFromText')) {
function getVideoUrlFromText($content)
{
preg_match_all('/<video.*?src="(.*?)".*?>/is', $content, $videos);
$data = [];
if (!empty($videos) && !empty($videos[1])) {
foreach ($videos[1] as $video) {
if (substr($video, 0, 4) != 'http') {
$key = getKeyByPath($video);
$data[$key] = $video;
}
}
}
return $data;
}
}
//获取目录下的所有文件
if (!function_exists('getAllFilesByPath')) {
function getAllFilesByPath($path, $rootPath)
{
if (is_dir($path) && file_exists($path)) {
$items = scandir($path);
$files = [];
foreach ($items as $item) {
if (substr($item, 0, 1) != '.' && strpos($item, '_') == false) {
$itemPath = $path . '/' . $item;
if (is_file($itemPath)) {
$size = filesize($itemPath);
$files[$item] = [
'path' => str_replace($rootPath, '/', $itemPath),
'realPath' => $itemPath,
'size' => $size,
'sizeStr' => sizeToStr($size),
'suffix' => strtolower(substr($item, strrpos($item, '.') + 1)) //后缀
];
} elseif (is_dir($itemPath)) {
$childFiles = getAllFilesByPath($itemPath, $rootPath);
if (!empty($childFiles)) {
$files = array_merge($files, $childFiles);
} else {
rmdir($itemPath);
}
}
}
}
return $files;
}
return [];
}
}
//过滤get输入
if (!function_exists('getFilter')) {
function getFilter($value)
{
$getFilter = "'|(and|or)\b.+?(>|<|=|in|like)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$forArray = false;
if (is_array($value)) {
$forFilter = implode($value);
$forArray = true;
} else {
$forFilter = $value;
}
if (preg_match("/" . $getFilter . "/is", $forFilter) == 1) {
$value = $forArray ? [] : '';
}
return filterExp($value);
}
}
//过滤post录入
if (!function_exists('postFilter')) {
function postFilter($value)
{
$postFilter = "\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$forArray = false;
if (is_array($value)) {
$forFilter = implode($value);
$forArray = true;
} else {
$forFilter = $value;
}
if (preg_match("/" . $postFilter . "/is", $forFilter) == 1) {
$value = $forArray ? [] : '';
}
return filterExp($value);
}
}
//过滤cookie数据
if (!function_exists('cookieFilter')) {
function cookieFilter($value)
{
$cookieFilter = "\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$forArray = false;
if (is_array($value)) {
$forFilter = implode($value);
$forArray = true;
} else {
$forFilter = $value;
}
if (preg_match("/" . $cookieFilter . "/is", $forFilter) == 1) {
$value = $forArray ? [] : '';
}
return filterExp($value);
}
}
if (!function_exists('filterExp')) {
function filterExp($value)
{
$filter = '/^(\s)+(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)(\s)+$/i';
$forArray = false;
if (is_array($value)) {
$forFilter = implode($value);
$forArray = true;
} else {
$forFilter = $value;
}
if (preg_match($filter, $forFilter) == 1) {
$value = $forArray ? [] : '';
}
return $value;
}
}
if (!function_exists('arrayHtmlFilter')) {
function arrayHtmlFilter($arr)
{
foreach ($arr as $k => $one) {
if (is_array($one)) {
$arr[$k] = arrayHtmlFilter($one);
} else {
$one = trim($one);
$arr[$k] = strip_tags($one);
}
}
return $arr;
}
}
if (!function_exists('toCamelString')) {
/**
* 转驼峰
*
* @param string $string
* @param false $small 默认false 为true首字母小写
* @return string
*/
function toCamelString(string $string, bool $small = false): string
{
//例: xxx_yYy_zzZ 和 xxX-yyy-Zzz
//1. 字符串转小写 xxx_yyy_zzz xxx-yyy-zzz
//2. -和_转空格 xxx yyy zzz
//3. 单词首字母大写 Xxx Yyy Zzz
//4. 清除空格 XxxYyyZzz
//处理下划线、减号 统统专程大驼峰 如xxx_yyy_zzz xxx-yyy-zzz 均转为 XxxYyyZzz
$string = strtolower($string);
$string = str_replace('-', ' ', $string);
$string = str_replace('_', ' ', $string);
$string = str_replace(' ', '', ucwords($string));
if ($small) {
$string = lcfirst($string);
}
return $string;
}
}
if (!function_exists('unCamelize')) {
/**
* 驼峰命名转特定分隔符[如下划线]命名
* @param string $camelCaps
* @param string $separator
* @return string
*/
function unCamelize(string $camelCaps, string $separator = '-'): string
{
return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
}
}
if (!function_exists('generateRand')) {
/**
* 生成随机数
*
* @param int $length 长度
* @param string $type 模式 默认mix混合 number纯数字 alpha字母
* @return string
*/
function generateRand(int $length = 8, string $type = 'mix'): string
{
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$number = '0123456789';
$alphabetLen = strlen($alphabet) - 1;
$numberLen = 9;
switch ($type) {
case 'number':
$str = $number;
$len = $numberLen;
break;
case 'alpha':
$str = $alphabet;
$len = $alphabetLen;
break;
default:
$str = $alphabet . $number;
$len = $alphabetLen + $numberLen;
}
$randStr = '';
$str = str_shuffle($str);
for ($i = 0; $i < $length; $i++) {
$num = mt_rand(0, $len);
$randStr .= $str[$num];
}
return $randStr;
}
}
if (!function_exists('generateCode')) {
/**
* 生成特定编码
*
* @param string $type 类型 默认mix混合 number纯数字 alpha字母
* @param int $len 随机数长度
* @return string
*/
function generateCode(string $type = 'number', int $len = 6): string
{
//#时间戳+微秒+6位随机数
$time = microtime(true);
$timeStr = str_replace('.', '', $time);
return sprintf("%s%s", $timeStr, generateRand($len, $type));
}
}
if (!function_exists('checkMobile')) {
/**
* 检测手机号
*
* @param string $mobile
* @return bool
*/
function checkMobile(string $mobile): bool
{
if (preg_match("/^1[3456789]{1}\d{9}$/", $mobile)) {
return true;
} else {
return false;
}
}
}
if (!function_exists('arrayKeysFilter')) {
/**
* 数组键名过滤
*
* @param array $data
* @param array $allowKeys
* @return array
*/
function arrayKeysFilter(array $data, array $allowKeys): array
{
$list = [];
foreach ($data as $key => $val) {
if (in_array($key, $allowKeys)) {
$list[$key] = $val;
}
}
return $list;
}
}
if (!function_exists('getFilesize')) {
/**
* 尺寸单位转换
*
* @param $num
* @return string
*/
function getFilesize($num): string
{
$p = 0;
$format = 'B';
if ($num > 0 && $num < 1024) {
return number_format($num) . ' ' . $format;
}
if ($num >= 1024 && $num < pow(1024, 2)) {
$p = 1;
$format = 'KB';
}
if ($num >= pow(1024, 2) && $num < pow(1024, 3)) {
$p = 2;
$format = 'MB';
}
if ($num >= pow(1024, 3) && $num < pow(1024, 4)) {
$p = 3;
$format = 'GB';
}
if ($num >= pow(1024, 4) && $num < pow(1024, 5)) {
$p = 3;
$format = 'TB';
}
$num /= pow(1024, $p);
return number_format($num, 3) . ' ' . $format;
}
}
if (!function_exists('arrayNullToString')) {
/**
* 数组中null值转为空字符串
*
* @param array $data
* @return array
*/
function arrayNullToString(array $data): array
{
foreach ($data as $key => $val) {
if (is_array($val)) {
$data[$key] = arrayNullToString($val);
} elseif ($val === null) {
$data[$key] = '';
}
}
return $data;
}
}
if (!function_exists('arrayKeysExcludeFilter')) {
/**
* 数组键名排除过滤
*
* @param array $data
* @param array $excludeKeys 排除的字段
* @return array
*/
function arrayKeysExcludeFilter(array $data, array $excludeKeys): array
{
foreach ($data as $key => $val) {
if (in_array($key, $excludeKeys)) {
unset($data[$key]);
}
}
return $data;
}
}
if (!function_exists('getLatelyWeekDate')) {
/**
* 获取本周的周一 到周日的日期
*/
function getLatelyWeekDate()
{
//本周一
$oneDate = date('Y-m-d 00:00:00', (time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 86400)); //w为星期几的数字形式,这里0为周日
$oneDateTime = strtotime($oneDate);
//返回周一到周天 1-7
return [
"1" => ["date"=>$oneDate],
"2" => ["date"=>date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 1)))],
"3" => ["date"=>date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 2)))],
"4" => ["date"=>date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 3)))],
"5" => ["date"=>date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 4)))],
"6" => ["date"=>date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 5)))],
"7" => ["date"=>date('Y-m-d 00:00:00', $oneDateTime + ((86400 * 6)))],
];
}
}
if (!function_exists('stringDesensitization')) {
/**
* 字符串脱敏 默认给手机号脱敏 其他未兼容
*
* @param string $string
* @param string $s
* @param int $start
* @param int $len
* @return string
*/
function stringDesensitization(string $string, string $s = '****', int $start = 3, int $len = 4): string
{
return substr_replace($string, $s, $start, $len);
}
}
/**
* UUID
*/
if(!function_exists("createUuid")){
function createUuid($prefix = "")
{
$chars = md5(uniqid(mt_rand(), true));
$uuid = substr($chars, 0, 8) . '-'
. substr($chars, 8, 4) . '-'
. substr($chars, 12, 4) . '-'
. substr($chars, 16, 4) . '-'
. substr($chars, 20, 12);
return $prefix . str_replace("-", "", $uuid);
}
}

35
app/controller/About.php Normal file
View File

@ -0,0 +1,35 @@
<?php
namespace app\controller;
use app\repository\OperationRepository;
use Exception;
use think\response\View;
use think\response\Redirect;
use app\repository\CmsRepository;
use app\repository\BlockRepository;
use think\db\exception\DbException;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
class About extends Base
{
/**
* 列表页
*
* @return Redirect|View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function index()
{
$this->setSeo();
$about = CmsRepository::getInstance()->getAbout($this->aboutCategory['id']);
$this->data['about'] = $about;
$this->data['category'] = $this->aboutCategory;
return $this->view();
}
}

513
app/controller/Account.php Normal file
View File

@ -0,0 +1,513 @@
<?php
namespace app\controller;
use app\exception\RepositoryException;
use app\repository\AccountRepository;
use app\repository\CommonRepository;
use app\repository\GoodsRepository;
use app\service\Kd100;
use app\validate\Account as VAccount;
use app\repository\OrderRepository;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
use think\response\Json;
use think\response\View;
class Account extends Base
{
protected $middleware = ['login'];
/**
* 个人中心
*
* @return View
* @throws DbException
*/
public function index(): View
{
$this->data['countList'] = OrderRepository::getInstance()->findOrderCount($this->authId);
$this->data['markList'] = OrderRepository::getInstance()->auctionMarkList('', [$this->authId]);
$this->data['biddingList'] = GoodsRepository::getInstance()->auctionBiddingList($this->authId);
return $this->view();
}
/**
* 个人资料
*
* @return View|Json
* @throws RepositoryException
*/
public function profile()
{
$repo = AccountRepository::getInstance();
$item = $repo->findById($this->authId);
if ($this->request->isPost()) {
$post = input('post.');
$update = [];
$update['headimgurl'] = $post['headimgurl'] ?? '';
$update['sex'] = $post['sex'];
$update['nickname'] = $post['nickname'];
if (!empty($post['nickname']) && $item['nickname'] !== $post['nickname']) {
if ($item['nickname_time'] > 0) {
return $this->json(4001, '每人仅先修改一次昵称,您已修改过了。');
}
$update['nickname_time'] = $item['nickname_time'] + 1;
}
$item->save($update);
return $this->json();
}
$this->data['item'] = $item;
return $this->view();
}
/**
* 我的订单
*
* @return View
*/
public function order(): View
{
$accountId = $this->auth['id'] ?? 0;
$tag = input('get.tag/s', 'waiting');
$this->data['items'] = OrderRepository::getInstance()->getOrderGoods($accountId, $tag);
$this->data['tag'] = $tag;
return $this->view();
}
/**
* 保证金
*
* @return View
* @throws RepositoryException
*/
public function deposit(): View
{
$accountId = $this->auth['id'] ?? 0;
if (!$accountId) {
$this->error('请先登录');
}
$item = AccountRepository::getInstance()->findById($accountId, ['quota', 'id', 'deposit']);
$this->data['item'] = $item;
return $this->view();
}
/**
* 实名认证
*
* @return View|Json
* @throws RepositoryException
*/
public function realName()
{
$accountId = $this->auth['id'] ?? 0;
$account = AccountRepository::getInstance()->findById($accountId);
if ($this->request->isPost()) {
if (!$account) {
return $this->json(4001, '请先登录');
}
if ($account['is_real_name']) {
return $this->json(4002, '您已通过认证');
}
$post = input('post.');
$validate = new VAccount();
if (!$validate->scene('real_name')->check($post)) {
return $this->json(4003, $validate->getError());
}
$post['is_real_name'] = 1;
$account->save($post);
return $this->json();
}
$this->data['item'] = $account;
return $this->view();
}
/**
* 个人账户
*
* @return View
* @throws RepositoryException
*/
public function info(): View
{
$accountId = $this->auth['id'] ?? 0;
$item = AccountRepository::getInstance()->findById($accountId);
$rechargeList = AccountRepository::getInstance()->fetchRechargeList($accountId);
$withdrawalList = AccountRepository::getInstance()->fetchWithdrawalList($accountId);
$this->data['item'] = $item;
$this->data['rechargeList'] = $rechargeList['list'];
$this->data['withdrawalList'] = $withdrawalList['list'];
return $this->view();
}
/**
* 中标清单
*
* @return View
* @throws DbException
*/
public function biddingList(): View
{
$accountId = $this->auth['id'] ?? 0;
$pageParams['query'] = input('get.');
$list = OrderRepository::getInstance()->auctionMarkList('', [$accountId], $pageParams);
$this->data['list'] = $list;
return $this->view();
}
/**
* 竞价清单
*
* @return View
*/
public function biddingLog(): View
{
$list = GoodsRepository::getInstance()->auctionBiddingList($this->authId);
$this->data['items'] = $list;
return $this->view();
}
/**
* 关注的拍品
*
* @return View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function auctionCollection(): View
{
$accountId = $this->auth['id'] ?? 0;
$items = AccountRepository::getInstance()->fetchCollection($accountId, GoodsRepository::TYPE_AUCTION);
$this->data['items'] = $items;
return $this->view();
}
/**
* 商品收藏
*
* @return View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function goodsCollection(): View
{
$accountId = $this->auth['id'] ?? 0;
$items = AccountRepository::getInstance()->fetchCollection($accountId, GoodsRepository::TYPE_GOODS);
$this->data['items'] = $items;
return $this->view();
}
/**
* 地址管理
*
* @return View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function address(): View
{
$accountId = $this->auth['id'] ?? 0;
//地址列表
$addressList = AccountRepository::getInstance()->findAddressByUid($accountId);
$this->data['addressList'] = $addressList;
return $this->view();
}
/**
* 地址详情
*
* @return Json|View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function addressDetail()
{
$resp = AccountRepository::getInstance();
$accountId = $this->auth['id'] ?? 0;
$id = input('param.id/d', 0);
$item = $resp->findAddressById($id);
if ($this->request->isPost()) {
$postItem = input('post.');
$postItem['user_id'] = $postItem['user_id'] ?? $accountId;
$resp->saveAddress($postItem);
return $this->json();
}
$this->data['item'] = $item;
return $this->view();
}
/**
* 地址删除
*
* @return Json
*/
public function addressDel(): Json
{
if ($this->request->isPost()) {
$id = input('post.id/d', 0);
AccountRepository::getInstance()->delAddress($id);
return $this->json();
}
return $this->json(4002, '请求方式错误');
}
/**
* 修改密码
*
* @return Json
*/
public function editPwd(): Json
{
$post = input('post.');
$accountId = $this->auth['id'] ?? 0;
$validate = new VAccount();
if (!$validate->scene('edit_password')->check($post)) {
return $this->json(4002, $validate->getError());
}
try {
AccountRepository::getInstance()->modifyPwd($accountId, $post['old_password'], $post['password']);
} catch (Exception $e) {
$this->json(4003, $e->getMessage());
}
return $this->json();
}
/**
* 取消收藏|关注
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function unCollect(): Json
{
$accountId = $this->auth['id'] ?? 0;
$goodsId = input('post.id/d');
AccountRepository::getInstance()->unCollectGoods($accountId, $goodsId);
return $this->json();
}
/**
* 操作保证金 充值|退回 相应改变额度
*
* @return Json
* @throws RepositoryException
*/
public function operateDeposit(): Json
{
if ($this->request->isPost()) {
$accountId = $this->auth['id'] ?? 0;
$amount = input('post.value', 0);
$type = input('post.type/s', 'recharge');
if (!AccountRepository::getInstance()->isEnough($accountId, $amount, 'deposit')) {
return $this->json(4000, '余额不足');
}
try {
AccountRepository::getInstance()->operateDeposit($accountId, $amount, $type);
} catch (RepositoryException $e) {
return $this->json(4002, $e->getMessage());
} catch (Exception $e) {
CommonRepository::log('保证金充值失败', $e);
return $this->json(5001, '充值失败');
}
return $this->json();
}
return $this->json(4002, '请求方式错误');
}
/**
* 充值
*
* @return Json
* @throws GuzzleException
*/
public function rechargeAmount(): Json
{
if ($this->request->isPost()) {
$accountId = $this->auth['id'] ?? 0;
$amount = input('post.amount', 0);
$type = input('post.type/s');
if (!$accountId) {
return $this->json(4001, '请先登录');
}
try {
$qr = AccountRepository::getInstance()->recharge($accountId, (float) $amount, $type);
return $this->json(0, 'success', ['payment_order_number' => $qr['order_id'], 'code_url' => $qr['qr']]);
} catch (Exception $e) {
CommonRepository::log('充值失败', $e);
return $this->json(5001, '充值失败:'.$e->getMessage());
}
}
return $this->json(4002, '请求方式错误');
}
/**
* 重新充值
*
* @return Json
* @throws GuzzleException
*/
public function rechargeAgain(): Json
{
if ($this->request->isPost()) {
$accountId = $this->auth['id'] ?? 0;
$orderId = input('post.order_id', 0);
$type = input('post.type/s');
if (!$accountId) {
return $this->json(4001, '请先登录');
}
try {
$qr = AccountRepository::getInstance()->rechargeAgain($accountId, $orderId, $type);
return $this->json(0, 'success', ['payment_order_number' => $qr['order_id'], 'code_url' => $qr['qr']]);
} catch (Exception $e) {
CommonRepository::log('充值失败', $e);
return $this->json(5001, '充值失败:'.$e->getMessage());
}
}
return $this->json(4002, '请求方式错误');
}
/**
* 查询订单
*
* @return array|Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function checkPayment()
{
if ($this->request->isPost()) {
$res['code'] = 0;
$res['msg'] = 'success';
$res['data']['paid'] = true;
$orderId = input('post.order_id/s', ''); //订单ID
$type = input('post.type/s', 'all'); //支付方式
if (!$orderId || !$type) {
$res['code'] = 1;
$res['msg'] = '参数错误';
return $res;
}
//根据支付类型 请求接口查询订单
$hasPaid = AccountRepository::getInstance()->hasPaid($orderId, $type);
if ($hasPaid) {
AccountRepository::getInstance()->paymentLogPaid($orderId, $type);
}
$res['data']['paid'] = $hasPaid;
return $res;
}
return $this->json(1, '非法请求!');
}
/**
* 提现
*
* @return Json
*/
public function withdrawal(): Json
{
if ($this->request->isPost()) {
$amount = input('post.amount', '');
$accountId = $this->auth['id'] ?? 0;
try {
AccountRepository::getInstance()->withdrawal($accountId, $amount);
return $this->json();
} catch (Exception $e) {
CommonRepository::log('提现失败', $e);
return $this->json(5001, '提现失败');
}
}
return $this->json(1, '非法请求!');
}
/**
* 获取已有订单号的支付二维码
*
* @return Json
* @throws GuzzleException
*/
public function getPaymentQr(): Json
{
if ($this->request->isPost()) {
$type = input('post.type', '');
$orderId = input('post.order_id', '');
try {
$codeQr = OrderRepository::getInstance()->generatePaymentQrCode($type, $orderId);
return $this->json(0, 'success', ['payment_order_number' => $orderId, 'code_url' => $codeQr]);
} catch (Exception $e) {
CommonRepository::log('获取支付二维码', $e);
return $this->json(5001, '获取支付二维码');
}
}
}
/**
* 物流查询
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function logistics(): Json
{
$orderId = input('post.order_id');
$type = input('post.type', 'goods');
// $com = 'shunfeng';
// $num = 'SF1980860132707';
if ($type == 'goods') {
if (!$delivery = OrderRepository::getInstance()->findExpressByOrder($orderId)) {
return $this->json(4001, '物流信息不存在');
}
} else {
if (!$delivery = OrderRepository::getInstance()->findExpressByAuction($orderId)) {
return $this->json(4001, '物流信息不存在');
}
}
$com = $delivery['express_code'];
$num = $delivery['express_number'];
return $this->json(0, 'success', ['res' => Kd100::query($com, $num)]);
}
}

View File

@ -0,0 +1,99 @@
<?php
namespace app\controller;
use app\model\{Archives as MArticle, Category};
use think\facade\View;
class Article extends Base
{
//详情
public function detail($id = 0)
{
if ($id <= 0) {
return $this->error('错误页面');
}
$article = MArticle::getById($id);
if (empty($article)) {
return $this->error('无此文章');
}
MArticle::updateById($id, ['views' => $article['views'] + 1]);
$category = Category::getById($article['category_id']);
$prev = MArticle::getPrevArticleByIdAndCategoryId($id, $article['category_id']);
$next = MArticle::getNextArticleByIdAndCategoryId($id, $article['category_id']);
$keywords = $article['seo_keywords'] ?: $this->system['seo_keywords'];
$description = $article['seo_description'] ?: $this->system['seo_description'];
$this->setSeo($article['title'], $keywords, $description);
$this->data['article'] = $article;
$this->data['category'] = $category;
$this->data['categoryId'] = $category['id'];
$this->data['prev'] = $prev;
$this->data['next'] = $next;
return $this->view($category['template_detail'] ?? '');
}
//列表页
public function index()
{
$categoryId = input('category_id/d', 0);
if ($categoryId <= 0) {
return $this->error('错误页面');
}
$category = Category::getById($categoryId);
$page_size = 20;
if( $category['number'])$page_size= $category['number'];
if( $this->request->param("page_size/d")){
$page_size= $this->request->param("page_size/d");
cookie("article_page_size",$this->request->param("page_size/d"));
}else{
if( cookie("?article_page_size"))$page_size= cookie("article_page_size");
}
if (empty($category)) {
return $this->error('错误页面');
}
$description = $category['description'] ?: $this->system['seo_description'];
$this->setSeo($category['title'], $this->system['seo_keywords'], $description);
$this->data['items'] = MArticle::getListPageByCategory($categoryId, $page_size);
$this->data['category'] = $category;
$this->data['categoryId'] = $categoryId;
$this->data['page_size'] = $page_size;
$this->data['article_count'] = MArticle::getListCount($categoryId);
return $this->view($category['template_list'] ?? '');
}
//查询
public function query(): \think\response\View
{
$keyword = $this->request->param("keyword/s");
//无key值跳转到产品
if (!$keyword) $this->redirect((string)url('/articles/12.html'));
$where = [
['category_id', 'in', [5, 12, 13, 14, 15]],
['status', '=', 1],
];
$where[] = ['title', 'like', '%' . $keyword . '%'];
$param['keyword'] = $keyword;
$paginate = [
'list_rows' => 20,
'query' => $param
];
$data = MArticle::where($where)
->order("sort desc")
->paginate($paginate, false);
View::assign("items", $data);
View::assign("keyword", $keyword);
$this->data['category'] = Category::getById(5);
$this->data['categoryId'] = 5;
return $this->view("/article/product_query");
}
}

48
app/controller/Base.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace app\controller;
use app\model\Category;
use app\model\Link;
use app\model\System;
use app\repository\BlockRepository;
use app\repository\CmsRepository;
/**
* 控制器基础类
*/
class Base extends BaseController
{
//需要向模板传递的值
protected $data = [];
//系统配置信息
protected $system = [];
protected $auth = [];
protected $authId = 0;
protected $aboutCategory = [];
// 初始化
protected function initialize()
{
$this->auth = session('frontend_auth') ?? [];
$this->data['auth'] = $this->auth;
$this->authId = $this->auth['id'] ?? 0;
}
//设置SEO信息
protected function setSeo($title = '', $keywords = '', $description = '')
{
$this->data['seoTitle'] = $title ?: $this->system['seo_title'] ?? '';
$this->data['seoKeywords'] = $keywords ?: $this->system['seo_keywords'] ?? '';
$this->data['seoDescription'] = $description ?: $this->system['seo_description'] ?? '';
}
//模板
protected function view($template = '')
{
return view($template)->assign($this->data);
}
}

View File

@ -0,0 +1,254 @@
<?php
declare (strict_types=1);
namespace app\controller;
use think\{App, Request, response\Json, response\Redirect, response\View, Validate};
use Exception;
use think\exception\ValidateException;
/**
* 控制器基础类
*/
abstract class BaseController
{
/**
* 无需登录的方法,同时也就不需要鉴权了
*
* @var array
*/
protected $noNeedLogin = [];
/**
* 无需鉴权的方法,但需要登录
*
* @var array
*/
protected $noNeedRight = [];
/**
* Request实例
* @var Request
*/
protected $request;
/**
* 应用实例
* @var App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
list($validate, $scene) = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
/**
* 验证器
*
* @param array $data
* @param $validate
* @param array $message
* @param bool $batch
* @return Json|bool
* @throws Exception
*/
protected function validateByApi(array $data, $validate, array $message = [], bool $batch = false)
{
try {
$this->validate($data, $validate, $message, $batch);
return true;
} catch (ValidateException $e) {
$msg = $e->getMessage();
if ($batch) {
$msg = implode(',', $e->getError());
}
return $this->json(4000, $msg);
} catch (Exception $e) {
throw $e;
}
}
/**
* 验证器
*
* @param array $data
* @param $validate
* @param array $message
* @param bool $batch
* @return Redirect
* @throws Exception
*/
protected function validateByView(array $data, $validate, array $message = [], bool $batch = false): Redirect
{
try {
$this->validate($data, $validate, $message, $batch);
} catch (ValidateException $e) {
$msg = $e->getMessage();
if ($batch) {
$msg = implode(',', $e->getError());
}
return $this->error( $msg);
} catch (Exception $e) {
throw $e;
}
}
/**
* 操作成功跳转的快捷方法
* @access protected
* @param mixed $msg 提示信息
* @param string|null $url 跳转的URL地址
* @param mixed $data 返回的数据
* @param integer $wait 跳转等待时间
* @param array $header 发送的Header信息
* @return Redirect
*/
protected function success($msg = '', string $url = null, $data = '', int $wait = 3, array $header = []): Redirect
{
if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) {
$url = $_SERVER["HTTP_REFERER"];
} elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url);
}
$result = [
'code' => 1,
'msg' => $msg,
'data' => $data,
'url' => $url,
'wait' => $wait,
];
return $this->redirect(url('error/404', $result));
}
/**
* 操作错误跳转的快捷方法
* @access protected
* @param mixed $msg 提示信息
* @param string|null $url 跳转的URL地址
* @param mixed $data 返回的数据
* @param integer $wait 跳转等待时间
* @return Redirect
*/
protected function error($msg = '', string $url = null, $data = '', int $wait = 3): Redirect
{
if (is_null($url)) {
$referer = $_SERVER['HTTP_REFERER'] ?? null;
if (empty($referer)) {
$url = $this->request->isAjax() ? '' : '/';
} else {
$url = $this->request->isAjax() ? '' : 'javascript:history.back(-1);';
}
} elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url);
}
$result = [
'code' => 0,
'msg' => $msg,
'data' => $data,
'url' => $url,
'wait' => $wait,
];
return $this->redirect(url('error/404', $result));
}
/**
* 返回封装后的API数据到客户端
* 以json格式抛出异常
* @access protected
* @param integer $code 返回的code
* @param mixed $msg 提示信息
* @param mixed $data 要返回的数据
* @return Json
*/
protected function json(int $code = 0, $msg = '操作成功', $data = []): Json
{
$result = [
'code' => $code,
'msg' => $msg,
'data' => $data
];
return json($result);
}
/**
* URL重定向
* @access protected
* @param string $url 跳转的URL表达式
* @return Redirect
*/
protected function redirect($url): Redirect
{
if (!is_string($url)) {
$url = $url->__toString();
}
return redirect($url);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace app\controller;
use app\repository\BlockRepository;
use Exception;
use think\response\View;
use app\repository\OperationRepository;
class Contact extends Base
{
/**
* @return View
* @throws Exception
*/
public function index(): View
{
$position = ['contact_banner'];
$slides = OperationRepository::getInstance()->slideListByPosition($position);
$this->data['blocks'] = BlockRepository::getInstance()->getByCateName(BlockRepository::CATEGORY_CONTACT);
$this->data['slide'] = $slides;
$this->setSeo();
return $this->view();
}
}

48
app/controller/Error.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace app\controller;
class Error extends BaseController
{
public function __call($method, $args)
{
if(request()->isAjax()) {
return $this->json(4004, 'error request!');
} else {
$referer = $_SERVER['HTTP_REFERER'] ?? null;
if (empty($referer)) {
$url = '/';
} else {
$domain = $this->request->domain();
$urlInfo = parse_url($referer);
$scheme = $urlInfo['scheme'] ?? '';
$requestSrc = '';
if (!empty($scheme)) {
$requestSrc = $scheme.'://'.($urlInfo['host'] ?? '');
}
if($domain != $requestSrc) {
$url = '/';
} else {
$url = 'javascript:history.back(-1);';
}
}
$result = [
'code' => 404,
'msg' => '无效请求! 没有找到相关资源',
'data' => [],
'url' => $url,
'wait' => 5,
];
return view('/manager/error/jump')->assign($result);
}
}
public function jump()
{
$param = request()->param();
return view()->assign($param);
}
}

101
app/controller/Index.php Normal file
View File

@ -0,0 +1,101 @@
<?php
namespace app\controller;
use app\repository\OrderRepository;
use app\service\wx\WechatPay;
use Exception;
use think\facade\Log;
use think\response\Redirect;
class Index extends Base
{
/**
* @return Redirect
* @throws Exception
*/
public function index(): Redirect
{
return $this->redirect('/manager');
}
/**
* 退出
*
* @return Redirect
*/
public function logout(): Redirect
{
session('frontend_auth', null);
$req = $this->request->header('referer');
return $this->redirect($req);
}
/**
* 微信的回调
*
* @throws \EasyWeChat\Kernel\Exceptions\Exception
*/
public function callback()
{
if ($this->request->isPost()) {
$app = WechatPay::getInstance();
$response = $app->handlePaidNotify(function ($message, $fail) {
// $aa = '{"appid":"wxa02e44170bc722cd","bank_type":"OTHERS","cash_fee":"1","fee_type":"CNY","is_subscribe":"N","mch_id":"1605090111","nonce_str":"60f7d8a1e4ac8","openid":"oKrEm0ehgsy2ZTWzEva4tbLuUgFw","out_trade_no":"16268555858753004863","result_code":"SUCCESS","return_code":"SUCCESS","sign":"DB3F6CDCB7FBB3B9DDF7C0CC8BBD5AAD","time_end":"20210721162000","total_fee":"1","trade_type":"JSAPI","transaction_id":"4200001200202107217942681078"}';
// $message = json_decode($aa, true);
$m = json_encode($message, JSON_UNESCAPED_UNICODE);
if (!$order = OrderRepository::getInstance()->findOneByWhere(['coding' => $message['out_trade_no']])) {
$this->log(sprintf("[微信支付回调][%s][%s]订单支付成功,但系统查无此订单 info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'error');
return true;//订单不存在
}
//记录日志
$this->log(sprintf("[微信支付回调][%s][%s]订单支付成功 info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'info');
if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
//更改订单状态
try {
$res = false;
// 用户是否支付成功
if (isset($message['result_code']) && $message['result_code'] === 'SUCCESS') {
//记录日志
$res = OrderRepository::getInstance()->setPaid($order['coding']);
$this->log(sprintf("[微信支付回调][%s][%s]订单支付成功 修改订单状态为%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $res), 'info');
// 用户支付失败
} elseif (isset($message['result_code']) && $message['result_code'] === 'FAIL') {
//记录日志
$this->log(sprintf("[微信支付回调][%s][%s]订单支付失败 修改订单状态为%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $res), 'info');
}
if (!$res) {
return $fail('Order status edit failed.');
}
} catch (Exception $e) {
$this->log(sprintf("[微信支付回调][%s][%s]订单支付失败 失败原因:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $e->getMessage()), 'info');
//错误信息 触发
return $fail('Order error.');
}
} else {
return $fail('通信失败,请稍后再通知我');
}
return true;
});
$response->send();
}
}
/**
* 记录订单日志
*
* @param string $message
* @param string $type
*/
private function log(string $message, string $type = 'info'): void
{
Log::channel('order')->write($message, $type);
}
}

283
app/controller/Login.php Normal file
View File

@ -0,0 +1,283 @@
<?php
namespace app\controller;
use app\exception\RepositoryException;
use app\repository\CommonRepository;
use app\validate\Account as VAccount;
use app\repository\AccountRepository;
use Exception;
use Overtrue\Socialite\SocialiteManager;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Config;
use think\facade\Log;
use think\response\Json;
use think\response\Redirect;
use think\response\View;
class Login extends Base
{
protected $middleware = ['csrf'];
public function index()
{
$referer = input('param.url/s', '/');
$referer = urldecode($referer);
$auth = session('frontend_auth');
if ($auth) {
return $this->redirect($referer);
}
session('login_return', $referer);
if ($this->request->isPost()) {
$username = input('post.username/s');
$password = input('post.password/s');
if (empty($username) || empty($password)) {
return $this->json(4001, '参数错误');
}
$user = AccountRepository::getInstance()->infoByPhone($username);
if (!$user) {
if (!$user = AccountRepository::getInstance()->infoByUsername($username)) {
return $this->json(4002, '账号或密码错误');
}
}
if ($user['password'] !== md5($password)) {
return $this->json(4003, '密码错误若手机验证码方式注册初始密码为手机号后6位');
}
unset($user['password']);
session('frontend_auth', $user->toArray());
$referer = session('login_return') ?? '/';
return $this->json(0, 'success', ['login_return' => $referer]);
}
return $this->view();
}
public function phone()
{
$referer = input('param.url/s', '/');
$referer = urldecode($referer);
$auth = session('frontend_auth');
if ($auth) {
return $this->redirect($referer);
}
session('login_return', $referer);
if ($this->request->isPost()) {
$phone = input('post.phone/s');
$code = input('post.code/s');
if (empty($phone) || empty($code)) {
return $this->json(4001, '参数错误');
}
if (!CommonRepository::getInstance()->checkSms($phone, $code, CommonRepository::SMS_TYPE_LOGIN)) {
return $this->json(4002, '短信验证码错误');
}
$user = AccountRepository::getInstance()->infoByPhone($phone);
if (!$user) {
$password = substr(trim($phone), -6);
$data['mobile'] = $phone;
$data['password'] = md5($password);
$data['nickname'] = trim($phone);
$data['status'] = 'normal';
$data['created_at'] = date('Y-m-d H:i:s');
$user = AccountRepository::getInstance()->create($data);
}
session('frontend_auth', $user);
$referer = session('login_return') ?? '/';
return $this->json(0, 'success', ['login_return' => $referer]);
}
return $this->view();
}
/**
* 微信登录
*
* @return Redirect|View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws RepositoryException
*/
public function wechat()
{
$code = input('code/s');
Config::load('extra/wechat', 'wechat');
$wechatConfig = config('wechat');
$referer = session('login_return') ?? '/';
if ($this->auth) {
return $this->redirect($referer);
} else {
if ($code) {
$config = [
'wechat' => [
'client_id' => $wechatConfig['openAppId'],
'client_secret' => $wechatConfig['openAppSecret'],
'redirect' => $wechatConfig['open_notify_url'],
],
];
$socialite = new SocialiteManager($config);
$user = $socialite->driver('wechat')->user();
$wechatUser = $user->getOriginal();
// $wechatUser = [
// 'openid' => 'o05Qy6rt1l7NOjrZsViC2bvS75j0',
// 'nickname' => '拙言',
// 'sex' => '1',
// 'language' => 'language',
// 'city' => 'chengdu ',
// 'province' => '四川',
// 'country' => '中国',
// 'headimgurl' => 'https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTIZib13lH3Sicc1BO189ibaqohRtXr3OuHw3xSHibn611kaGmmLvppOD5hHyE5IJmicTDpdwCEDw4LF9Xw/132',
// 'unionid' => 'oIrzJv6Vk8s8Hg_rJuNB8muquziw',
// ];
if (empty($wechatUser)) {
}
$account = AccountRepository::getInstance()->findOneByWhere(['unionid' => $wechatUser['unionid']]);
$data = [];
$now = date('Y-m-d H:i:s');
if (!$account) {
//无账号 新建账号
$data = $wechatUser;
$data['created_at'] = $now;
$data['status'] = AccountRepository::STATUS_NORMAL;
$account = AccountRepository::getInstance()->create($wechatUser);
}
$data['login_ip'] = $this->request->ip();
$data['last_login'] = $now;
session('frontend_auth', $account->toArray());
$account->save($data);
if (empty($account['mobile'])) {
//没有手机号 跳转绑定
return $this->redirect('/login/binding');
}
return $this->redirect($referer);
}
}
$openAppId = $wechatConfig['openAppId'] ?? '';
$redirect = $wechatConfig['open_notify_url'] ?? '';
$this->data['redirect'] = urlencode($redirect);
$this->data['openAppId'] = $openAppId;
return $this->view();
}
/**
* 常规注册
*
* @throws Exception
*/
public function register(): Json
{
if ($this->request->isPost()) {
$post = input('post.');
$validate = new VAccount();
if (!$validate->scene('register')->check($post)) {
return $this->json(4001, $validate->getError());
}
if (!CommonRepository::getInstance()->checkSms($post['phone'], $post['code'], CommonRepository::SMS_TYPE_REGISTER)) {
return $this->json(4002, '验证码错误');
}
try {
AccountRepository::getInstance()->registerByNormal($post);
} catch (RepositoryException $e) {
return $this->json(4003, $e->getMessage());
} catch (Exception $e) {
Log::error(sprintf("[注册失败]%s:%s %s", $e->getFile(), $e->getLine(), $e->getMessage()));
return $this->json(5001, '注册失败');
}
return $this->json();
}
}
/**
* 发送注册验证码
*
* @return Json
*/
public function sms(): Json
{
$post = input('post.');
$validate = new VAccount();
if (!$validate->scene('send_sms')->check($post)) {
return $this->json(4001, $validate->getError());
}
if (CommonRepository::getInstance()->sendSms($post['phone'], $post['type'])) {
return $this->json();
}
return $this->json(4002, '验证码发送失败');
}
/**
* 绑定手机号
*
* @return Redirect|Json|View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws RepositoryException
*/
public function binding()
{
if ($this->request->isPost()) {
$post = input('post.');
$validate = new VAccount();
if (!$validate->scene('binding')->check($post)) {
return $this->json(4001, $validate->getError());
}
if (!$account = AccountRepository::getInstance()->info($this->auth['id'] ?? 0)) {
return $this->json(4006, '请先登录');
}
if (!empty($account['mobile'])) {
return $this->json(4007, '您已绑定手机号,无需重复绑定!');
}
if (AccountRepository::getInstance()->infoByPhone($post['phone'])) {
return $this->json(4005, '该手机已绑定账号');
}
if (!CommonRepository::getInstance()->checkSms($post['phone'], $post['code'], CommonRepository::SMS_TYPE_BINDING)) {
return $this->json(4002, '验证码错误');
}
try {
$account->save(['mobile' => $post['phone']]);
} catch (RepositoryException $e) {
return $this->json(4003, $e->getMessage());
} catch (Exception $e) {
CommonRepository::log('绑定手机号失败', $e, 'error');
return $this->json(5001, '绑定手机号失败');
}
return $this->json();
} else {
if (!$account = AccountRepository::getInstance()->info($this->auth['id'] ?? 0)) {
return $this->redirect('/login');
}
if (!empty($account['mobile'])) {
return $this->redirect('/');
}
}
return $this->view();
}
}

28
app/controller/Page.php Normal file
View File

@ -0,0 +1,28 @@
<?php
namespace app\controller;
use app\model\{Category, Block};
class Page extends Base
{
public function index()
{
$categoryId=$this->request->param("category_id");
$category = Category::getById($this->request->param("category_id"));
if ($category) {
$description = $category['description'] ?: $this->system['seo_description'];
$this->setSeo($category['title'], $this->system['seo_keywords'], $description);
} else {
return $this->error('错误页面');
}
$childCategory = Category::getChildrenByParentId($categoryId);
$this->data['categoryId'] = $categoryId;
$this->data['category'] = $category;
$this->data['childCategory'] = $childCategory;
$this->data['blocks'] = Block::getByCategoryId($categoryId);
return $this->view($category['template_detail']);
}
}

40
app/controller/Search.php Normal file
View File

@ -0,0 +1,40 @@
<?php
namespace app\controller;
use app\repository\AccountRepository;
use app\repository\GoodsRepository;
use app\repository\OperationRepository;
use Exception;
use think\response\View;
class Search extends Base
{
/**
* 搜索
*
* @return View
* @throws Exception
*/
public function index(): View
{
$tag = input('get.tag/s', 'goods');
$keyword = input('get.keyword/s', '');
$pageParams['query'][] = input('get.');
$where['size'] = 50;
$where['where'][] = ['type', '=', $tag];
$where['where'][] = ['status', '=', GoodsRepository::STATUS_ON];
$where['where'][] = ['stock', '>', 0];
$where['where'][] = ['title', 'like', '%'.$keyword.'%'];
$items = GoodsRepository::getInstance()->findListWithPaginate($where, $pageParams);
$position = ['search_banner'];
$slides = OperationRepository::getInstance()->slideListByPosition($position);
$collectedIds = $this->authId ? AccountRepository::getInstance()->getCollectedIds($this->authId, $tag) : [];
$this->data['items'] = $items;
$this->data['collectedIds'] = $collectedIds;
$this->data['slide'] = $slides;
return $this->view();
}
}

View File

@ -0,0 +1,272 @@
<?php
namespace app\controller\api;
use app\model\AccountRecord;
use app\model\Disease;
use app\repository\ArchivesRepository;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
use app\exception\RepositoryException;
class Archives extends Base
{
protected $noNeedLogin = ['course', 'detail'];
/**
* 病种列表
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function disease(): Json
{
$data = Disease::getListByPid();
return $this->json(0, 'success', $data);
}
/**
* 病种问题文章列表 分类问题
*
* @return Json
*/
public function diseaseQuestion(): Json
{
$diseaseId = input('disease_id/d', 0);
try {
$data = ArchivesRepository::getInstance()->diseaseQuestion($diseaseId);
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
} catch (Exception $e) {
ArchivesRepository::log($e->getMessage(), $e);
return $this->json(5000, '操作失败');
}
}
/**
* 恒美小课堂
*
* @return Json
* @throws Exception
*/
public function course(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$courseId = input('course_id/d', 0);
$page = input('page/d', 1);
$size = input('size/d', 20);
try {
$data = ArchivesRepository::getInstance()->course($accountId, $courseId, $page, $size);
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
} catch (Exception $e) {
ArchivesRepository::log($e->getMessage(), $e);
return $this->json(5000, '操作失败');
}
}
/**
* 热门推荐
*
* @return Json
* @throws Exception
*/
public function hot(): Json
{
$categoryId = input('category_id/d', 0);
$page = input('page/d', 1);
$size = input('size/d', 20);
$keyword = input('keyword/s', '');
$accountId = $this->request->user['user_id'] ?? 0;
try {
$where[] = ['hot', '=', 1];
if (!empty($keyword)) {
$keyword = trim($keyword);
$where[] = ['title|subtitle|disease_name|doctor_name', 'like', '%'.$keyword.'%'];
AccountRecord::saveSearch($accountId, $keyword);
}
$data = ArchivesRepository::getInstance()->category($accountId, $categoryId, $where, $page, $size);
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
} catch (Exception $e) {
ArchivesRepository::log($e->getMessage(), $e);
return $this->json(5000, '操作失败');
}
}
/**
* 获取指定栏目内容列表
*
* @return Json
* @throws Exception
*/
public function category(): Json
{
$categoryId = input('category_id/d', 0);
$page = input('page/d', 1);
$size = input('size/d', 20);
$keyword = input('keyword/s', '');
$diseaseIds = input('disease_id/s', '');//病种 多个用逗号分隔
$accountId = $this->request->user['user_id'] ?? 0;
try {
$where = [];
if (!empty($keyword)) {
$keyword = trim($keyword);
$where[] = ['title|subtitle|disease_name|doctor_name', 'like', '%'.$keyword.'%'];
AccountRecord::saveSearch($accountId, $keyword);
}
if (!empty($diseaseIds)) {
$where[] = ['disease_id', 'in', explode(',', $diseaseIds)];
}
$data = ArchivesRepository::getInstance()->category($accountId, $categoryId, $where, $page, $size);
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
} catch (Exception $e) {
ArchivesRepository::log($e->getMessage(), $e);
return $this->json(5000, '操作失败');
}
}
/**
* 获取关于我们栏目内容列表
*
* @return Json
* @throws Exception
*/
public function about(): Json
{
$categoryId = input('category_id/d', 0);
$page = input('page/d', 1);
$size = input('size/d', 20);
$exceptId = input('except_id/d', 0);
$keyword = input('keyword/s', '');
$accountId = $this->request->user['user_id'] ?? 0;
try {
$where = [];
if (!empty($keyword)) {
$keyword = trim($keyword);
$where[] = ['title|subtitle|disease_name|doctor_name', 'like', '%'.$keyword.'%'];
AccountRecord::saveSearch($accountId, $keyword);
}
if ($exceptId > 0) {
$where[] = ['id', '<>', $exceptId];
}
$order = ['published_at' => 'desc'];
$data = ArchivesRepository::getInstance()->about($accountId, $categoryId, $where, $page, $size, $order);
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
} catch (Exception $e) {
ArchivesRepository::log($e->getMessage(), $e);
return $this->json(5000, '操作失败');
}
}
/**
* 内容详情
*
* @return Json
* @throws Exception
*/
public function detail(): Json
{
$id = input('id/d', 0);
$shareId = input('share_id/d', 0);//分享人ID
$accountId = $this->request->user['user_id'] ?? 0;
try {
$data = ArchivesRepository::getInstance()->detail($id, $accountId, $shareId);
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
} catch (Exception $e) {
ArchivesRepository::log($e->getMessage(), $e);
return $this->json(5000, '获取详情失败');
}
}
/**
* 点赞、收藏
*/
public function record(): Json
{
if (!$this->request->isPost()) {
return $this->json(4000, '无效请求');
}
$accountId = $this->request->user['user_id'] ?? 0;
$archiveId = $this->request->param('archive_id/d', 0);
$action = $this->request->param('action/s', '');
try {
ArchivesRepository::getInstance()->record($accountId, $archiveId, $action);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
}
return $this->json();
}
/**
* 取消 点赞、收藏
*/
public function unRecord(): Json
{
if (!$this->request->isPost()) {
return $this->json(4000, '无效请求');
}
$accountId = $this->request->user['user_id'] ?? 0;
$archiveId = $this->request->param('archive_id/d', 0);
$action = $this->request->param('action/s', '');
try {
ArchivesRepository::getInstance()->unRecord($accountId, $archiveId, $action);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
}
return $this->json();
}
/**
* 用户内容收藏列表
*/
public function collects(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$categoryId = $this->request->param('category_id/d', 0);
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 10);
$page = $page <= 0 ? 1 : $page;
$size = $size <= 0 ? 10 : $size;
$data = ArchivesRepository::getInstance()->accountCollects($accountId, $categoryId, $page, $size);
return $this->json(0, 'success', $data);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace app\controller\api;
use app\controller\BaseController;
/**
* API控制器基础类
*/
class Base extends BaseController
{
// 布尔值数字关系
public const BOOL_FALSE = 0;
public const BOOL_TRUE = 1;
protected function initialize()
{
parent::initialize();
$this->middleware = [
'jwt',
'apiLogin' => ['except' => $this->noNeedLogin]
];
}
public function __call($method, $args)
{
return $this->json(4004, 'error request!');
}
}

View File

@ -0,0 +1,94 @@
<?php
namespace app\controller\api;
use app\exception\RepositoryException;
use app\repository\AccountRepository;
use app\repository\CommonRepository;
use app\repository\OperationRepository;
use app\repository\OrderRepository;
use app\service\Sms;
use app\validate\CommonValidate;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
class Common extends Base
{
protected $noNeedLogin = [
'slidePositions',
'slides',
];
/**
* 发送短信验证码
*
* @OA\Post(
* path="/common/send-code",
* tags={"common"},
* operationId="sendCode",
* )
*/
public function sendCode(): Json
{
$input = input('post.');
$validate = new CommonValidate();
if (!$validate->scene('send_sms')->check($input)) {
return $this->json(4001, '参数错误');
}
if (!in_array($input['type'], ['register', 'login', 'binding'])) {
return $this->json(4002, '参数错误');
}
CommonRepository::getInstance()->sendSms($input['phone'], $input['type']);
return $this->json();
}
/**
* 查看轮播图可视位置配置信息
*/
public function slidePositions(): Json
{
$repo = OperationRepository::getInstance();
$list = $repo->slidePositions();
return $this->json(0, 'success', $list);
}
/**
* 轮播图
*/
public function slides(): Json
{
$size = $this->request->param('size/d', 0);
$position = trim($this->request->param('position/s', ''));
if (empty($position)) {
return $this->json();
}
try {
$repo = OperationRepository::getInstance();
$list = $repo->slideListByPosition($position, $size);
} catch (\Exception $e) {
$list = new Collection();
}
return $this->json(0, 'success', $list);
}
/**
* 获取快递公司列表
*
* @throws ModelNotFoundException
* @throws DbException
* @throws DataNotFoundException
*/
public function expressList(): Json
{
$list = OrderRepository::getInstance()->allExpress();
return $this->json(0, 'success', $list);
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace app\controller\api;
use app\exception\RepositoryException;
use app\repository\GoodsRepository;
use app\validate\Goods as GoodsValidate;
use Exception;
use think\response\Json;
/**
* 测试用
*
* Class DepartmentGoodsListLog
* @package app\controller\api
*/
class DepartmentGoodsListLog extends Base
{
/**
* @return Json
* @throws RepositoryException
*/
public function list()
{
$params = $this->request->param();
$validate = new GoodsValidate();
if (!$validate->scene('base')->check($params)) {
return $this->json(4001, $validate->getError());
}
$data = GoodsRepository::getInstance()->list();
return $this->json(0, 'success', $data);
}
/**
* 获取分类列表
*
* @return Json
* @throws Exception
*/
public function category()
{
$params = $this->request->param();
$validate = new GoodsValidate();
if (!$validate->scene('base')->check($params)) {
return $this->json(4001, $validate->getError());
}
$data = GoodsRepository::getInstance()->categoryList();
return $this->json(0, 'success', $data);
}
public function testApiClassMethod()
{
$header = $this->request->header();
$all = $this->request->param();
$get = input('get.');
$post = input('post.');
return $this->json(0, 'success', ['cost'=>$cost ?? 0]);
}
}

View File

@ -0,0 +1,100 @@
<?php
namespace app\controller\api;
use app\exception\RepositoryException;
use app\job\NotifySms;
use app\model\AccountFootmarks;
use app\model\HotKeyword;
use app\repository\AccountRepository;
use app\service\ExtraConfig;
use think\Collection;
use think\facade\Queue;
use think\response\Json;
class Index extends Base
{
protected $noNeedLogin = [
'miniProgramSetting',
'clearFootmarks',
'hotKeywords'
];
public function index(): Json
{
return json(['code' => 0, 'msg' => 'I am index']);
}
/**
* 测试用
*
* @return Json
* @throws RepositoryException
*/
public function test(): Json
{
$userId = $this->request->middleware('userInfo')['user_id'] ?? 0;
$user = AccountRepository::getInstance()->info($userId, []);
return json(['code' => 0, 'msg' => 'I am test ', 'data' => $user]);
}
public function login(): Json
{
$userId = $this->request->middleware('userInfo')['user_id'] ?? 0;
return json(['code' => 0, 'msg' => 'I am login '.$userId]);
}
public function notify()
{
$beginNotifyList = AccountRepository::getInstance()->getBeginNotifyList();
// $res = Queue::later(3, NotifySms::class, $beginNotifyList);
// $getSuccessList = AccountRepository::getInstance()->getSuccessList();
return $this->json(0, 'success', $beginNotifyList);
}
/**
* 小程序个性装修配置
*/
public function miniProgramSetting(): Json
{
$conf = ExtraConfig::miniProgram();
return $this->json(0, 'success', $conf);
}
/**
* 推荐显示的热搜词
*/
public function hotKeywords(): Json
{
try {
$type = input('type/s',"");
$list = HotKeyword::allRecommends($type);
} catch (\Exception $e) {
$list = new Collection();
}
return $this->json(0, 'success', $list);
}
/**
* 清理过期足迹
*
* @return Json
*/
public function clearFootmarks(): Json
{
try {
//清理N天以前的数据
$day = 30;
$time = date('Y-m-d H:i:s', time() - $day * 86400);
$count = AccountFootmarks::where('created_at', '<', $time)->count();
AccountFootmarks::where('created_at', '<', $time)->delete();
return $this->json(0, '成功清理足迹(条):'.$count);
} catch (\Exception $e) {
return $this->json(5000, '清理足迹失败');
}
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace app\controller\api;
use app\model\Account;
use app\model\AccountLevel;
use app\repository\AccountRepository;
use think\response\Json;
class Level extends Base
{
protected $noNeedLogin = [
];
public function index(): Json
{
$userId = $this->request->user['user_id'] ?? 0;
$user = Account::findById($userId);
if (empty($user)) {
return json(['code' => 6001, 'msg' => '未登录']);
}
$level = AccountRepository::getInstance()->getUserLevel($user["coin_total"]);
$nextLevel = AccountRepository::getInstance()->getUserNextLevel($level["value"]);
if (!empty($nextLevel)) {
$nextLevel["disparity"] = ( $nextLevel["value"] - $user['coin_total']);
}
return $this->json(0, "ok", [
"level" => $level,
"nextLevel" => $nextLevel,
"nickname" => $user['nickname'],
"headimgurl" => $user['headimgurl'],
]);
}
}

View File

@ -0,0 +1,406 @@
<?php
namespace app\controller\api;
use app\exception\RepositoryException;
use app\repository\OrderRepository;
use app\validate\OrderValidate;
use app\model\Order as OrderModel;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
/**
* 订单
*
* Class Order
* @package app\controller\api
*/
class Order extends Base
{
/**
* 创建订单
*
* @return Json
* @throws GuzzleException
*/
public function create(): Json
{
if ($this->request->isPost()) {
$params = $this->request->param();
$accountId = $this->request->user['user_id'] ?? 0;
try {
$data = OrderRepository::getInstance()->createOrder($accountId, $params);
OrderRepository::getInstance()->updateSpuStock([]);
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
OrderRepository::log('订单创建失败', $e, 'error', 'order');
return $this->json(5000, '订单创建失败');
}
}
return $this->json(4002, '请求错误');
}
/**
* 购物车列表
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function shoppingCart(): Json
{
$params = $this->request->param();
$accountId = $this->request->user['user_id'] ?? 0;
$type = $params['type'] ?? '';
$page = $params['page'] ?? 1;
$size = $params['size'] ?? 20;
$data = OrderRepository::getInstance()->shoppingCart($accountId, $type, $page, $size);
return $this->json(0, 'success', $data);
}
/**
* 添加购物车
*
* @return Json
* @throws Exception
*/
public function shoppingCartAdd(): Json
{
if ($this->request->isPost()) {
$params = $this->request->param();
$accountId = $this->request->user['user_id'] ?? 0;
$rules = [
'sku_id|商品' => 'require|number',
'num|数量' => 'require|number',
];
$validate = $this->validateByApi($params, $rules);
if ($validate !== true) {
return $validate;
}
try {
OrderRepository::getInstance()->shoppingCartAdd($accountId, $params['sku_id'], $params['num'] ?? 1);
return $this->json();
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
OrderRepository::log('购物车添加失败', $e);
return $this->json(5000, '购物车添加失败');
}
}
return $this->json(4002, '请求错误');
}
/**
* 购物车商品数量变更
*
* @return Json
* @throws Exception
*/
public function shoppingCartChangeNum(): Json
{
if ($this->request->isPost()) {
$params = $this->request->param();
$rules = [
'id|ID' => 'require|number',
'num|数量' => 'require|number',
];
$validate = $this->validateByApi($params, $rules);
if ($validate !== true) {
return $validate;
}
try {
OrderRepository::getInstance()->shoppingCartChangeNum($params['id'], $params['num']);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
OrderRepository::log('购物车数量加减失败', $e);
return $this->json(5000, '操作失败');
}
return $this->json();
}
return $this->json(4002, '请求错误');
}
/**
* 购物车商品删除
*
* @return Json
*/
public function shoppingCartDel(): Json
{
if ($this->request->isPost()) {
$id = input('post.id/d', 0);
$accountId = $this->request->user['user_id'] ?? 0;
if (!$id) {
return $this->json(4001, '参数错误');
}
try {
OrderRepository::getInstance()->shoppingCartDel($accountId, $id);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
OrderRepository::log('购物车数量加减失败', $e);
return $this->json(5000, '操作失败');
}
return $this->json();
}
return $this->json(4002, '请求错误');
}
/**
* 订单准备信息
* 结算页面 获取商品数据及汇总金额
* @return Json
*/
public function prepareInfo(): Json
{
if ($this->request->isPost()) {
$params = $this->request->param();
$accountId = $this->request->user['user_id'] ?? 0;
try {
$data = OrderRepository::getInstance()->prepareInfo($accountId, $params);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
OrderRepository::log('获取订单前置信息失败', $e, 'error', 'order');
return $this->json(5000, '订单信息获取失败');
}
return $this->json(0, 'success', $data);
}
return $this->json(4002, '请求错误');
}
/**
* 支付成功通知
* 结算页面 获取商品数据及汇总金额
*
* @return Json
* @throws Exception
*/
public function paid(): Json
{
if ($this->request->isPost()) {
$params = $this->request->param();
$accountId = $this->request->user['user_id'] ?? 0;
$rules = [
'order_coding|订单编号' => 'require',
];
$validate = $this->validateByApi($params, $rules);
if ($validate !== true) {
return $validate;
}
try {
if (OrderRepository::getInstance()->setPaid($params['order_coding'])) {
return $this->json();
}
return $this->json(4003, '支付失败');
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
OrderRepository::log('支付成功通知操作失败', $e);
return $this->json(5000, '操作失败');
}
}
return $this->json(4002, '请求错误');
}
/**
* 订单验收 - 确认收货
*
* @return Json
*/
public function accepted(): Json
{
if (!$this->request->isPost()) {
return $this->json(4002, '请求错误');
}
$accountId = $this->request->user['user_id'] ?? 0;
$orderId = $this->request->param('order_id', 0);
try {
OrderRepository::getInstance()->orderAccepted($orderId, $accountId);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
}
return $this->json();
}
/**
* 发货
*
* @return Json
*/
public function ship(): Json
{
if (!$this->request->isPost()) {
return $this->json(4002, '请求错误');
}
$orderId = $this->request->param('order_id', 0);
$expressId = $this->request->param('express_id', 0);
$expressNumber = $this->request->param('express_number', 0);
try {
OrderRepository::getInstance()->orderShipping($orderId, $expressId, $expressNumber);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
}
return $this->json();
}
/**
* 查询订单物流
*
* @return Json
*/
public function logistics(): Json
{
$orderCoding = input('order_coding');
try {
$res = OrderRepository::getInstance()->logistics($orderCoding);
return $this->json(0, 'success', $res);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
OrderRepository::log('物流查询失败', $e);
return $this->json(5000, '获取物流信息失败');
}
}
/**
* 取消订单
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function cancel(): Json
{
if (!$this->request->isPost()) {
return $this->json(4002, '请求错误');
}
$orderCoding = $this->request->param('order_coding', 0);
$reason = $this->request->param('remarks', '');
try {
OrderRepository::getInstance()->setClosed($orderCoding, OrderModel::STATUS_CLOSED, $reason);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
}
return $this->json();
}
/**
* 订单付款
*
* @return Json
* @throws Exception
*/
public function pay(): Json
{
if (!$this->request->isPost()) {
return $this->json(4002, '请求错误');
}
$accountId = $this->request->user['user_id'] ?? 0;
$orderCoding = $this->request->param('order_coding', 0);
try {
$res = OrderRepository::getInstance()->pay($orderCoding, $accountId);
return $this->json(0, 'success', $res);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
}
}
/**
* 购物车数量
*
* @return Json
* @throws Exception
*/
public function shoppingCartCount(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$type = $this->request->param('type/s', 'spu');
try {
$count = OrderRepository::getInstance()->shoppingCartCount($accountId, $type);
return $this->json(0, 'success', ['count' => $count]);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
}
}
/**
* 商品sku核验
*
*/
public function check(): Json
{
$orderCoding = input('order_coding/s', '');
$id = input('id/d', 0);
$checkBy = input('check_user/d', 0);
$num = input('num/d', 1);
try {
OrderRepository::getInstance()->check($orderCoding, $id, $num, $checkBy);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
OrderRepository::log('订单商品核验失败', $e);
return $this->json(5000, '订单商品核验失败');
}
return $this->json();
}
/**
* 商品sku核验结果
*
*/
public function checkResult(): Json
{
$orderCoding = input('order_coding/s', '');
$id = input('id/d', 0);
$notCheckNum = input('not_check_num/d', 0);
try {
$res = OrderRepository::getInstance()->checkResult($orderCoding, $id, $notCheckNum);
return $this->json(0, 'success', ['result' => (int) $res]);
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
OrderRepository::log('订单商品核验结果获取失败', $e);
return $this->json(5000, '订单商品核验结果获取失败');
}
}
}

View File

@ -0,0 +1,152 @@
<?php
namespace app\controller\api;
use app\exception\RepositoryException;
use app\repository\BusinessRepository;
use app\repository\RechargeRepository;
use app\service\wx\WechatPay;
use app\model\Recharge as RechargeModel;
use think\facade\Db;
use think\facade\Log;
/**
* 充值
*
* Class Recharge
* @package app\controller\api
*/
class Recharge extends Base
{
protected $noNeedLogin = ['query'];
/**
* 查询是否支付成功
* */
public function query()
{
$orderNum = input("order_num/s");
if (empty($orderNum)) {
return $this->json("4001", "参数错误");
}
$recharge = RechargeRepository::getInstance()->getModel()->where(["order_num" => $orderNum])->lock(true)->find();
if (empty($recharge)) {
return $this->json("4001", "订单不存在");
}
if ($recharge['state'] == RechargeModel::state_on) {
return $this->json();
}
$business = BusinessRepository::getInstance()->getModel()->where(["code" => $recharge['business_code']])->lock(true)->find();
if (empty($business)) {
return $this->json("4001", "商家不存在");
}
//查询 交易成功判断条件: return_code、result_code和trade_state都为SUCCESS
$res = WechatPay::getInstance()->order->queryByOutTradeNumber($orderNum);
if ($res['return_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
if (isset($res['result_code']) && $res['result_code'] == 'SUCCESS') {
if (isset($res['trade_state']) && $res['trade_state'] == 'SUCCESS') {
Db::startTrans();
try {
//这里确定支付成功
$total_fee = $res['total_fee'] / 100;
//加余额
$business->save(["balance" => ($business["balance"] + $total_fee)]);
//修改支付状态
$recharge->save([
"money" => $total_fee,
"state" => RechargeModel::state_on,
"update_time" => date("Y-m-d H:i:s"),
"balance" => $business->balance
]);
Db::commit();
return $this->json();
} catch (RepositoryException $e) {
Db::rollback();
return $this->json("5001", $e->getMessage());
} catch (\Exception $e) {
Db::rollback();
return $this->json("5001", "充值失败");
}
}
}
}
return $this->json("4001", "未支付成功");
}
/**
* 微信的回调
*
* @throws \EasyWeChat\Kernel\Exceptions\Exception
*/
public function notify(){
if ($this->request->isPost()) {
$app = WechatPay::getInstance();
$response = $app->handlePaidNotify(function ($message, $fail) {
// $aa = '{"appid":"wxa02e44170bc722cd","bank_type":"OTHERS","cash_fee":"1","fee_type":"CNY","is_subscribe":"N","mch_id":"1605090111","nonce_str":"60f7d8a1e4ac8","openid":"oKrEm0ehgsy2ZTWzEva4tbLuUgFw","out_trade_no":"16268555858753004863","result_code":"SUCCESS","return_code":"SUCCESS","sign":"DB3F6CDCB7FBB3B9DDF7C0CC8BBD5AAD","time_end":"20210721162000","total_fee":"1","trade_type":"JSAPI","transaction_id":"4200001200202107217942681078"}';
// $message = json_decode($aa, true);
$m = json_encode($message, JSON_UNESCAPED_UNICODE);
$recharge = RechargeRepository::getInstance()->getModel()->where(["order_num" => $message['out_trade_no']])->lock(true)->find();
if (empty($recharge)) {
$this->log(sprintf("[微信支付回调][%s][%s]订单支付成功,但系统查无此订单 info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'error');
return true;//订单不存在
}
if ($recharge['state'] == RechargeModel::state_on) {
return true;//订单已经支付
}
$business = BusinessRepository::getInstance()->getModel()->where(["code" => $recharge['business_code']])->lock(true)->find();
if (empty($business)) {
$this->log(sprintf("[微信支付回调][%s][%s]订单支付成功,但商家不存在 info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'error');
return true;
}
if ($message['return_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
if (isset($message['result_code']) && $message['result_code'] == 'SUCCESS') {
if (isset($message['trade_state']) && $message['trade_state'] == 'SUCCESS') {
Db::startTrans();
try {
//这里确定支付成功
$total_fee = $message['total_fee'] / 100;
//加余额
$business->save(["balance" => ($business["balance"] + $total_fee)]);
//修改支付状态
$recharge->save([
"money" => $total_fee,
"state" => RechargeModel::state_on,
"update_time" => date("Y-m-d H:i:s"),
"balance" => $business->balance
]);
Db::commit();
//记录日志
$this->log(sprintf("[微信支付回调][%s][%s]订单支付成功 info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'info');
return true;
} catch (RepositoryException $e) {
Db::rollback();
$this->log(sprintf("[微信支付回调][%s][%s]订单支付成功-修改订单状态失败-RepositoryException info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'info');
return $fail('Order status edit failed.');
} catch (\Exception $e) {
Db::rollback();
$this->log(sprintf("[微信支付回调][%s][%s]订单支付成功-修改订单状态失败-Exception info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'info');
return $fail('Order status edit failed.');
}
}
}
}
return $fail('通信失败,请稍后再通知我');
});
$response->send();
}
}
/**
* 记录订单日志
*
* @param string $message
* @param string $type
*/
private function log(string $message, string $type = 'info'): void
{
Log::channel('order')->write($message, $type);
}
}

181
app/controller/api/Sign.php Normal file
View File

@ -0,0 +1,181 @@
<?php
namespace app\controller\api;
use app\exception\RepositoryException;
use app\model\Account;
use app\model\AccountSignOnline;
use app\repository\AccountRepository;
use think\Exception;
use think\facade\Config;
use think\facade\Db;
use think\response\Json;
class Sign extends Base
{
protected $noNeedLogin = [];
/**
* 签到页面加载
* */
public function miniLoad()
{
Config::load('extra/base', 'base');
$baseConfig = config('base');
$score = isset($baseConfig['sign_score']) ? abs($baseConfig['sign_score']) : 1;
$userId = $this->request->user['user_id'] ?? 0;
if ($userId == 0) {
return $this->json(6001, "请先登录");
}
$account = Account::findOne(["id" => $userId], []);
if (empty($account)) {
return $this->json(6001, "请先登录");
}
//更新连续签到次数
AccountRepository::getInstance()->checkContinuitySign($account);
$weekDate = getLatelyWeekDate();
$weedSignInOnlineRecord = AccountRepository::getInstance()->weedSignInOnlineRecord($userId, $weekDate["1"]["date"], strtotime($weekDate["7"]["date"]) + 86399);
foreach ($weedSignInOnlineRecord as $item) {
$w = date("w", strtotime($item['created_at']));
if ($w == 0) {
$weekDate["1"]["record"] = $item["score"];
} else {
$weekDate[$w]["record"] = $item["score"];
}
$weekDate[$w]['is_sign'] = AccountSignOnline::COMMON_ON;//当天是否签到
}
$todaySignIn = AccountSignOnline::COMMON_OFF;
foreach ($weekDate as &$item) {
$key = date("m.d", strtotime($item['date']));
if (!isset($item['record'])) {
$item['record'] = $score;
$item['is_sign'] = AccountSignOnline::COMMON_OFF;//当天是否签到
}
if ($key == date("m.d")) {
$key = "今天";
if ($item['is_sign'] == AccountSignOnline::COMMON_ON) {
$todaySignIn = AccountSignOnline::COMMON_ON;
}
} elseif ($key == (date("m.d", strtotime("+1 day")))) {
$key = "明天";
}
$item["key"] = $key;
}
return $this->json(0, "操作成功", [
"sign_record" => $weekDate,
"reward_score" => $score,
"user_score" => $account['score'],
"today_sign_in" => $todaySignIn,
]);
}
/**
* 签到记录
* */
public function onlineSignRecord()
{
$userId = $this->request->user['user_id'] ?? 0;
if ($userId == 0) {
return $this->json(6001, "请先登录");
}
$page = input("page/d", 1);
$size = input("size/d", 10);
$record = AccountRepository::getInstance()->onlineSignRecordList($userId, $page, $size);
if ($record->isEmpty()) {
return $this->json(4001, "没有更多");
}
return $this->json(0, "ok", $record);
}
/**
* 线上签到
* */
public function onlineSingIn(): Json
{
//检查是否已经签到
$userId = $this->request->user['user_id'] ?? 0;
if ($userId == 0) {
return $this->json(6001, "请先登录");
}
$check = AccountRepository::getInstance()->checkSignInOnline($userId);
if ($check) {
return $this->json(4003, "今天已经签到了,请明天再来");
}
$account = Account::findOne(["id" => $userId], [], function ($q) {
return $q->lock(true);
});
if (empty($account)) {
return $this->json(6001, "请先登录");
}
//更新连续签到次数
AccountRepository::getInstance()->checkContinuitySign($account);
Config::load('extra/base', 'base');
$baseConfig = config('base');
$score = isset($baseConfig['sign_score']) ? abs($baseConfig['sign_score']) : 1;
Db::startTrans();
try {
AccountRepository::getInstance()->SignInOnline($account, $score);
Db::commit();
return $this->json();
} catch (Exception $e) {
Db::rollback();
$this->json(4003, "签到失败");
} catch (RepositoryException $e) {
Db::rollback();
$this->json(4003, "签到失败");
}
}
/**
* 线下签到
* */
public function SingIn(): Json
{
//检查是否已经签到
$userId = $this->request->user['user_id'] ?? 0;
if ($userId == 0) {
return $this->json(6001, "请先登录");
}
$check = AccountRepository::getInstance()->checkSignIn($userId);
if ($check) {
return $this->json(4003, "今天已经签到了,请明天再来");
}
Db::startTrans();
try {
AccountRepository::getInstance()->SignIn($userId);
Db::commit();
return $this->json();
} catch (Exception $e) {
Db::rollback();
$this->json(4003, "签到失败");
} catch (RepositoryException $e) {
Db::rollback();
$this->json(4003, "签到失败");
}
}
}

335
app/controller/api/Spu.php Normal file
View File

@ -0,0 +1,335 @@
<?php
namespace app\controller\api;
use app\controller\api\Base;
use app\exception\RepositoryException;
use app\model\AccountLevel;
use app\model\AccountRecord;
use app\model\AccountRole;
use app\model\Spu as SpuModel;
use app\model\Disease;
use app\model\SpuActivity;
use app\model\Staff;
use app\repository\OrderRepository;
use app\repository\SpuRepository;
use Exception;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Log;
use think\response\Json;
class Spu extends Base
{
protected $exceptExtra = ['list', 'category', 'detail'];
/**
* 商品列表筛选条件
*
* @throws ModelNotFoundException
* @throws DbException
* @throws DataNotFoundException
*/
public function condition(): Json
{
$list = [
'disease' => Disease::getListByPid(0, ['pid', 'name', 'id', 'sort']),
'doctor_roles' => AccountRole::findAccountRolesByGroupName(AccountRole::ROLE_GROUP_DOCTOR),
'activity' => SpuModel::activity(),
];
return $this->json(0, 'success', $list);
}
/**
* 获取已发布的商品列表
*
* @return Json
* @throws RepositoryException
* @throws Exception
*/
public function list(): Json
{
$repo = SpuRepository::getInstance();
$fields = SpuModel::spuListFields();
$params = input();
$params['fields'] = $fields;
$params['is_score'] = SpuModel::COMMON_OFF;//排除积分商品
$list = $repo->listForFront($params, function ($q) {
return $q->with([
'activity_info' => function ($query) {
$query->withoutField('content');
}
]);
});
return $this->json(0, 'success', $list);
}
/**
* 获取已发布的积分商品列表
*
* @return Json
* @throws RepositoryException
* @throws Exception
*/
public function score(): Json
{
$repo = SpuRepository::getInstance();
$type = input('type/s', SpuModel::TYPE_NORMAL);//normal=综合 newest=最新
$sortField = input('sort_field/s', '');// score=积分 num=兑换量
$sortValue = input('sort_value/s', '');//desc=降序 asc=升序
$rules = [
'page|页数' => 'integer|gt:0',
'size|每页数量' => 'integer|gt:0',
'type|类型' => 'in:newest,'.SpuModel::TYPE_NORMAL,
'sort_field|排序字段' => 'in:score,amount',
'sort_value|排序值' => 'in:asc,desc',
];
$message = [
'type.in' => '类型错误',
'$sortField.in' => '排序字段错误',
'sort_value.in' => '排序值错误',
];
$params = input();
$validate = $this->validateByApi($params, $rules, $message);
if ($validate !== true) {
return $validate;
}
$order = [];//排序
// 综合排序
if ($type === SpuModel::TYPE_NORMAL) {
$order = [
'sort' => 'desc',
'id' => 'desc',
];
}
// 最新排序
if ($type === 'newest') {
$order = ['published_at' => 'desc'];
}
// 兑换量排序
if (!empty($sortField)) {
if (empty($sortValue)) {
return $this->json(4003, '排序参数错误');
}
$order = [
$sortField => $sortValue
];
}
$params['is_score'] = SpuModel::COMMON_ON;
$params['fields'] = SpuModel::scoreListFields();
$list = $repo->listForFront($params, function ($q) {
return $q->with([
'activity_info' => function ($query) {
$query->withoutField('content');
}
]);
}, $order);
return $this->json(0, 'success', $list);
}
/**
* 收藏列表
*
* @return Json
* @throws Exception
*/
public function collection(): Json
{
$rules = [
'page|页数' => 'integer',
'size|每页数量' => 'integer',
];
$params = input();
$page = $params['page'] ?? 1;
$size = $params['size'] ?? 10;
$accountId = $this->request->user['user_id'] ?? 0;
$params['page'] = 1;
$params['size'] = 0;
$validate = $this->validateByApi($params, $rules);
if ($validate !== true) {
return $validate;
}
//获取收藏相关
$collection = AccountRecord::where('type', AccountRecord::TYPE_SPU)
->where('action', AccountRecord::ACTION_COLLECT)
->where('account_id', $accountId)
->where('is_record', AccountRecord::COMMON_ON)
->order('recorded_at', 'desc');
$total = $collection->count();
if ($total <= 0) {
return $this->json(0, 'success', [
'total' => 0,
'current' => $page,
'size' => $size,
'list' => new Collection(),
]);
}
$recordList = $collection->page($page)->limit($size)->field('relation_id,recorded_at')->select();
$where = [];
$where[] = ['id', 'in', $recordList->column('relation_id')];
$list = SpuRepository::getInstance()->listForFront($params, function ($q) {
return $q->with([
'activity_info' => function ($query) {
$query->withoutField('content');
}
]);
}, [], $where);
$data = [];
$spuList = $list['list']->toArray();
foreach ($recordList as $record) {
foreach ($spuList as $key => $spu) {
if ($record['relation_id'] == $spu['id']) {
$data[] = $spu;
unset($spuList[$key]);
}
}
}
$list['total'] = $total;
$list['current'] = $page;
$list['size'] = $size;
$list['list'] = $data;
return $this->json(0, 'success', $list);
}
/**
* SPU 详情
*/
public function detail(): Json
{
$repo = SpuRepository::getInstance();
$id = input('id/d', 0);
$shareId = input('share_id/d', 0);//分享人ID
$isActivity = input('is_activity/d', 0);//分享人ID
$accountId = $this->request->user['user_id'] ?? 0;
try {
$data = $repo->detail($id, $accountId, $shareId, (bool) $isActivity);
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
} catch (Exception $e) {
$repo->log($e->getMessage(), $e);
return $this->json(5000, '获取详情失败');
}
}
/**
* 获取指定活动商品的拼团列表 仅限拼团活动商品
*/
public function groupList(): Json
{
$id = input('id/d', 0);
try {
$data = OrderRepository::getInstance()->getGroupList($id);
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
} catch (Exception $e) {
SpuRepository::log($e->getMessage(), $e);
return $this->json(5000, '获取拼团列表失败');
}
}
/**
* 收藏
*/
public function record(): Json
{
if (!$this->request->isPost()) {
return $this->json(4000, '无效请求');
}
$accountId = $this->request->user['user_id'] ?? 0;
$id = $this->request->param('id/d', 0);
$action = $this->request->param('action/s', '');
try {
if ($accountId <= 0 || $id <= 0) {
return $this->json(4001, '无效请求');
}
if (!in_array($action, AccountRecord::allowActions())) {
return $this->json(4001, '操作类型参数错误');
}
if (!SpuModel::findById($id)) {
return $this->json(4001, '商品不存在');
}
AccountRecord::record($accountId, AccountRecord::TYPE_SPU, $action, $id);
} catch (Exception $e) {
Log::error('[商品记录失败]'.$e->getMessage());
return $this->json(5000, '操作失败');
}
return $this->json();
}
/**
* 取消 收藏
*/
public function unRecord(): Json
{
if (!$this->request->isPost()) {
return $this->json(4000, '无效请求');
}
$accountId = $this->request->user['user_id'] ?? 0;
$id = $this->request->param('id/d', 0);
$action = $this->request->param('action/s', '');
try {
if ($accountId <= 0 || $id <= 0) {
return $this->json(4001, '无效请求');
}
if (!in_array($action, AccountRecord::allowActions())) {
return $this->json(4001, '操作类型参数错误');
}
if (!SpuModel::findById($id)) {
return $this->json(4001, '商品不存在');
}
AccountRecord::unRecord($accountId, $id, AccountRecord::TYPE_SPU, $action);
} catch (Exception $e) {
Log::error('[取消商品记录失败]'.$e->getMessage());
return $this->json(5000, '操作失败');
}
return $this->json();
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace app\controller\api;
use app\model\AccountFootmarks;
use app\model\Event;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
class Statistics extends Base
{
protected $noNeedLogin = ['event'];
/**
* 事件列表
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function event(): Json
{
$data = Event::field('id, name')->select()->toArray();
return $this->json(0, 'success', $data);
}
/**
* 上报
*
* @return Json
* @throws Exception
*/
public function report(): Json
{
$data = input();
$accountId = $this->request->user['user_id'] ?? 0;
if (empty($data)) {
return $this->json();
}
if (!is_array($data)) {
$data = json_decode($data, true);
}
$insert = [];
if (count($data) > 1000) {
//TODO 太大就分片处理
} else {
foreach ($data as $d) {
if (!isset($d['e']) || !isset($d['t'])) {
return $this->json(4001, '参数错误');
}
$arr = [];
$arr['event_id'] = (int) ($d['e'] ?? 0);
$arr['account_id'] = $accountId;
$arr['content_id'] = (int) ($d['c'] ?? 0);
$t = (strlen($d['t']) == 13) ? $d['t'] / 1000 : $d['t'];
$arr['created_at'] = date('Y-m-d H:i:s', $t);
$insert[] = $arr;
}
}
// 若量大 时间长 可丢入队列操作
if (count($insert) > 0) {
(new AccountFootmarks())->saveAll($insert);
}
return $this->json();
}
}

2164
app/controller/api/User.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
<?php
namespace app\controller\api\file;
use app\controller\api\Base;
use app\model\File;
use app\model\System;
use app\service\Image;
use app\validate\Upload as VUpload;
use think\facade\Config;
use think\facade\Filesystem;
use think\facade\Lang;
use think\response\Json;
/**
* 文件上传
*
* Class Upload
* @package app\controller\api\file
*/
class Upload extends Base
{
protected $noNeedLogin = [];
// 图片上传是否进行压缩[max-width:1920px]
private bool $isCompress = true;
private $validate = null;
// 文件上传对外默认保存目录(相对路径)
private string $uploadPath = '';
// 文件上传对外默认保存目录是否有写权限
private bool $uploadPathIsWritable = false;
protected bool $saveToOos = false;
public function initialize()
{
parent::initialize();
$system = System::getSystem();
if (!empty($system)) {
$this->isCompress = $system['compress'] ?? true;
}
$this->validate = new VUpload();
$this->uploadPath = Config::get('filesystem.disks.local.url');
if(is_writable(app()->getRootPath() . 'public' . $this->uploadPath)){
$this->uploadPathIsWritable = true;
}
$this->cancelTimeLimit();
}
/**
* 通用文件上传
* @return Json
*/
public function file()
{
$file = request()->file('file');
if (empty($file)) {
return $this->json(4001, '请上传的文件');
}
if($this->validate->checkFile($file)){
try{
if(!$this->uploadPathIsWritable){
throw new \Exception('上传文件夹需要写入权限');
}
$src = Filesystem::putFile(date('Ymd'), $file, 'uniqid');
$src = $this->uploadPath . '/' . $src;
$return['src'] = $src;
$return['name'] = $file->getOriginalName();
//加入上传文件表
File::add($file, $src, 'file');
} catch (\Exception $e) {
return $this->json(4003, $e->getMessage());
}
return $this->json(0,'success', $return);
}else{
$errorMsg = Lang::get($this->validate->getError());
return $this->json(4002, $errorMsg);
}
}
/**
* 通用图片上传
* @return Json
*/
public function image()
{
$image = request()->file('image');
if (empty($image)) {
return $this->json(4001, '请上传图片文件');
}
$md5 = $image->md5();//文件md5
if($this->validate->checkImage($image)){
try{
if(!$this->uploadPathIsWritable){
throw new \Exception('上传文件夹需要写入权限');
}
$src = Filesystem::putFile(date('Ymd'), $image, 'uniqid');
$src = $this->uploadPath . '/' . $src;
$return['src'] = $src;
if($this->isCompress){
Image::resize($src);
}
//加入上传文件表
File::add($image, $src,$md5);
} catch (\Exception $e) {
return $this->json(4003, $e->getMessage());
}
return $this->json(0, 'success', $return);
}else{
$errorMsg = Lang::get($this->validate->getError());
return $this->json(4002, $errorMsg);
}
}
/**
* 同步到OOS服务器存储
* @param string $src
*/
private function syncToOos(string $src)
{
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* @OA\Info(
* description="商城接口",
* version="1.0.0",
* title="大头商城",
* )
*/
/**
* @OA\Tag(
* name="common",
* description="通用",
* )
*
* @OA\Tag(
* name="home",
* description="首页",
* )
*
* @OA\Tag(
* name="goods",
* description="商品相关",
* )
* @OA\Tag(
* name="order",
* description="订单相关",
* )
* @OA\Tag(
* name="user",
* description="用户相关",
* )
*
*/

View File

@ -0,0 +1,488 @@
<?php
namespace app\controller\manager;
use app\model\Log;
use app\service\AliOss;
use think\facade\Config;
use Exception;
use app\model\Attachment as AttachmentModel;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\response\Json;
use think\response\View;
/**
* 附件管理 - 素材管理
* Class Attachment
* @package app\controller\manager
*/
class Attachment extends Base
{
protected $noNeedLogin = ['file', 'getSize', 'md5List', 'pathDirHandle', 'toOss', 'delLostFile', 'test'];
protected $DIRECTORY_SEPARATOR = "/";
protected function initialize()
{
parent::initialize(); // TODO: Change the autogenerated stub
$this->DIRECTORY_SEPARATOR = DIRECTORY_SEPARATOR == "\\" ? "/" : DIRECTORY_SEPARATOR;
}
/**
* 删除
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function del(): Json
{
if ($this->request->isPost()) {
$ids = input('post.ids/a', []);
if (empty($ids)) {
$ids[] = input('post.id/d');
}
$items = AttachmentModel::whereIn('id', $ids)->where('is_dir', AttachmentModel::COMMON_ON)->select();
if ($items->where('is_dir', AttachmentModel::COMMON_ON)->count()) {
$dirPaths = [];
foreach ($items->toArray() as $item) {
$dirPaths[] = $item['path'].$item['name']. $this->DIRECTORY_SEPARATOR ;
}
if (AttachmentModel::where('path', 'in', $dirPaths)->count()) {
return $this->json(4001, '待删除目录下存在内容!');
}
}
AttachmentModel::deleteByIds($ids);
Log::write(get_class().'Del', 'del', '涉及到的ID为'.implode(',', $ids));
return $this->json();
}
return $this->json(4001, '非法请求!');
}
/**
* 单个字段编辑
*
* @return Json
* @throws Exception
*/
public function modify(): Json
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'field' => 'require',
'value' => 'require',
]);
if ($validate !== true) {
return $validate;
}
if (!$info = AttachmentModel::findById($item['id'])) {
return $this->json(4001, '记录不存在');
}
if ($item['field'] == 'name' && $info['is_dir'] == AttachmentModel::COMMON_ON) {
return $this->json(4002, '目录名称不能修改');
}
$update = [$item['field'] => $item['value']];
try {
$info->save($update);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->json(4000, '非法请求');
}
/**
* 添加
*
* @return Json|View
* @throws Exception
*/
public function add()
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'title|合集标题' => 'require',
'user|虚拟用户' => 'require',
'headimg|虚拟用户头像' => 'require',
]);
if ($validate !== true) {
return $validate;
}
try {
$now = date('Y-m-d H:i:s');
$item['created_at'] = $now;
$item['created_by'] = $this->auth['user_id'];
AttachmentModel::create($item);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->view();
}
/**
* 添加文件夹
*
* @return Json|View
* @throws Exception
*/
public function addFolder()
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'name|文件夹名称' => 'require|alphaDash|max:20',
'path|文件路径' => 'require',
]);
// 例 name=dir4 path=/storage/dir1/dir2/dir3
// 去首尾/
$path = trim($item['path'], $this->DIRECTORY_SEPARATOR );
// 全路径 如 /storage/dir1/dir2/dir3/dir4/ 注意前后都有/
$fullPath = $this->DIRECTORY_SEPARATOR .$path. $this->DIRECTORY_SEPARATOR .$item['name']. $this->DIRECTORY_SEPARATOR ;
if ($validate !== true) {
return $validate;
}
AttachmentModel::pathDirHandle($fullPath);
return $this->json();
}
$path = input('path/s', AttachmentModel::ROOT_PATH);
$this->data['path'] = $path;
return $this->view();
}
/**
* 图片列表
*
* @return View|Json
* @throws Exception
*/
public function image()
{
$path = input('post.path', AttachmentModel::ROOT_PATH);
$path = $this->DIRECTORY_SEPARATOR . trim($path, $this->DIRECTORY_SEPARATOR). $this->DIRECTORY_SEPARATOR;
$path = str_replace("\\","/",$path);
$type = input('type/s', 'image');
$selected = input('selected', false);
$multiple = input('multiple', false);
Config::load('extra/alioss', 'alioss');
$config = config('alioss');
$oss = $config['customDomain'];
if ($this->request->isPost()) {
$items = $this->list($path, ['image']);
return $this->json(0, '操作成功', $items);
}
$this->data['path'] = $path;
$this->data['oss'] = $oss;
$this->data['type'] = $type;
$this->data['multiple'] = $multiple;
$this->data['selected'] = $selected;
return $this->view();
}
/**
* 视频列表
*
* @return View|Json
* @throws Exception
*/
public function video()
{
$path = input('post.path', AttachmentModel::ROOT_PATH);
$path = $this->DIRECTORY_SEPARATOR . trim($path, $this->DIRECTORY_SEPARATOR ) . $this->DIRECTORY_SEPARATOR ;
$path = str_replace("\\","/",$path);
$type = input('type/s', 'video');
$selected = input('selected', false);
$multiple = input('multiple', false);
Config::load('extra/alioss', 'alioss');
$config = config('alioss');
$oss = $config['customDomain'];
if ($this->request->isPost()) {
$items = $this->list($path, ['video']);
return $this->json(0, '操作成功', $items);
}
$this->data['path'] = $path;
$this->data['oss'] = $oss;
$this->data['type'] = $type;
$this->data['multiple'] = $multiple;
$this->data['selected'] = $selected;
return $this->view();
}
/**
* 文件列表
*
* @return View|Json
* @throws Exception
*/
public function file()
{
Config::load('extra/alioss', 'alioss');
$config = config('alioss');
$oss = $config['customDomain'];
$type = input('type/s', 'all');
$selected = input('selected', false);
$multiple = input('multiple', false);
if ($this->request->isPost()) {
$page = input('post.page', 1);
$size = input('post.size', 20);
$searchParams = input('searchParams');
$where = [];
if ($searchParams) {
foreach ($searchParams as $key => $param) {
if (!empty($param)) {
if (is_string($param)) {
if ($key == 'is_oss') {
if ($param >= 0) {
$where[] = ['is_oss', '=', $param];
}
} else {
$where[] = [$key, 'like', '%'.$param.'%'];
}
} elseif (is_array($param)) {
//数组空元素去除
foreach ($param as $k => $val) {
if (empty($val)) {
unset($param[$k]);
}
}
if (!empty($param)) {
$where[] = [$key, 'in', $param];
}
}
}
}
}
if ($type !== 'all') {
$where[] = ['type', '=', $type];
}
$items = AttachmentModel::findList($where, [], $page, $size, function ($q) {
return $q->where('type', '<>', 'dir')->order('updated_at', 'desc');
});
$items['list']->each(function ($item) {
$item->size_text = getFilesize($item['size'] ?? 0);
});
return $this->json(0, '操作成功', $items);
}
$this->data['oss'] = $oss;
$this->data['type'] = $type;
$this->data['multiple'] = $multiple;
$this->data['selected'] = $selected;
return $this->view();
}
/**
* 一键删除失效记录 即oss不存在&&本地不存在
*
* @return Json
*/
public function delLostFile(): Json
{
if ($this->request->isPost()) {
$total = AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
->where('is_dir', AttachmentModel::COMMON_OFF)
->where('is_oss', AttachmentModel::COMMON_OFF)
->where('has_local', AttachmentModel::COMMON_OFF)
->count();
if ($total === 0) {
return $this->json(0, 'success', ['total' => $total]);
}
if (AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
->where('is_dir', AttachmentModel::COMMON_OFF)
->where('is_oss', AttachmentModel::COMMON_OFF)
->where('has_local', AttachmentModel::COMMON_OFF)
->delete()) {
return $this->json(0, 'success', ['total' => $total]);
}
return $this->json(4004, '删除失败');
}
return $this->json(4000, '请求错误');
}
/**
* 一键上传本地文件到OSS
*
* @return Json
*/
public function toOss(): Json
{
if ($this->request->isPost()) {
Config::load('extra/alioss', 'alioss');
$config = config('alioss');
$ossObject = AliOss::instance();
$bucket = $config['bucket'];
$total = AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
->where('is_dir', AttachmentModel::COMMON_OFF)
->where('is_oss', AttachmentModel::COMMON_OFF)
->field('id')
->count();
$done = 0;
$none = 0;
if ($total === 0) {
return $this->json(0, 'success', ['total' => $total, 'done' => $done, 'none' => $none]);
}
try {
AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
->where('is_dir', AttachmentModel::COMMON_OFF)
->where('is_oss', AttachmentModel::COMMON_OFF)
->field('id,src')
->chunk(3, function ($items) use ($ossObject, $bucket, &$done, &$none) {
$doneIds = [];
$noneIds = [];
foreach ($items as $item) {
if ($item['src']) {
$realPath = public_path().ltrim($item['src'], $this->DIRECTORY_SEPARATOR );
if (!file_exists($realPath)) {
$none++;
$noneIds[] = $item['id'];
continue;
}
$pathInfo = pathinfo($item['src']);
$object = ltrim($item['src'], $this->DIRECTORY_SEPARATOR );
//是否存在
if (!$ossObject->doesObjectExist($bucket, $object)) {
//创建目录
$ossObject->createObjectDir($bucket, ltrim($pathInfo['dirname'], $this->DIRECTORY_SEPARATOR ));
$ossObject->uploadFile($bucket, $object, $realPath);
}
$doneIds[] = $item['id'];
$done++;
}
}
// 失效标记
if ($noneIds) {
$update = ['is_oss' => AttachmentModel::COMMON_OFF, 'has_local' => AttachmentModel::COMMON_OFF];
(new AttachmentModel())->where('id', 'in', $noneIds)->update($update);
}
// 完成标记
if ($doneIds) {
$update = ['is_oss' => AttachmentModel::COMMON_ON];
(new AttachmentModel())->where('id', 'in', $doneIds)->update($update);
}
});
return $this->json(0, 'success', ['total' => $total, 'done' => $done, 'none' => $none]);
} catch (Exception $e) {
\think\facade\Log::error('本地文件一键上传OSS失败 '.$e->getMessage());
return $this->json(0, 'success', ['total' => $total, 'done' => $done, 'none' => $none]);
}
}
}
/**
* 指定类型附件列表
*
* @param array $type
* @param string $path
* @return array
* @throws Exception
*/
protected function list(string $path, array $type): array
{
$type[] = 'dir';
$where[] = ['path', '=', $path];
$where[] = ['type', 'in', $type];
$items = AttachmentModel::findList($where, [], 1, 0, function ($q) {
return $q->order('is_dir', 'desc')->order('updated_at', 'desc');
});
$items['list']->each(function ($item) {
$item->size_text = getFilesize($item['size'] ?? 0);
});
$items['path'] = $path;
return $items;
}
/**
* 获取文件大小
*
* @return Json
*/
public function getSize(): Json
{
$path = input('post.path', '');
$types = input('post.type/a', []);
$size = '';
if (empty($path)) {
return $this->json(0, '操作成功', $size);
}
$path = str_replace("\\","/",$path);
$total = AttachmentModel::where('path', 'like', $path.'%')
->when(!empty($types), function ($q) use ($types) {
$q->where('type', 'in', $types);
})
->sum('size');
return $this->json(0, '操作成功', getFilesize($total));
}
// 将没有md5的文件 更新md5 仅针对本地文件
public function md5List()
{
$noMd5List = AttachmentModel::whereNull('md5')->select();
$update = [];
foreach ($noMd5List as $item) {
try {
if (!empty($item['src'])) {
$arr = [];
$path = public_path().ltrim($item['src'], $this->DIRECTORY_SEPARATOR );
$file = new \think\File($path);
$arr['md5'] = $file->md5();
$arr['id'] = $item['id'];
$update[] = $arr;
}
} catch (Exception $e) {
continue;
}
}
(new AttachmentModel())->saveAll($update);
}
}

View File

@ -0,0 +1,153 @@
<?php
namespace app\controller\manager;
use think\facade\{Db, Config, Env};
use app\model\{Log as MLog};
use app\service\Tool;
class Backup extends Base
{
/**
* 因受mysql 配置参数net_buffer_length和max_allowed_packet大小的限制因此insert语句改为单条插入
* show VARIABLES like "%net_buffer_length%" 默认单条sql语句长度16k
* show VARIABLES like "%max_allowed_packet%" 默认单个sql文件最大容量
* sql 文件注释 -- + 空格之后填写注释内容
* 因根目录文件夹权限限制因此需要手动创建backup/data目录并赋予权限www用户组
*/
public function back()
{
ini_set('max_execution_time', 0);
ini_set("memory_limit",-1);
set_time_limit(0);
$path = Config::get('filesystem.disks.backup.root') . '/';
$dataBase = Env::get('database.database');
// 不要使用单引号,双引号中的变量可以解析,单引号就是绝对的字符串
$eol = "\r\n";
$eolB = "\r\n\r\n";
$info = '-- ------------------------------'.$eol;
$info .= '-- 日期: '.date('Y-m-d H:i:s',time()).$eol;
$info .= '-- MySQL --Database - '.$dataBase.$eol;
$info .= '-- ------------------------------'.$eol;
$info .= 'CREATE DATABASE IF NOT EXISTS `'.$dataBase.'` DEFAULT CHARACTER SET "utf8mb4" COLLATE "utf8mb4_general_ci";'.$eolB;
$info .= 'USE `'.$dataBase.'`;'.$eol;
if(is_dir($path)) {
if(!is_writable($path)) {
chmod($path, 0755);
}
} else {
mkdir($path, 0755, true);
}
$fileName = $path.$dataBase.'_'.date('YmdHis',time()).'.sql';
if(file_exists($fileName)) {
@unlink($fileName);
}
// 以追加的方式写入
file_put_contents($fileName, $info, FILE_APPEND);
$tables = Db::query('show tables');
foreach ($tables as $table) {
// 表结构
$tableName = $table['Tables_in_'.$dataBase];
$sqlTable = 'SHOW CREATE TABLE '.$tableName;
$res = Db::query($sqlTable);
$infoTable = '-- ------------------------------'.$eol;
$infoTable .= '-- Table structure for `'.$tableName.'`'.$eol;
$infoTable .= '-- ------------------------------'.$eolB;
$infoTable .= 'DROP TABLE IF EXISTS `'.$tableName.'`;'.$eolB;
$infoTable .= $res[0]['Create Table'].';'.$eolB;
// 表数据
$infoTable .= '-- ------------------------------'.$eol;
$infoTable .= '-- Data for the table `'.$tableName.'`'.$eol;
$infoTable .= '-- ------------------------------'.$eolB;
file_put_contents($fileName, $infoTable, FILE_APPEND);
$sqlData = 'select * from '.$tableName;
$data = Db::query($sqlData);
$count = count($data);
if ($count > 0) {
$dataStr = 'INSERT INTO `'.$tableName.'` VALUE ';
foreach ($data as $k => $item) {
$valStr = '(';
foreach ($item as $val) {
// 字符串转义
$val = addslashes($val);
$valStr .= '"'.$val.'", ';
}
// 去除最后的逗号和空格
$valStr = substr($valStr,0,strlen($valStr)-2);
// 限制单条sql语句在16K以内可根据mysql配置条件进行调整
$sqlLength = strlen($dataStr) + strlen($valStr);
if($sqlLength >= (1024 * 16 - 10)) {
$dataStr .= $valStr.');'.$eol;
file_put_contents($fileName, $dataStr, FILE_APPEND);
// 提前分段写入后需重置数据语句
if ($k <= ($count-1)) {
$dataStr = 'INSERT INTO `'.$tableName.'` VALUE ';
} else {
$dataStr = '';
}
} else {
if ($k < ($count-1)) {
$dataStr .= $valStr.'),'.$eol;
} else {
$dataStr .= $valStr.');'.$eolB;
}
}
}
file_put_contents($fileName, $dataStr, FILE_APPEND);
}
}
clearstatcache();
$backups = explode('/', $fileName);
$backupName = $backups[count($backups)-1];
$src = Config::get('filesystem.disks.backup.url') . '/';
return $this->json(0, '备份成功:' . $src . $backupName);
}
public function index()
{
$path = Config::get('filesystem.disks.backup.root') . '/';
$src = Config::get('filesystem.disks.backup.url') . '/';
$items = [];
if(is_dir($path)) {
if(!is_readable($path)) {
chmod($path,0755);
}
$files = scandir($path);
foreach ($files as $file) {
if($file != '.' && $file != '..') {
$ext = substr($file, -4);
if ($ext == '.sql') {
$creatTime = substr($file, -18, 14);
$items[] = [
'file' => $file,
'path' => $src . $file,
'time' =>is_numeric($creatTime) ? date('Y-m-d H:i:s', strtotime($creatTime)) : '',
];
}
}
}
}
clearstatcache();
$this->data['items'] = $items;
$this->data['backupPath'] = str_replace('\\','/', $path);
return $this->view();
}
public function del()
{
if (request()->isPost()) {
$filePath = input('post.id');
Tool::delFile($filePath);
MLog::write('backup', 'del', '删除了备份数据文件,文件路径为:' . $filePath);
return $this->json();
} else {
return $this->json(1, '非法请求');
}
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace app\controller\manager;
use app\controller\BaseController;
use app\service\File as FileTool;
use Exception;
use think\exception\ValidateException;
use think\response\Json;
use think\response\Redirect;
use think\response\View;
/**
* 控制器基础类
*/
class Base extends BaseController
{
protected $data = [];
protected $auth = null;
protected function initialize()
{
$this->middleware = [
'auth' => ['except' => array_merge($this->noNeedLogin, $this->noNeedRight)],
// 'jwt' => ['except' => $this->noNeedRight],
];
$this->auth = session('auth');
$this->data['member'] = $this->auth;
$this->data['_token'] = $this->auth['token'] ?? '';
$this->data['groupId'] = $this->auth['groupId'] ?? 0;
$this->fileDomain();
}
//变量赋值到模板
protected function view(string $template = '')
{
return view($template)->assign($this->data);
}
/**
* @param string $msg
* @param string|null $url
* @param string $data
* @param int $wait
* @return Redirect
*/
protected function error($msg = '', string $url = null, $data = '', int $wait = 3): Redirect
{
if (is_null($url)) {
$url = $this->request->isAjax() ? '' : 'javascript:history.back(-1);';
} elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url);
}
$result = [
'code' => 0,
'msg' => $msg,
'data' => $data,
'url' => $url,
'wait' => $wait,
];
return $this->redirect(url('/manager/error/jump', $result));
}
public function __call($name, $args)
{
return $this->view('/manager/error/jump');
}
/**
* 验证器
*
* @param array $data
* @param $validate
* @param array $message
* @param bool $batch
* @return Redirect
* @throws Exception
*/
protected function validateError(array $data, $validate, array $message = [], bool $batch = false): Redirect
{
try {
parent::validate($data, $validate, $message, $batch);
} catch (ValidateException $e) {
$msg = $e->getMessage();
if ($batch) {
$msg = implode(',', $e->getError());
}
return $this->error($msg);
} catch (Exception $e) {
throw $e;
}
}
/**
* 文件域名前缀
*/
public function fileDomain()
{
$this->data['fileDomain'] = FileTool::getFileDomain();
}
}

View File

@ -0,0 +1,364 @@
<?php
namespace app\controller\manager;
use app\exception\RepositoryException;
use app\model\BusinessFlow;
use app\model\Coupon;
use app\model\CouponMain;
use app\model\Recharge;
use app\model\Business as BusinessModel;
use app\model\Member;
use app\repository\BusinessRepository;
use app\repository\CouponRepository;
use app\repository\RechargeRepository;
use app\service\wx\WechatPay;
use Exception;
use think\facade\Db;
use think\response\Json;
use think\response\View;
/*商家*/
class Business extends Base
{
protected $noNeedLogin = ['queryManagerRecharge'];
/**
* 商家列表列表
*
* @return Json|View
* @throws Exception
*/
public function index()
{
if ($this->request->isPost()) {
$model = new BusinessFlow();
$repo = BusinessRepository::getInstance($model);
$keyword = $this->request->param('keyword/s', '');
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 30);
$whereMap = [["business.state", "=", BusinessModel::state_on]];
$orders = ['business.id' => 'desc'];
if (!empty($keyword)) {
$whereMap[] = ['account.nick_name|business.business_name', 'like', "%$keyword%"];
}
$list = $repo->businessList($whereMap, $page, $size, $orders);
$list["list"]->each(function ($item) {
//得到当前商家的所有优惠券
$date = date("Y-m-d H:i:s");
//优惠券总数
$item->coupon_total_count = CouponMain::where(["business_code" => $item->business->code])->sum("count");
//进行中优惠券总数
$item->coupon_doing_count = CouponMain::where(["business_code" => $item->business->code])
->whereTime("start_time", "<", $date)
->whereTime("end_time", ">", $date)
->where("status", CouponMain::status_on)
->where("on_shelf", CouponMain::on_shelf_on)
->sum("count");
//进行中优惠券总数
$item->coupon_receive_count = CouponMain::where(["business_code" => $item->business->code])->sum("received_count");
//过期未使用优惠券总数
$item->coupon_be_overdue_count = Coupon::where(["business_code" => $item->business->code])
->where("is_verificated", "=", Coupon::is_verificated_off)
->whereTime("end_time", "<", $date)
->count();
//已使用优惠券总数
$item->coupon_used_count = Coupon::where(["business_code" => $item->business->code])
->where("is_verificated", "=", Coupon::is_verificated_on)
->count();
//商家充值总额
$item->recharge_total_money = Recharge::where(["business_code" => $item->business->code])
->where("state", "=", Recharge::state_on)
->sum("money");
});
return $this->json(0, 'success', $list);
}
return $this->view();
}
/**
* 商家优惠券列表
*
* @return Json|View
* @throws Exception
*/
public function businessCouponList()
{
$businessCode = input("business_code/s", "");
if ($this->request->isPost()) {
event('CouponStatusCheck');
$repo = BusinessRepository::getInstance();
$keyword = $this->request->param('keyword/s', '');
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 30);
$whereMap = ["business_code" => $businessCode];
if (!empty($keyword)) {
$whereMap[] = ['name', 'like', "%$keyword%"];
}
$list = $repo->businessCouponList($whereMap, $page, $size, ["create_time" => "desc", "id" => "desc"]);
return $this->json(0, 'success', $list);
}
$this->data["businessCode"] = $businessCode;
return $this->view();
}
/**
* 商家扣费记录列表
*
* @return Json|View
* @throws Exception
*/
public function businessDeductionList()
{
$businessCode = input("business_code/s", "");
if ($this->request->isPost()) {
$repo = BusinessRepository::getInstance();
$keyword = $this->request->param('keyword/s', '');
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 30);
$whereMap = ["business_code" => $businessCode];
if (!empty($keyword)) {
$whereMap[] = ['reason|business_name', 'like', "%$keyword%"];
}
$list = $repo->businessDeductionList($whereMap, $page, $size, ["create_time" => "desc", "id" => "desc"]);
return $this->json(0, 'success', $list);
}
$this->data["businessCode"] = $businessCode;
return $this->view();
}
/**
* 商家充值记录列表
*
* @return Json|View
* @throws Exception
*/
public function businessRechargeList()
{
$businessCode = input("business_code/s", "");
if ($this->request->isPost()) {
$repo = BusinessRepository::getInstance();
$keyword = $this->request->param('keyword/s', '');
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 30);
$whereMap = ["business_code" => $businessCode];
if (!empty($keyword)) {
$whereMap[] = ['order_num', 'like', "%$keyword%"];
}
$list = $repo->businessRechargeList($whereMap, $page, $size, ["create_time" => "desc", "id" => "desc"]);
return $this->json(0, 'success', $list);
}
$this->data["businessCode"] = $businessCode;
return $this->view();
}
/**
* 商家详情
*
* @return Json|View
* @throws Exception
*/
public function businessDetail()
{
$businessCode = input("business_code/s", "");
if ($this->request->isPost()) {
}
$business = $repo = BusinessRepository::getInstance()->findOneByWhere(['code' => $businessCode]);
if (empty($business)) {
return $this->error("商家不存在");
}
$this->data["item"] = $business;
return $this->view();
}
/**
* 商家认证列表
*
* @return Json|View
* @throws Exception
*/
public function businessWaitList()
{
if ($this->request->isPost()) {
$model = new BusinessFlow();
$repo = BusinessRepository::getInstance($model);
$keyword = $this->request->param('keyword/s', '');
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 30);
$whereMap = [["business.state", "in", [BusinessModel::state_reviewing, BusinessModel::state_off]]];
$orders = ['business.id' => 'desc'];
if (!empty($keyword)) {
$whereMap[] = ['account.nick_name|business.business_name', 'like', "%$keyword%"];
}
$list = $repo->businessList($whereMap, $page, $size, $orders);
return $this->json(0, 'success', $list);
}
return $this->view();
}
/**
* 执行商家认证
*
* @return Json|View
* @throws Exception
*/
public function businessWait()
{
if ($this->request->isPost()) {
$businessCode = input("business_code/s", "");
$state = input("state/d", 0);
$business = BusinessRepository::getInstance()->findOneByWhere(["code" => $businessCode]);
if (empty($business)) {
return $this->json(4001, "商家不存在");
}
if ($business['state'] != BusinessModel::state_reviewing) {
return $this->json(4001, "商家当前状态不可审核");
}
if (!in_array($state, [BusinessModel::state_off, BusinessModel::state_on])) {
return $this->json(4001, "错误的审核状态");
}
Db::startTrans();
try {
$business->save(["state"=>$state]);
Db::commit();
return $this->json();
}catch (RepositoryException $e){
Db::rollback();
return $this->json("5001","审核失败");
}catch (\think\Exception $e){
Db::rollback();
return $this->json("5002","审核失败");
}
}
}
/**
* 给商家指派代理商
*
* @return Json|View
* @throws Exception
*/
public function assign()
{
$businessCode = input("business_code/s", "");
$business = BusinessRepository::getInstance()->findOneByWhere(["code" => $businessCode]);
if ($this->request->isPost()) {
$anent_code = input("agency_code/s", "");
if(empty($business)){
return $this->json(4001,"商家不存在");
}
Db::startTrans();
try {
$business->save(["agency_code"=>$anent_code]);
Db::commit();
return $this->json();
}catch (RepositoryException $e){
Db::rollback();
return $this->json("5001","指派失败");
}catch (\think\Exception $e){
Db::rollback();
return $this->json("5002","指派失败");
}
}
if(empty($business)){
return $this->error("商家不存在");
}
$this->data["agent"] = Member::getAgentAll();
$this->data["businessCode"] = $businessCode;
$this->data["business"] = $business;
return $this->view();
}
/**
* 代为充值
*
* @throws Exception
*/
public function rechargeBehalf()
{
$businessCode = input("business_code/s", "");
$business = BusinessRepository::getInstance()->findOneByWhere(["code" => $businessCode]);
if ($this->request->isPost()) {
$money = input("money/f", 0,"abs");
if($money<=0){
return $this->json(4001,"金额错误");
}
$money = floor($money * 100) / 100;
if(empty($business)){
return $this->json(4001,"商家不存在");
}
Db::startTrans();
try {
//创建充值订单
if (!$order = RechargeRepository::getInstance()->createOrder($businessCode,$money)) {
throw new RepositoryException('订单创建失败,请稍后重试');
}
//生成支付
$res = WechatPay::getInstance()->order->unify([
'body' => '商家充值',
'out_trade_no' => $order->order_num,
'total_fee' => $money * 100,
'trade_type' => 'NATIVE',
'product_id' => $order->id,
'notify_url' => $this->request->domain()."/api/recharge/notify.html",
]);
if(!isset($res['code_url'])){
throw new RepositoryException('订单创建失败,请稍后重试');
}
Db::commit();
return $this->json(0,"success",["order_num"=>$order->order_num,"code_url"=>$res['code_url']]);
}catch (RepositoryException $e){
Db::rollback();
return $this->json("5001",$e->getMessage());
}catch (Exception $e){
Db::rollback();
return $this->json("5001",$e->getMessage());
}
}
if(empty($business)){
return $this->error("商家不存在");
}
$this->data["businessCode"] = $businessCode;
return $this->view();
}
}

View File

@ -0,0 +1,215 @@
<?php
namespace app\controller\manager;
use app\repository\CmsRepository;
use app\model\Log;
use app\model\Category as CategoryModel;
use Exception;
use think\facade\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\response\Json;
use think\response\View;
/**
* 分类管理
*
* Class Category
* @package app\controller\manager
*/
class Category extends Base
{
/**
* 编辑
*
* @return Json|View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function edit()
{
$id = input('id/d', 0);
if (!$info = CategoryModel::findById($id)) {
return $this->json(4001, '记录不存在');
}
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'pid|父级分类' => 'require|number',
'name|标题' => 'require|max:100|unique:disease,name,'.$id,
]);
if ($validate !== true) {
return $validate;
}
Db::startTrans();
try {
$oldPath = $info['path'] ?? '';
$item['path'] = CategoryModel::getPath($item['pid']);
$info->save($item);
//刷新所有路径
$oldPath = $oldPath.','.$id;
$newPath = $item['path'].','.$id;
if ($oldPath != $newPath) {
CategoryModel::refreshPath();
}
Db::commit();
return $this->json();
} catch (ValidateException $e) {
Db::rollback();
return $this->json(4001, $e->getError());
}
}
$disabled = CategoryModel::getAllChildrenIds($id);
$disabled[] = $id;
$this->data['jsonList'] = $this->categoryJson([$info['pid']], $disabled);
$this->data['item'] = $info;
return $this->view();
}
/**
* 单个字段编辑
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function modify(): Json
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'id|ID' => 'require|number',
'field|字段名' => 'require',
'value|值' => 'require',
]);
if ($validate !== true) {
return $validate;
}
if (!$info = CategoryModel::findById($item['id'])) {
return $this->json(4001, '记录不存在');
}
$update = [$item['field'] => $item['value']];
try {
$info->save($update);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->json(4000, '非法请求');
}
/**
* 添加
*
* @return Json|View
* @throws Exception
*/
public function add()
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'pid|父级分类' => 'require|number',
'name|标题' => 'require|max:100',
]);
if ($validate !== true) {
return $validate;
}
try {
CategoryModel::create($item);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
$this->data['jsonList'] = $this->categoryJson();
return $this->view();
}
/**
* 删除
* @return Json
*/
public function del()
{
if (!$this->request->isPost()) {
return $this->json(4000, '非法请求');
}
$ids = $this->request->param('ids/a', []);
if(!empty(CategoryModel::findOne([["pid","in",$ids]]))){
return $this->json(5001,"该栏目还有下级 不能删除");
}
CategoryModel::destroy($ids);
return $this->json();
}
/**
* 列表
*
* @return Json|View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function index()
{
if ($this->request->isPost()) {
$menus = CategoryModel::getList();
$res = [
'code' => 0,
'msg' => 'success',
'count' => $menus->count(),
'data' => $menus->toArray(),
];
return json($res);
}
return $this->view();
}
/**
* @param array $selected
* @param array $disabled
* @return false|string
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
private function categoryJson(array $selected = [], array $disabled = [])
{
$categoryList[] = ['name' => '顶级分类', 'id' => 0, 'disabled' => false, 'selected' => in_array(0, $selected)];
$list = CategoryModel::getListByPid();
$list = $list->toArray();
foreach ($list as $k => $m) {
$list[$k]['selected'] = in_array($m['id'], $selected);
$list[$k]['disabled'] = in_array($m['id'], $disabled);
}
$list = CmsRepository::getInstance()->buildMenuChild(0, $list);
$categoryList = array_merge($categoryList, CmsRepository::getInstance()->handleSelectedList($list));
return json_encode($categoryList, JSON_UNESCAPED_UNICODE);
}
}

View File

@ -0,0 +1,185 @@
<?php
namespace app\controller\manager;
use app\model\CommentRule;
use Exception;
use think\exception\ValidateException;
use think\facade\Config as CConfig;
use think\response\Json;
/**
* 额外配置
* Class Config
* @package app\controller\manager
*/
class Config extends Base
{
private string $extraPath = '';
protected function initialize()
{
parent::initialize();
$this->extraPath = config_path() . 'extra/';
if (!is_dir($this->extraPath)) {
if (is_writable(config_path())) {
mkdir($this->extraPath, 0777, true);
} else {
halt('请联系系统管理人员配置文件夹读写权限!请添加'.$this->extraPath.'文件夹的读写权限');
}
} elseif (!is_writable($this->extraPath)) {
halt('请联系系统管理人员配置文件夹读写权限!请添加'.$this->extraPath.'文件夹的读写权限');
}
}
public function other()
{
if ($this->request->isPost()) {
$data = input("post.");
unset($data['_token']);
$php = var_export($data, true);
file_put_contents($this->extraPath . 'other.php', '<?php' . PHP_EOL . 'return ' . $php . ';');
return $this->json();
} else {
CConfig::load('extra/other', 'other');
$this->data['item'] = config('other');
return $this->view();
}
}
public function wechat()
{
if ($this->request->isPost()) {
$data = input("post.");
unset($data['_token']);
$php = var_export($data, true);
file_put_contents($this->extraPath . 'wechat.php', '<?php' . PHP_EOL . 'return ' . $php . ';');
return $this->json();
} else {
CConfig::load('extra/wechat', 'wechat');
$this->data['item'] = config('wechat');
return $this->view();
}
}
public function alipay()
{
if ($this->request->isPost()) {
$data = input("post.");
unset($data['_token']);
$php = var_export($data, true);
file_put_contents($this->extraPath . 'alipay.php', '<?php' . PHP_EOL . 'return ' . $php . ';');
return $this->json();
} else {
CConfig::load('extra/alipay', 'alipay');
$this->data['item'] = config('alipay');
return $this->view();
}
}
public function commentRule()
{
if ($this->request->isPost()) {
$page = input('param.page/d', 1);
$size = input('param.size/d', 10);
$items = CommentRule::findList([],[], $page, $size);
return $this->json(0, 'ok', $items);
}
return $this->view();
}
public function delCommentRule()
{
if ($this->request->isPost()) {
$ids = input('post.ids/a', []);
if (empty($ids)) {
$ids[] = input('post.id/d');
}
CommentRule::deleteByIds($ids);
return $this->json();
}
return $this->json(4001, '非法请求!');
}
public function addCommentRule()
{
if ($this->request->isPost()) {
$item = input('post.item');
$validate = $this->validateByApi($item, [
'rule|规则' => 'require',
'state|状态' => 'require',
]);
if ($validate !== true) {
return $validate;
}
try {
$item['create_time'] = date('Y-m-d H:i:s');
CommentRule::create($item);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->view();
}
/**
* 单个字段编辑
*
* @return Json
* @throws Exception
*/
public function modifyCommentRule(): Json
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'field' => 'require',
'value' => 'require',
]);
if ($validate !== true) {
return $validate;
}
if (!$info = CommentRule::findById($item['id'])) {
return $this->json(4001, '记录不存在');
}
$update = [$item['field'] => $item['value']];
try {
$info->save($update);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->json(4000, '非法请求');
}
public function __call($name, $args)
{
if ($this->request->isPost()) {
try {
$data = input("post.");
$php = var_export($data, true);
file_put_contents(config_path().'extra/'.$name.'.php', '<?php'.PHP_EOL.'return '.$php.';');
return $this->json();
} catch (Exception $e) {
return $this->json(4001, $e->getMessage());
}
} else {
CConfig::load('extra/'.$name, $name);
$this->data['item'] = config($name);
$this->data['action'] = $name;
return $this->view('manager/config/'.$name);
}
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace app\controller\manager;
class Error
{
public function jump()
{
$param = request()->param();
return view()->assign($param);
}
}

View File

@ -0,0 +1,143 @@
<?php
namespace app\controller\manager;
use app\model\{File as MFile, Archives, Block, Category, Link, Slide, Log};
use app\service\Tool;
class File extends Base
{
protected $noNeedLogin = ['delPath', 'del', 'unuse', 'getAllFilesInUse', 'list', 'index'];
//删除磁盘上的文件
public function delPath()
{
if ($this->request->isPost()) {
$paths = input('post.paths/a');
if(!empty($paths)){
foreach($paths as $path){
Tool::delFile($path);
}
Log::write('file', 'delPath', '批量删除了磁盘文件,涉及到的文件路径为:' . implode(',', $paths));
return $this->json();
}
return $this->json(2, '待删除文件列表为空');
}
return $this->json(1, '非法请求!');
}
//删除文件记录
public function del()
{
if ($this->request->isPost()) {
$ids = input('post.ids/a');
if(empty($ids) || !is_array($ids)) {
return $this->json(2, '参数错误,请核对之后再操作!');
}
$items = MFile::getListByIds($ids);
if(!empty($items)){
$delIds = [];
foreach($items as $item){
$delIds[] = $item['id'];
if($item['type'] == MFile::IMG){
Tool::delFile($item['src'], 1);
}else{
Tool::delFile($item['src']);
}
}
MFile::destroy($delIds);
Log::write('file', 'del', '批量删除了文件涉及到的文件ID为' . implode(',', $delIds));
return $this->json();
}else{
return $this->json(3, '待删除文件列表为空');
}
}
return $this->json(1, '非法请求!');
}
/**
* 未使用文件列表,
* 1. 遍历数据库中使用的图片视频及文件路径
* 2. 遍历上传目录中的文件
* 3. 数据对比,找出存在目录中的文件&不在数据库中的文件
* 4. 页面上显示查找出来的文件
*/
public function unuse()
{
$filesInUse = $this->getAllFilesInUse(); //数据库中在使用的文件
$rootPath = app()->getRootPath();
$uploadPath = $rootPath . 'storage';
$uploadedFiles = getAllFilesByPath($uploadPath, $rootPath); //磁盘上上传的文件
$files = MFile::getAll();
$dbUploadedFiles = []; //数据库中上传的文件
foreach($files as $file){
$src = trim($file['src']);
if(!empty($src)){
$key = getKeyByPath($src);
$dbUploadedFiles[$key] = $file;
}
}
$uploadedNotInUseFiles = array_diff_key($uploadedFiles, $filesInUse); //磁盘上上传未使用的文件
$dbUploadedNotInUseFiles = array_diff_key($dbUploadedFiles, $filesInUse); //数据库中上传未使用的文件
$bothNotInUseFiles = array_intersect_key($uploadedNotInUseFiles, $dbUploadedNotInUseFiles); //磁盘和数据库中,两边都未使用
$this->data['uploadedNotInUseFiles'] = $uploadedNotInUseFiles;
$this->data['dbUploadedNotInUseFiles'] = $dbUploadedNotInUseFiles;
$this->data['bothNotInUseFilesKey'] = array_keys($bothNotInUseFiles);
return $this->view();
}
//获取所有在使用的文件
private function getAllFilesInUse()
{
$files = [];
$blockFiles = Block::getFilesInUse();
if(!empty($blockFiles)){
$files = array_merge($files, $blockFiles);
}
$slideFiles = Slide::getFilesInUse();
if(!empty($slideFiles)){
$files = array_merge($files, $slideFiles);
}
$linkFiles = Link::getFilesInUse();
if(!empty($linkFiles)){
$files = array_merge($files, $linkFiles);
}
$categoryFiles = Category::getFilesInUse();
if(!empty($categoryFiles)){
$files = array_merge($files, $categoryFiles);
}
$articleFiles = Archives::getFilesInUse();
if(!empty($articleFiles)){
$files = array_merge($files, $articleFiles);
}
return $files;
}
//ajax获取文件列表
public function list()
{
if($this->request->isAjax()){
$page = input('param.page/d', 1);
$size = input('param.size/d', 20);
if(!is_integer($page) || $page < 1){
$page = 1;
}
if (!is_integer($size) || $size < 1) {
$size = 20;
}
$type = input('param.type', '');
if(!in_array($type, array_keys(MFile::getTypes()))){
$type = '';
}
$items = MFile::getList($type, $page, $size);
return $this->json(0, 'ok', $items);
}
return $this->json(1, '无此操作');
}
//列表
public function index()
{
$items = MFile::getListPage();
$this->data['items'] = $items;
$this->data['types'] = MFile::getTypes();
return $this->view();
}
}

View File

@ -0,0 +1,141 @@
<?php
namespace app\controller\manager;
use app\model\{AuthGroup, AuthRule, Log};
use app\validate\AuthGroup as VAuthGroup;
use think\exception\ValidateException;
/**
* 角色管理控制器
*/
class Group extends Base
{
/**
* 角色、分组删除
*/
public function del()
{
if ($this->request->isPost()) {
$id = input('post.id/d');
if (is_numeric($id) === true && $id > 0) {
$item = AuthGroup::getById($id);
if(!empty($item)){
AuthGroup::destroy($id);
Log::write('group', 'del', '删除角色ID' . $id . ',名称:' . $item['title']);
return $this->json();
}
}
return $this->json(2, '传入参数错误,请核对之后再操作!');
}
return $this->json(1, '非法请求!');
}
/**
* 角色、分组权限分配
*/
public function rule()
{
if($this->request->isPost()){
$rules = input('post.rules/a');
$groupId = input('post.group_id/d');
if (is_array($rules) && (is_numeric($groupId) === true && $groupId > 0)) {
$group = AuthGroup::getById($groupId);
if(empty($group)){
return $this->json(2, '无此角色信息,请核对之后再操作!');
}
AuthGroup::updateRules($groupId, $rules);
// 重置该角色对应的权限缓存
AuthGroup::resetGroupRulesCache($groupId);
Log::write('group', 'rule', '角色分配权限ID' . $groupId . ',名称:' . $group['title']);
return $this->json();
}else{
return $this->json(3, '传入参数错误,请核对之后再操作!');
}
} else {
$groupId = input('param.group_id/d');
$group = AuthGroup::getById($groupId);
if(!empty($group)){
$rules = AuthRule::getListTree();
$this->data['group_id'] = $groupId;
$this->data['group'] = $group;
$this->data['rules'] = $rules;
return $this->view();
}else{
return $this->json(1, '无此角色信息,请核对之后再操作!');
}
}
}
/**
* 角色、分组添加
* @param int $status 1:正常0禁止
*/
public function add()
{
if($this->request->isPost()){
$title = trim(input('post.title'));
$status = input('post.status/d');
if (!empty($title) && (is_numeric($status) === true) && ($status == 1 || $status == 0)) {
$item = [
'title' => $title,
'status' => $status
];
try {
validate(VAuthGroup::class)->check($item);
$group = AuthGroup::create($item);
Log::write('group', 'add', "角色新增ID{$group->id} ,标题:{$group->title}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}
return $this->json(1, '传入参数错误,请核对之后再操作!');
}else{
return $this->view();
}
}
/**
* 角色、分组编辑
*/
public function edit()
{
if($this->request->isPost()){
$title = trim(input('post.title'));
$status = input('post.status/d');
$id = input('post.id/d');
if (!empty($title) && ($status == 1 || $status == 0) && (is_numeric($id) === true && $id > 0)) {
$item = [
'title' => $title,
'status' => $status
];
try {
validate(VAuthGroup::class)->check($item);
AuthGroup::updateById($id, $item);
Log::write('group', 'edit', "角色编辑ID{$id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}
return $this->json(1, '传入参数错误,请核对之后再操作!');
}else{
$id = input('param.id/d');
if (is_numeric($id) === true && $id > 0) {
$item = AuthGroup::getById($id);
$this->data['item'] = $item;
return $this->view();
}
return $this->json(1, '传入参数错误,请核对之后再操作!');
}
}
/**
* 所有角色分组信息
* @return void
*/
public function index()
{
$list = AuthGroup::select()->toArray();
$this->data['list'] = $list;
return $this->view();
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace app\controller\manager;
use app\model\AccountRecord;
use app\model\Overview;
use app\model\AccountRole;
use app\model\Appointment;
use app\model\Account;
use app\repository\CmsRepository;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
use think\response\View;
use app\model\Member;
use app\model\Menu;
class Index extends Base
{
//TODO 权限未完善
protected $noNeedLogin = ['index', 'init'];
/**
* 后台初始页面 随后进入dashboard页面
*
* @return View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function index(): View
{
$auth = session('auth');
$this->data['user'] = Member::findById($auth['user_id'] ?? 0, ['id', 'username', 'nickname', 'mobile']);
return $this->view();
}
/**
* 控制台
*
* @return Json|View
* @throws Exception
*/
public function dashboard()
{
return $this->view();
}
/**
* 菜单初始化
*
* @return Json
*/
public function init(): Json
{
$res = [];
$res['homeInfo'] = ['title' => '控制台', 'href' => "manager/index/dashboard"];
$res['logoInfo'] = ['title' => '恒美植发', 'href' => "", 'image' => '/static/manager/image/logo.png'];
$menus = CmsRepository::getInstance()->getMenuList(Menu::TYPE_MENU, Menu::SHOW_YES)->toArray();
foreach ($menus as $k => $m) {
$menus[$k]['icon'] = !empty($m['icon']) ? 'fa '.$m['icon'] : '';
$menus[$k]['href'] = ltrim($m['href'], '/');
}
$menus = CmsRepository::getInstance()->buildMenuChild(0, $menus, 'child');
$res['menuInfo'] = $menus;
return json($res);
}
/**
* 缓存清理
*
* @return Json
*/
public function clear(): Json
{
$res = ['code' => 1, 'msg' => '服务端清理缓存成功'];
sleep(2);
return json($res);
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace app\controller\manager;
use app\service\Jwt;
use Exception;
use app\model\{Member, AuthRule, LoginLog};
use app\controller\BaseController;
use think\response\Json;
use think\response\View;
class Login extends BaseController
{
protected $noNeedLogin = ['index'];
/**
* @return View|Json
* @throws Exception
*/
public function index()
{
if (request()->isPost()) {
$param = input('post.data');
$username = trim($param['username']);
$password = trim($param['password']);
$captcha = trim($param['captcha'] ?? '');
if (!captcha_check($captcha)) {
return $this->json(4001, '验证码错误'.$captcha);
}
if (empty($username) || empty($password)) {
return $this->json(4001, '用户名和密码不能为空');
}
$member = Member::getByUserName($username);
if (empty($member)) {
return $this->json(4002, '用户名或密码错误');
}
if ($member['password'] != md5($password.$username)) {
return $this->json(4003, '用户名或密码错误');
}
if ($member['status'] != Member::STATUS_NORMAL) {
return $this->json(4004, '账号已被禁用');
}
$userInfo = [
'user_id' => $member['id'],
'username' => $member['username'],
'nickname' => $member['nickname'],
'account_id' => $member['account_id'],//绑定的前台用户ID
];
$jwtToken = Jwt::generate($userInfo, env('app.expire', 7200));
$userInfo['token'] = $jwtToken;//jwt生成token
//记录最后登陆时间
$ip = request()->ip();
$time = time();
Member::updateById($member['id'], [
'login_time' => $time,
'login_ip' => $ip
]);
LoginLog::create([
'member_id' => $member['id'],
'name' => $member['username'],
'ip' => $ip,
'create_time' => $time
]);
session('auth', $userInfo);
return $this->json(0, 'success', ['url' => '/manager']);
}
$viewData = [];
return view()->assign($viewData);
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace app\controller\manager;
use app\controller\BaseController;
use think\response\Redirect;
class Logout extends BaseController
{
protected $noNeedLogin = ['index'];
/**
* 退出
*
* @return Redirect
*/
public function index(): Redirect
{
session(null);
return redirect(url('/manager/login/index'));
}
}

View File

@ -0,0 +1,411 @@
<?php
namespace app\controller\manager;
use app\model\Log;
use app\model\Member as MemberModel;
use app\model\Role as RoleModel;
use app\model\Business as BusinessModel;
use app\repository\BusinessRepository;
use Exception;
use tauthz\facade\Enforcer;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\facade\Db;
use think\response\Json;
use think\response\Redirect;
use think\response\View;
/**
* (后台)人员管理
*
* Class Member
* @package app\controller\manager
*/
class Member extends Base
{
/**
* 删除
*
* @return Json
*/
public function del(): Json
{
if ($this->request->isPost()) {
$ids = input('post.ids/a', []);
if (empty($ids)) {
$ids[] = input('post.id/d');
}
MemberModel::deleteByIds($ids);
foreach ($ids as $id) {
Enforcer::deleteRolesForUser($id);
}
Log::write(get_class().'Del', 'del', '涉及到的ID为'.implode(',', $ids));
return $this->json();
}
return $this->json(4001, '非法请求!');
}
/**
* 个人详情
*
* @return Json|View|Redirect
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function profile()
{
$id = $this->auth['user_id'] ?? 0;
if (!$item = MemberModel::findById($id)) {
if ($this->request->isAjax()) {
return $this->json(4001, '记录不存在');
}
return $this->error('记录不存在');
}
if ($this->request->isPost()) {
$post = input('post.');
$validate = $this->validateByApi($post, [
'mobile|手机号' => 'require|unique:member,mobile,'.$id,
'nickname|昵称' => 'require|chsAlphaNum|min:2|max:10',
'remark|备注信息' => 'max:255',
]);
if ($validate !== true) {
return $validate;
}
if (!checkMobile($post['mobile'])) {
return $this->json(4002, '请输入正确的手机号码');
}
try {
$item->save($post);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
$this->data['item'] = $item;
return $this->view();
}
/**
* 编辑
*
* @return Json|View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function edit()
{
$id = input('id/d', 0);
if (!$info = MemberModel::findById($id)) {
return $this->json(4001, '记录不存在');
}
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'mobile|手机号' => 'require|unique:member,mobile,'.$id,
'nickname|昵称' => 'require|chsAlphaNum|min:2|max:10',
'remark|备注信息' => 'max:255',
]);
if ($validate !== true) {
return $validate;
}
if (!checkMobile($item['mobile'])) {
return $this->json(4002, '请输入正确的手机号码');
}
$roles = [];
if ($item['roles']) {
$roles = $item['roles'];
$item['roles'] = implode(',', $item['roles']);
}
Db::startTrans();
try {
//之前关联的商家不为空 并且已经改变 吧之前的商家 从代理商变成普通商家
if ($info['business_code'] != $item['business_code']) {
if(!empty($info['business_code']) ){
$oldBusiness = BusinessRepository::getInstance()->findOneByWhere(["code" => $info['business_code']]);
if (!empty($oldBusiness)) {
$oldBusiness->save(["is_agency" => BusinessModel::COMMON_OFF]);
}
}
//如果改变了关联商家
if(!empty($item['business_code'])){
$Business = BusinessRepository::getInstance()->findOneByWhere(["code" => $item['business_code']]);
if (empty($Business)) {
Db::rollback();
return $this->json(4001, "指定商家不存在");
}
$Business->save(["is_agency" => BusinessModel::COMMON_ON]);
}
}
$info->save($item);
//删除所有角色
Enforcer::deleteRolesForUser($id);
//新增角色
foreach ($roles as $role) {
Enforcer::addRoleForUser($id, $role);
}
Db::commit();
return $this->json();
} catch (ValidateException $e) {
Db::rollback();
return $this->json(4001, $e->getError());
}
}
$this->data['item'] = $info;
$this->data['roleJson'] = $this->roleJson(explode(',', $info['roles']));
$this->data['business'] = BusinessRepository::getInstance()->getBusinessAll();
return $this->view();
}
/**
* 单个字段编辑
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function modify(): Json
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'field' => 'require',
'value' => 'require',
]);
if ($validate !== true) {
return $validate;
}
if (!$info = MemberModel::findById($item['id'])) {
return $this->json(4001, '记录不存在');
}
$update = [$item['field'] => $item['value']];
try {
$info->save($update);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->json(4000, '非法请求');
}
/**
* 添加
*
* @return Json|View
* @throws Exception
*/
public function add()
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'username|用户名' => 'require|alphaDash|min:4|max:16|unique:member',
'mobile|手机号' => 'require|unique:member',
'nickname|昵称' => 'require|chsAlphaNum|min:2|max:10',
'password|密码' => 'require|min:4|max:16',
'remark|备注信息' => 'max:255',
]);
if ($validate !== true) {
return $validate;
}
if (!checkMobile($item['mobile'])) {
return $this->json(4002, '请输入正确的手机号码');
}
$roles = [];
if ($item['roles']) {
$roles = $item['roles'];
$item['roles'] = implode(',', $item['roles']);
}
Db::startTrans();
try {
$item['password'] = md5($item['password'].$item['username']);
$member = MemberModel::create($item);
foreach ($roles as $role) {
Enforcer::addRoleForUser($member['id'], $role);
}
Db::commit();
return $this->json();
} catch (ValidateException $e) {
Db::rollback();
return $this->json(4001, $e->getError());
}
}
$this->data['roleJson'] = $this->roleJson();
return $this->view();
}
/**
* 修改密码
*
* @return Json|View|Redirect
* @throws Exception
*/
public function password()
{
$id = input('id/d', 0);
if (!$item = MemberModel::findById($id)) {
if ($this->request->isAjax()) {
return $this->json(4001, '记录不存在');
}
return $this->error('记录不存在');
}
if ($this->request->isPost()) {
$post = input('post.');
$validate = $this->validateByApi($post, [
'password|密码' => 'require|confirm',
]);
if ($validate !== true) {
return $validate;
}
$password = md5($post['password'].$item['username']);
try {
$item->save(['password' => $password]);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
$this->data['item'] = $item;
return $this->view();
}
/**
* 个人修改密码
*
* @return Json|View
* @throws Exception
*/
public function myPassword()
{
$id = $this->auth['user_id'] ?? 0;
if (!$item = MemberModel::findById($id)) {
return $this->json(4001, '记录不存在');
}
if ($this->request->isPost()) {
$post = input('post.');
$validate = $this->validateByApi($post, [
'old-password|旧密码' => 'require',
'password|密码' => 'require|confirm',
]);
if ($validate !== true) {
return $validate;
}
if ($item['password'] !== md5($post['old-password'].$item['username'])) {
return $this->json(4002, '原始密码错误');
}
$password = md5($post['password'].$item['username']);
try {
$item->save(['password' => $password]);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
$this->data['item'] = $item;
return $this->view();
}
/**
* 列表
*
* @return View|Json
* @throws Exception
*/
public function index()
{
if ($this->request->isPost()) {
$page = input('page/d', 1);
$limit = input('size/d', 20);
$searchParams = input('searchParams');
$where = [];
if ($searchParams) {
foreach ($searchParams as $key => $param) {
if (!empty($param)) {
$where[] = [$key, 'like', '%'.$param.'%'];
}
}
}
$items = MemberModel::findList($where, [], $page, $limit, function ($q) {
return $q->order('id', 'desc');
});
return $this->json(0, '操作成功', $items);
}
return $this->view();
}
/**
* 构造角色json数据
*
* @param array $selected
* @return false|string
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
private function roleJson(array $selected = [])
{
$roles = RoleModel::where('status', RoleModel::STATUS_NORMAL)
->order('sort', 'desc')
->select()
->toArray();
foreach ($roles as $k => $m) {
$roles[$k]['checked'] = in_array($m['id'], $selected);
$roles[$k]['spread'] = true;
}
return json_encode($roles, JSON_UNESCAPED_UNICODE);
}
}

View File

@ -0,0 +1,263 @@
<?php
namespace app\controller\manager;
use app\repository\CmsRepository;
use app\model\Log;
use app\model\Menu as MenuModel;
use app\validate\MenuValidate;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\facade\Db;
use think\response\Json;
use think\response\View;
/**
* 菜单管理
*
* Class Menu
* @package app\controller\manager
*/
class Menu extends Base
{
/**
* 删除
*
* @return Json
*/
public function del(): Json
{
if ($this->request->isPost()) {
$ids = input('post.ids/a', []);
if (empty($ids)) {
$ids[] = input('post.id/d');
}
$repo = CmsRepository::getInstance();
if ($repo->hasChildrenMenuByIds($ids)) {
return $this->json(4002, '待删除数据存在子数据');
}
$repo->delMenuByIds($ids);
Log::write('menuDel', 'del', '删除了菜单涉及到的ID为'.implode(',', $ids));
return $this->json();
}
return $this->json(4001, '非法请求!');
}
/**
* 规则
*
* @return string[]
*/
private function rule(): array
{
return [
'pid|父级菜单' => 'require|number',
'title|标题' => 'require|max:100',
'name|路由标识' => 'require',
'remark|备注信息' => 'max:255',
];
}
/**
* 编辑
*
* @return Json|View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function edit()
{
$id = input('id/d', 0);
if (!$info = MenuModel::findById($id)) {
return $this->json(4001, '记录不存在');
}
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, $this->rule());
if ($validate !== true) {
return $validate;
}
try {
$oldPath = $info['path'];
$item['path'] = MenuModel::getPath($item['pid']);
$info->save($item);
//刷新所有路径
$oldPath = $oldPath.','.$id;
$newPath = $item['path'].','.$id;
if ($oldPath != $newPath) {
MenuModel::refreshPath();
}
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
$disabled = MenuModel::getAllChildrenIds($id);
$disabled[] = $id;
$this->data['menuList'] = $this->menuJson([$info['pid']], $disabled);
$this->data['item'] = $info;
return $this->view();
}
/**
* 单个字段编辑
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function modify(): Json
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = new MenuValidate();
if (!$validate->scene('menu_modify')->check($item)) {
return $this->json(4002, $validate->getError());
}
if (!$info = MenuModel::findById($item['id'])) {
return $this->json(4001, '记录不存在');
}
$update = [$item['field'] => $item['value']];
try {
$info->save($update);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->json(4000, '非法请求');
}
/**
* 添加
*
* @return Json|View
* @throws Exception
*/
public function add()
{
$id = input('id/d', 0);
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, $this->rule());
if ($validate !== true) {
return $validate;
}
try {
$item['path'] = MenuModel::getPath($item['pid']);
MenuModel::create($item);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
$selected = $id > 0 ? [$id] : [];
$this->data['menuList'] = $this->menuJson($selected);
return $this->view();
}
/**
* 常规权限生成
*
* @return Json|View
* @throws Exception
*/
public function generate()
{
$id = input('id/d', 0);
if ($this->request->isPost()) {
$id = input('id/d', 0);
if (!$item = MenuModel::findById($id)) {
return $this->json(4002, '记录不存在');
}
if ($item['type'] != MenuModel::TYPE_MENU) {
return $this->json(4003, '仅菜单类型可操作');
}
Db::startTrans();
try {
//自动生成常规操作
MenuModel::generate($id, $item['name'], $item['path']);
Db::commit();
return $this->json();
} catch (ValidateException $e) {
Db::rollback();
return $this->json(4001, $e->getError());
}
}
$selected = $id > 0 ? [$id] : [];
$this->data['menuList'] = $this->menuJson($selected);
return $this->view();
}
/**
* 列表
*
* @return View|Json
*/
public function index()
{
if ($this->request->isPost()) {
$menus = CmsRepository::getInstance()->getMenuList();
$menus->each(function ($item) {
if ($item['type'] == 'menu') {
$item->open = false;
}
});
$res = [
'code' => 0,
'msg' => 'success',
'count' => $menus->count(),
'data' => $menus->toArray(),
];
return json($res);
}
return $this->view();
}
/**
* xmSelect插件 json数据
*
* @param array $selected
* @param array $disabled
* @return false|string
*/
private function menuJson(array $selected = [], array $disabled = [])
{
$categoryList[] = ['title' => '顶级菜单', 'id' => 0, 'prefix' => '', 'disabled' => false, 'open' => true, 'selected' => in_array(0, $selected)];
$menus = CmsRepository::getInstance()->getMenuList();
$menus = $menus->toArray();
foreach ($menus as $k => $m) {
$menus[$k]['selected'] = in_array($m['id'], $selected);
$menus[$k]['disabled'] = in_array($m['id'], $disabled);
}
$menus = CmsRepository::getInstance()->buildMenuChild(0, $menus);
$categoryList = array_merge($categoryList, CmsRepository::getInstance()->handleSelectedList($menus));
return json_encode($categoryList, JSON_UNESCAPED_UNICODE);
}
}

View File

@ -0,0 +1,165 @@
<?php
namespace app\controller\manager;
use app\model\{Model as MModel, Log};
use app\validate\Model as VModel;
use think\exception\ValidateException;
class Model extends Base
{
//删除模型
public function del()
{
if($this->request->isPost()){
$ids = input('post.ids/a');
if(is_array($ids)) {
$idsArr = $ids;
} else {
$idsArr = array_filter(explode(',', $ids));
}
if(count($idsArr) == 0) {
return $this->json(1, '无效请求,参数错误!');
}
$items = MModel::getListByIds($idsArr);
if(!empty($items)){
$delIds = [];
foreach($items as $item){
$delIds[] = $item['id'];
}
MModel::destroy($delIds);
Log::write('model', 'del', "模型删除ID" . implode(',', $ids));
return $this->json();
}
return $this->json(2, '无效请求,参数错误!');
}
return $this->json(1, '非法请求!');
}
//编辑模型
public function edit()
{
if($this->request->isPost()){
$item = [];
$item['name'] = input('post.name');
$item['template'] = input('post.template');
$item['manager'] = input('post.manager');
$id = input('post.id/d');
if(is_numeric($id) && $id > 0) {
$model = MModel::getById($id);
if(empty($model)){
return $this->json(2, '无此模型数据!');
}
try {
validate(VModel::class)->check($item);
MModel::updateById($id, $item);
Log::write('model', 'edit', "模型编辑ID{$id}, 标题:{$item['name']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(3, $e->getError());
}
}
return $this->json(1, '无效请求,参数错误!');
}else{
$id = input('param.id/d');
if (is_numeric($id) && $id > 0) {
$item = MModel::getById($id);
$this->data['item'] = $item;
return $this->view();
}
return $this->json(1,'传入参数错误,请核对之后再操作!');
}
}
/**
* 添加模型
*/
public function add()
{
if($this->request->isPost()){
$item = [];
$item['name'] = input('post.name');
$item['template'] = input('post.template');
$item['manager'] = input('post.manager');
try {
validate(VModel::class)->check($item);
$model = MModel::create($item);
Log::write('model', 'add', "模型新增ID{$model->id}, 标题:{$item['name']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}else {
return $this->view();
}
}
/**
* 模型列表
*/
public function index()
{
$items = MModel::getList();
$this->data['items'] = $items;
return $this->view();
}
/**
* 排序
*/
public function sort()
{
if($this->request->isPost()){
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = MModel::getById($id);
if(empty($item)) {
return $this->json(3, '无此模型!');
}
if($sort == 'up'){
$where = "sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = MModel::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new MModel();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('model', 'sort', "模型排序ID{$id} ,标题:{$item['name']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '非法请求!');
}
}

View File

@ -0,0 +1,467 @@
<?php
namespace app\controller\manager;
use app\model\{Category, Block, Log};
use app\validate\Block as VBlock;
use think\exception\ValidateException;
use app\service\Tool;
class Page extends Base
{
//源码,代码
public function code()
{
if($this->request->isPost()){
$item = input('post.item/a');
$categoryId = input('post.category_id/d');
$id = input('post.id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
if(empty($item['value'])){
return $this->json(2, '内容不可为空!');
}
$block = Block::getByKeyword($item['keyword'], $categoryId);
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(3, '键值已存在,请更改键值');
}
Block::updateById($id, $item);
Log::write('page', 'code', "单页代码编辑ID{$id}, 键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(4, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(3, '键值已存在,请更改键值');
}
$item['category_id'] = $categoryId;
$item['type'] = Block::CODE;
$block = Block::create($item);
Log::write('page', 'code', "单页代码新增ID{$block->id}, 键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此代码块!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
return $this->view();
}
}
//排序
public function sort()
{
if($this->request->isPost()){
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = Block::getById($id);
if(empty($item)){
return $this->json(3, '无此块信息');
}
if($sort == 'up'){
$where = "category_id='{$item['category_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "category_id='{$item['category_id']}' and sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = Block::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new Block();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('page', 'sort', "单页区块排序ID{$id} ,键值:{$item['keyword']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->error('无此操作');
}
//删除
public function del()
{
if ($this->request->isAjax()) {
$id = input('post.id/d');
$item = Block::getById($id);
if(!empty($item)){
Block::destroy($id);
Log::write('page', 'del', "单页区块删除ID{$id} ,键值:{$item['keyword']}");
return $this->json();
}
return $this->json(1, 'fail');
}
return $this->error('无此操作');
}
//图片
public function img()
{
if($this->request->isPost()){
$item = input('post.item/a');
$img = trim(input('post.img'));
$categoryId = input('post.category_id/d');
if (!empty($img) && $img == 'null') {
$img = '';
}
$id = input('post.id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
$block = Block::getByKeyword($item['keyword'], $categoryId);
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改键值');
}
if(!empty($img)){
$item['value'] = $img;
}
Block::updateById($id, $item);
Log::write('page', 'img', "单页图片编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if(!empty($block)){
return $this->json(4, '键值已存在,请更改键值');
}
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!!');
}
if(empty($img)){
return $this->json(3, '图片不可为空');
}
$item['value'] = $img;
$item['type'] = Block::IMG;
$item['category_id'] = $categoryId;
$block = Block::create($item);
Log::write('page', 'img', "单页图片新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此图片!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
if(isset($item) && $item['width'] && $item['height']){
$imgSize = $item['width'].'px X '.$item['height'].'px';
}else{
$imgSize = '';
}
$this->data['categoryId'] = $categoryId;
$this->data['imgSize'] = $imgSize;
$this->data['groupId'] = session('auth.groupId');
return $this->view();
}
}
//文字块
public function block()
{
if($this->request->isPost()){
$item = input('post.item/a');
$categoryId = input('post.category_id/d');
$id = input('post.id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
if(empty($item['value'])){
return $this->json(1, '内容不可为空!');
}
$block = Block::getByKeyword($item['keyword'], $categoryId);
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改键值');
}
Block::updateById($id, $item);
Log::write('page', 'block', "单页文字块编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(4, '键值已存在,请更改键值');
}
$item['category_id'] = $categoryId;
$block = Block::create($item);
Log::write('page', 'block', "单页文字块新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此文字块!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
return $this->view();
}
}
//富文本内容
public function text()
{
if($this->request->isPost()){
$item = input('post.item/a');
$categoryId = input('post.category_id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
if(empty($item['value'])){
return $this->json(1, '内容不可为空!');
}
$block = Block::getByKeyword($item['keyword'], $categoryId);
$id = input('post.id/d');
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改');
}
Block::updateById($id, $item);
Log::write('page', 'text', "单页富文本编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(4, '键值已存在,请更改键值');
}
$item['category_id'] = $categoryId;
$item['type'] = Block::TEXT;
$block = Block::create($item);
Log::write('page', 'text', "单页富文本新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此富文本!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
return $this->view();
}
}
//组图
public function group()
{
if($this->request->isPost()){
$item = input('post.item/a');
$imgs = input('post.img/a');
$categoryId = input('post.category_id/d');
if (!empty($imgs) && is_array($imgs)) {
$item['value'] = json_encode($imgs);
} else {
$item['value'] = '';
}
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
$block = Block::getByKeyword($item['keyword'], $categoryId);
$id = input('post.id/d');
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改');
}
Block::updateById($id, $item);
Log::write('page', 'group', "单页组图编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(4, '键值已存在,请更改键值');
}
$item['category_id'] = $categoryId;
$item['type'] = Block::GROUP;
$block = Block::create($item);
Log::write('page', 'group', "单页组图新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此组图!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
if(isset($item) && $item['width'] && $item['height']){
$imgSize = $item['width'].'px X '.$item['height'].'px';
}else{
$imgSize = '';
}
$this->data['imgSize'] = $imgSize;
$this->data['groupId'] = session('auth.groupId');
return $this->view();
}
}
//视频
public function video()
{
if($this->request->isPost()){
$item = input('post.item/a');
$img = trim(input('post.img'));
$video = trim(input('post.video'));
$categoryId = input('post.category_id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
$block = Block::getByKeyword($item['keyword'], $categoryId);
$id = input('post.id/d');
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改');
}
if(!empty($img)){
$item['img'] = $img;
}
if(!empty($video)){
$item['value'] = $video;
}
Block::updateById($id, $item);
Log::write('page', 'video', "单页视频编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(3, '键值已存在,请更改键值');
}
if(empty($video)){
return $this->json(3, '视频不可为空');
}
$item['category_id'] = $categoryId;
$item['type'] = Block::VIDEO;
$item['value'] = $video;
$item['img'] = $img;
$block = Block::create($item);
Log::write('page', 'video', "单页视频新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此视频!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
if(isset($item) && $item['width'] && $item['height']){
$imgSize = $item['width'].'px X '.$item['height'].'px';
}else{
$imgSize = '';
}
$this->data['imgSize'] = $imgSize;
$this->data['groupId'] = session('auth.groupId');
return $this->view();
}
}
}

View File

@ -0,0 +1,270 @@
<?php
namespace app\controller\manager;
use app\model\Log;
use app\model\Menu;
use app\model\Menu as MenuModel;
use app\model\Role as RoleModel;
use app\model\Rules;
use app\repository\CmsRepository;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\facade\Db;
use think\response\Json;
use think\response\View;
/**
* 角色管理
*
* Class Role
* @package app\controller\manager
*/
class Role extends Base
{
/**
* 删除
*
* @return Json
*/
public function del(): Json
{
if ($this->request->isPost()) {
$ids = input('post.ids/a', []);
if (empty($ids)) {
$ids[] = input('post.id/d');
}
RoleModel::deleteByIds($ids);
Log::write(get_class().'Del', 'del', '涉及到的ID为'.implode(',', $ids));
return $this->json();
}
return $this->json(4001, '非法请求!');
}
/**
* 编辑
*
* @return Json|View
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function edit()
{
$id = input('id/d', 0);
if (!$info = RoleModel::findById($id)) {
return $this->json(4001, '记录不存在');
}
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'title' => 'require',
]);
if ($validate !== true) {
return $validate;
}
try {
$info->save($item);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
$this->data['item'] = $info;
return $this->view();
}
/**
* 单个字段编辑
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function modify(): Json
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'field' => 'require',
'value' => 'require',
]);
if ($validate !== true) {
return $validate;
}
if (!$info = RoleModel::findById($item['id'])) {
return $this->json(4001, '记录不存在');
}
$update = [$item['field'] => $item['value']];
try {
$info->save($update);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->json(4000, '非法请求');
}
/**
* 添加
*
* @return Json|View
* @throws Exception
*/
public function add()
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'title' => 'require',
]);
if ($validate !== true) {
return $validate;
}
try {
RoleModel::create($item);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->view();
}
/**
* 角色权限
*
* @return Json|View
* @throws Exception
*/
public function rule()
{
$id = input('id/d', 0);
if (!$item = RoleModel::findById($id)) {
return $this->json(4001, '记录不存在');
}
if ($this->request->isPost()) {
$ids = input('post.ids');
$roleUpdate = $ids;//角色更新数据
$ids = explode(',', $ids);
Db::startTrans();
try {
//查询角色已有权限
$hasRules = Rules::where('ptype', 'p')->where('v0', $id)->select()->toArray();
//角色最新权限列表
$currentRules = MenuModel::where('id', 'in', $ids)->field('name')->select()->toArray();
foreach ($currentRules as &$rule) {
$route = explode(':', $rule['name']);
$v1 = $route[0];
$v2 = $route[1] ?? 'index';
$rule['ptype'] = 'p';
$rule['v0'] = $id;
$rule['v1'] = $v1;
$rule['v2'] = $v2;
}
foreach ($hasRules as $k => $has) {
foreach ($currentRules as $m => $current) {
if ($has['ptype'] == $current['ptype'] && $has['v0'] == $current['v0'] && $has['v1'] == $current['v1'] && $has['v2'] == $current['v2']) {
unset($currentRules[$m]);//删除当前权限列表已存在的 currentRules剩下的就是需要添加的记录
unset($hasRules[$k]);//删除已有权限中存在的 hasRules剩下的就是需要删除的记录
}
}
}
$insert = $currentRules;//需要添加的数据
$delete = $hasRules;//需要删除的数据
$deleteIds = array_column($delete, 'id');//需要删除的ID
(new Rules())->saveAll($insert);
(new Rules())->where('id', 'in', $deleteIds)->delete();
cache('tauthz', null);//权限缓存清空
$item->save(['rules' => $roleUpdate]);
Db::commit();
return $this->json();
} catch (ValidateException $e) {
Db::rollback();
return $this->json(4001, $e->getError());
}
}
$selected = explode(',', $item['rules']);
$this->data['authJson'] = $this->authJson($selected);
$this->data['item'] = $item;
return $this->view();
}
/**
* 构造json数据
*
* @param array $selected
* @return false|string
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
private function authJson(array $selected = [])
{
$menus = Menu::field("id,pid,title,sort")
->where('status', Menu::STATUS_NORMAL)
->order('sort', 'desc')
->order('id', 'asc')
->select()->toArray();
foreach ($menus as $k => $m) {
$menus[$k]['checked'] = in_array($m['id'], $selected);
$menus[$k]['open'] = true;
}
$menus = CmsRepository::getInstance()->buildMenuChild(0, $menus);
return json_encode($menus, JSON_UNESCAPED_UNICODE);
}
/**
* 列表
*
* @return View|Json
* @throws Exception
*/
public function index()
{
if ($this->request->isPost()) {
$page = input('page/d', 1);
$limit = input('size/d', 20);
$items = RoleModel::findList([], [], $page, $limit, function ($q) {
return $q->order('sort', 'desc')->order('id', 'asc');
});
return $this->json(0, '操作成功', $items);
}
return $this->view();
}
}

View File

@ -0,0 +1,183 @@
<?php
namespace app\controller\manager;
use app\model\{AuthRule, AuthGroup, Log};
use app\validate\AuthRule as VAuthRule;
use Exception;
use think\exception\ValidateException;
use think\response\Json;
class Rule extends Base
{
/**
* 权限排序
* 暂不允许父级变更
*
* @return Json
* @throws Exception
*/
public function sort()
{
if ($this->request->isAjax()) {
$id = input('post.id');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = AuthRule::getById($id);
if(empty($item)){
return $this->json(3, '权限不存在');
}
if($sort == 'up'){
$where = "parent_id = {$item['parent_id']} and sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "parent_id = {$item['parent_id']} and sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = AuthRule::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new AuthRule();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('rule', 'sort', "权限排序ID{$id} ,标题:{$item['title']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '非法请求!');
}
/**
* 权限删除
*/
public function del()
{
if ($this->request->isAjax()) {
$ids = input('post.ids/a');
$items = AuthRule::where('id', 'in', $ids)->select();
if(!$items){
return $this->json(1, '无此权限');
}
if(AuthRule::where('parent_id', 'in', $ids)->count()){
return $this->json(2, '当前权限有下级权限,不可删除');
}
AuthRule::destroy($ids);
AuthGroup::resetGroupRulesCache();
$ids = implode(',', $ids);
Log::write('rule', 'del', "权限删除ID{$ids}");
return $this->json();
}
return $this->json(1, '非法请求!');
}
/**
* 权限修改
*/
public function edit()
{
if($this->request->isPost()){
$item = input('post.item/a');
$id = input('post.id');
$rule = AuthRule::getById($id);
if(empty($rule)){
return $this->json(1, '请选择正确的权限');
}
$rule2 = AuthRule::getByName($item['name']);
if(!empty($rule2) && $rule2['id'] != $id){
return $this->json(2, '已存在相同权限['.$item['name'].']');
}
try {
validate(VAuthRule::class)->check($item);
AuthRule::updateById($id, $item);
AuthGroup::resetGroupRulesCache();
Log::write('rule', 'edit', "权限编辑ID{$id}, 标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(3, $e->getError());
}
}
$id = input('param.id/d');
$rule = AuthRule::getById($id);
if(empty($rule)){
return $this->json(1,'无此权限信息,请核对之后再操作!');
}else{
$this->data['item'] = $rule;
if($rule['parent_id'] > 0){
$parent = AuthRule::getById($rule['parent_id']);
$this->data['parent'] = $parent;
}
return $this->view();
}
}
/**
* 权限添加
*/
public function add()
{
if($this->request->isPost()){
$item = input('post.item/a');
try {
validate(VAuthRule::class)->check($item);
$rule = AuthRule::getByName($item['name']);
if(!empty($rule)){
return $this->json(1, '已存在相同权限');
}
$rule = AuthRule::create($item);
//基本权限的话需要重置所有已有角色权限缓存
if ($item['is_base'] > 0) {
AuthGroup::resetGroupRulesCache();
} else {
AuthGroup::resetGroupRulesCache(1);
}
Log::write('rule', 'add', "权限新增ID{$rule->id}, 标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}
$parentId = input('param.parent_id/d',0);
if($parentId > 0){
$parent = AuthRule::getById($parentId);
$this->data['parent'] = $parent;
}
$this->data['parentId'] = $parentId;
return $this->view();
}
/**
* 权限列表(全部)
*/
public function index()
{
$list = AuthRule::getListTree();
$this->data['items'] = $list;
return $this->view();
}
}

View File

@ -0,0 +1,277 @@
<?php
namespace app\controller\manager;
use app\model\Log;
use app\repository\CmsRepository;
use app\repository\OperationRepository;
use app\validate\Slide as VSlide;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\response\Json;
use think\response\View;
class Slide extends Base
{
/**
* 编辑
*
* @return Json|View
* @throws DbException
* @throws ModelNotFoundException
*/
public function edit()
{
$id = $this->request->param('id/d', 0);
if (!$slide = OperationRepository::getInstance()->findSlideById($id)) {
return $this->json(4001, '数据不存在');
}
if ($this->request->isPost()) {
$item = input('post.item/a');
$validate = new VSlide();
if (!$validate->scene('slide')->check($item)) {
return $this->json(4002, $validate->getError());
}
unset($item['id']);
OperationRepository::getInstance()->updateSlide($item, $id);
return $this->json();
}
$this->data['item'] = $slide;
$this->data['positionsJson'] = $this->xmSelectPositionsJson([$slide['position']]);
$this->data['id'] = $id;
return $this->view();
}
/**
* 添加
*
* @return View|Json
*/
public function add()
{
$repo = OperationRepository::getInstance();
if ($this->request->isPost()) {
$item = input('post.item/a');
$validate = new VSlide();
if (!$validate->scene('slide')->check($item)) {
return $this->json(4002, $validate->getError());
}
$item['type'] = $item['type'] ?? 'img';
$repo->createSlide($item);
return $this->json();
}
$this->data['positionsJson'] = $this->xmSelectPositionsJson();
return $this->view();
}
/**
* 轮播图列表
*
* @return Json|View
* @throws Exception
*/
public function index()
{
$repo = OperationRepository::getInstance();
if ($this->request->isPost()) {
$position = $this->request->param('position/s', '');
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 30);
$whereMap = [];
$orders = ['sort'=>'asc'];
if (!empty($position)) {
$whereMap[] = ['position', '=', $position];
}
$list = $repo->slideList($whereMap, [], $page, $size, null, $orders);
return $this->json(0, 'success', $list);
}
$this->data['positions'] = $repo->slidePositions();
return $this->view();
}
/**
* 排序
* @return Json
*/
public function sort()
{
if (!$this->request->isPost()) {
return $this->json(4000, '非法请求');
}
try {
$id = $this->request->param('id/d', 0);
$sort = $this->request->param('sort/d', 0);
OperationRepository::getInstance()->updateSlide(['sort'=>$sort], $id);
} catch (Exception $e) {
return $this->json(4001, '排序失败');
}
return $this->json();
}
/**
* 删除
* @return Json
*/
public function del()
{
if (!$this->request->isPost()) {
return $this->json(4000, '非法请求');
}
$ids = $this->request->param('ids/a', []);
if (empty($ids)) {
$ids[] = $this->request->param('id/d', 0);
$ids = array_filter($ids);
}
if (count($ids)) {
OperationRepository::getInstance()->deleteSlides($ids);
Log::write(get_class(), 'del', '删除了轮播图涉及到的ID为'.implode(',', $ids));
}
return $this->json();
}
/**
* 显示位置下拉选项数据
*
* @param array $selected
* @param array $disabled
* @return false|string
*/
private function xmSelectPositionsJson(array $selected = [], array $disabled = [])
{
$positionList = OperationRepository::getInstance()->slidePositions();
foreach ($positionList as $k => $item) {
$positionList[$k]['selected'] = in_array($item['key'], $selected);
$positionList[$k]['disabled'] = in_array($item['key'], $disabled);
}
$positionList = CmsRepository::getInstance()->handleSelectedList($positionList);
return json_encode($positionList, JSON_UNESCAPED_UNICODE);
}
/**
* 轮播图显示位置管理
*
*/
public function position()
{
$repo = OperationRepository::getInstance();
if ($this->request->isPost()) {
$list = $repo->slidePositionList([], [], 1, 0);
return $this->json(0, 'success', $list);
}
return $this->view();
}
/**
* 添加显示位置信息
*
* @return Json|View
*/
public function addPosition()
{
$repo = OperationRepository::getInstance();
if ($this->request->isPost()) {
$item = input('post.item/a');
try {
$this->validate($item, [
'title|标题' => 'max:250',
'key|位置标识' => 'require|max:100|alphaDash'
]);
} catch (ValidateException $e) {
return $this->json(4002, $e->getError());
}
if ($repo->slidePositionExists($item['key'])) {
return $this->json(4003, '当前位置标识已存在!');
}
$repo->createSlidePosition($item);
return $this->json();
}
return $this->view();
}
/**
* 编辑显示位置信息
*
* @return Json|View
* @throws DbException
* @throws ModelNotFoundException
* @throws DataNotFoundException
*/
public function editPosition()
{
$id = $this->request->param('id/d', 0);
if (!$position = OperationRepository::getInstance()->findSlidePositionById($id)) {
return $this->json(4001, '数据不存在');
}
if ($this->request->isPost()) {
$item = input('post.item/a');
try {
$this->validate($item, [
'title|标题' => 'max:250'
]);
} catch (ValidateException $e) {
return $this->json(4002, $e->getError());
}
unset($item['id']);
unset($item['key']);
OperationRepository::getInstance()->updateSlidePosition($item, $id);
return $this->json();
}
$this->data['item'] = $position;
$this->data['id'] = $id;
return $this->view();
}
/**
* 删除显示位置信息
* @return Json
*/
public function delPosition()
{
if (!$this->request->isPost()) {
return $this->json(4000, '非法请求');
}
$ids = $this->request->param('ids/a', []);
if (empty($ids)) {
$ids[] = $this->request->param('id/d', 0);
$ids = array_filter($ids);
}
if (count($ids)) {
OperationRepository::getInstance()->deleteSlidePositions($ids);
Log::write(get_class(), 'delPosition', '删除了轮播显示位置涉及到的ID为'.implode(',', $ids));
}
return $this->json();
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace app\controller\manager;
use app\service\Tool;
use app\model\{System as MSystem, Log};
use app\service\Image;
use think\facade\Cache;
class System extends Base
{
/**
* 获取当前系统设置
*
* @return void
*/
public function index()
{
if ($this->request->isPost()) {
$item = input('post.item/a');
$img = input('post.img');
$system = MSystem::getSystem();
if (empty($system)) {
if(!empty($img)){
$item['mark_img'] = $img;
}
$system = MSystem::create($item);
Log::write('system', 'index', "系统设置ID{$system->id}");
} else {
if (!empty($img)) {
Image::delImg($system['mark_img']);
$item['mark_img'] = $img;
}
MSystem::update($item, ['id' => $system['id']]);
Log::write('system', 'index', "系统设置ID{$system['id']}");
}
return $this->json();
} else {
$item = MSystem::getSystem();
$positions = Image::getMarkPosition();
$this->data['item'] = $item;
$this->data['positions'] = $positions;
return $this->view();
}
}
public function other()
{
return $this->view();
}
public function clearCache()
{
Cache::clear();
$cachePath = app()->getRuntimePath().'cache';
$tempPath = app()->getRuntimePath().'temp';
Tool::removeByPath($cachePath);
Tool::removeByPath($tempPath);
clearstatcache();
return $this->json();
}
}

View File

@ -0,0 +1,221 @@
<?php
namespace app\controller\manager;
use app\service\Image;
use app\model\{System, File};
use app\validate\Upload as VUpload;
use think\facade\{Filesystem, Config, Lang};
use think\Image as TImage;
use app\controller\BaseController;
class Upload extends BaseController
{
protected $noNeedLogin = ['video', 'file', 'image', 'wangImage'];
private $isCompress = true;
private $validate;
private $uploadPath;
private $videoUploadPath;
private $uploadPathIsWritable = 0;
private $videoUploadPathIsWritable = 0;
private $DIRECTORY_SEPARATOR = "/";
public function __construct()
{
$system = System::getSystem();
if (!empty($system)) {
$this->isCompress = $system['compress'] ?? true;
}
$this->validate = new VUpload();
$this->uploadPath = Config::get('filesystem.disks.local.url');
$this->videoUploadPath = Config::get('filesystem.disks.video.url');
if (is_writable(app()->getRootPath().'public'.$this->uploadPath)) {
$this->uploadPathIsWritable = 1;
}
if (is_writable(app()->getRootPath().'public'.$this->videoUploadPath)) {
$this->videoUploadPathIsWritable = 1;
}
$this->DIRECTORY_SEPARATOR = DIRECTORY_SEPARATOR == "\\" ? "/" : DIRECTORY_SEPARATOR;
ini_set('max_execution_time', '0');
ini_set("memory_limit", '-1');
set_time_limit(0);
}
//视频上传
public function video()
{
$video = request()->file('video_video');
if (!$this->videoUploadPathIsWritable) {
return $this->json(1, '上传文件夹需要写入权限');
}
if ($this->validate->checkVideo($video)) {
$md5 = $video->md5();//文件md5
if ($fileItem = File::where('md5', $md5)->find()) {
$return['src'] = $fileItem['src'];
$fileItem['updated_at'] = date('Y-m-d H:i:s');
$fileItem->save();
return $this->json(200, '该文件已存在 路径为:'.$fileItem['path'], $return);
}
$path = request()->param('path/s', '');//指定路径 基于public下 若为空则默认
$hasPath = !empty($path);
// 去除以/storage/开头的部分 如/storage/20210808/test => 20210808/test
$path = ltrim(trim($path, $this->DIRECTORY_SEPARATOR), \app\model\Attachment::ROOT_NAME . $this->DIRECTORY_SEPARATOR);
$datePath = $hasPath ? $path : 'videos'.$this->DIRECTORY_SEPARATOR.date('Ymd');//自定义目录
$src = Filesystem::putFile($datePath, $video, 'uniqid');
$src = $this->uploadPath.'/'.$src;
$return['src'] = $src;
File::add($video, $src, $md5, 'video'); //加入上传文件表
return $this->json(0, 'ok', $return);
} else {
$errorMsg = Lang::get($this->validate->getError());
return $this->json(1, $errorMsg);
}
}
//文件上传(通用)
public function file()
{
$file = request()->file('file_file');
$md5 = $file->md5();//文件md5
$fileName = $file->getOriginalName();//原始文件名
if ($fileItem = File::where('md5', $md5)->find()) {
$return['src'] = $fileItem['src'];
$return['name'] = $fileName;
$fileItem['updated_at'] = date('Y-m-d H:i:s');
return $this->json(200, '该文件已存在 路径为:'.$fileItem['path'], $return);
}
if ($this->validate->checkFile($file)) {
try {
if (!$this->uploadPathIsWritable) {
throw new \Exception('上传文件夹需要写入权限');
}
$src = Filesystem::putFile(date('Ymd'), $file, 'uniqid');
$src = $this->uploadPath.$this->DIRECTORY_SEPARATOR.$src;
$return['src'] = $src;
$return['name'] = $fileName;
File::add($file, $src, $md5, 'file'); //加入上传文件表
} catch (\Exception $e) {
return $this->json(1, $e->getMessage());
}
return $this->json(0, 'ok', $return);
} else {
$errorMsg = Lang::get($this->validate->getError());
return $this->json(1, $errorMsg);
}
}
//图片上传(通用)
public function image()
{
// 字段名 image-image避免冲突 layui组件自动生成的隐藏file input框中name容易重名冲突
$image = request()->file('image_image');
$md5 = $image->md5();//文件md5
$type = request()->param('type/s', '');
$path = request()->param('path/s', '');//指定路径 基于public下 若为空则默认
$hasPath = !empty($path);
if ($this->validate->checkImage($image)) {
$info = @getimagesize($image->getPathname());
$width = $info[0] ?? 0;
$height = $info[1] ?? 0;
// 海报限制大小 750 * 1334
switch ($type) {
case 'porter':
if ($width != 750 || $height != 1334) {
return $this->json(1, '海报背景图尺寸大小固定为750 * 1334');
}
break;
}
if ($fileItem = File::where('md5', $md5)->find()) {
$return['src'] = $fileItem['src'];
$fileItem['updated_at'] = date('Y-m-d H:i:s');
return $this->json(200, '该文件已存在 路径为:'.$fileItem['path'], $return);
}
try {
if (!$this->uploadPathIsWritable) {
throw new \Exception('上传文件夹需要写入权限');
}
// 去除以/storage/开头的部分 如/storage/20210808/test => 20210808/test
if (strpos(trim($path, $this->DIRECTORY_SEPARATOR), \app\model\Attachment::ROOT_NAME.$this->DIRECTORY_SEPARATOR) === 0) {
$path = substr(trim($path, $this->DIRECTORY_SEPARATOR), strlen(\app\model\Attachment::ROOT_NAME.$this->DIRECTORY_SEPARATOR));
}
$datePath = $hasPath ? $path : date('Ymd');//自定义目录
$datePath = ($datePath == $this->DIRECTORY_SEPARATOR."storage") ? $this->DIRECTORY_SEPARATOR : $datePath;
$src = Filesystem::putFile($datePath, $image, 'uniqid');
$src = $this->uploadPath . $this->DIRECTORY_SEPARATOR . $src;
$suffix = strtolower($image->getOriginalExtension());
if ($suffix == 'gif') {
$return['thumb_src'] = $src; //TODO获取GIF缩略图
} else {
$return['thumb_src'] = Image::getThumb($src, 100, 100, TImage::THUMB_SCALING); //上传返回缩略图宽度为100
}
$return['src'] = $src;
if ($this->isCompress) {
Image::resize($src);
}
File::add($image, $src, $md5); //加入上传文件表
} catch (\Exception $e) {
return $this->json(1, $e->getMessage());
}
return $this->json(0, 'ok', $return);
} else {
$errorMsg = Lang::get($this->validate->getError());
return $this->json(1, $errorMsg);
}
}
//富文本编辑器商城图片
public function wangImage()
{
$imageArr = request()->file('wang_img'); // 该方式前端js上传方法中字段名称必须以数组形式传参 如 wang_img[] = 值
$errno = 0;
$data = [];
if (!$this->uploadPathIsWritable) {
$errno = 1;
$data[] = '上传文件夹需要写入权限';
} else {
foreach ($imageArr as $image) {
$md5 = $image->md5();//文件md5
if ($fileItem = File::where('md5', $md5)->find()) {
$return['src'] = $fileItem['src'];
$fileItem['updated_at'] = date('Y-m-d H:i:s');
$data[] = $fileItem['src'];
$fileItem->save();
continue;
}
if ($this->validate->checkImage($image)) {
$src = Filesystem::putFile(date('Ymd'), $image, 'uniqid');
$src = $this->uploadPath.$this->DIRECTORY_SEPARATOR.$src;
$data[] = $src;
if ($this->isCompress) {
Image::resize($src);
}
File::add($image, $src, $md5); //加入上传文件表
} else {
$errno = 1;
$data = [];
$data[] = Lang::get($this->validate->getError());
break;
}
}
}
$return['errno'] = $errno;
$return['data'] = $data;
return json($return);
}
}

24
app/event.php Normal file
View File

@ -0,0 +1,24 @@
<?php
// 事件定义文件
return [
//事件标识
'bind' => [
// 'UserLogin' => 'app\event\UserLogin',
],
//监听事件
'listen' => [
'AppInit' => [],
'HttpRun' => [],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
//订阅事件
'subscribe' => [
'app\subscribe\Spu',
'app\subscribe\Order',
'app\subscribe\Coupon',
],
];

View File

@ -0,0 +1,10 @@
<?php
namespace app\exception;
use Exception;
class ApiRedirectException extends Exception
{
}

View File

@ -0,0 +1,8 @@
<?php
namespace app\exception;
class RepositoryException extends \Exception
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace app\exception;
class TraitException extends \Exception
{
}

37
app/job/NotifySms.php Normal file
View File

@ -0,0 +1,37 @@
<?php
namespace app\job;
use app\repository\AccountRepository;
use think\queue\Job;
class NotifySms
{
public function fire(Job $job, $data){
//短信通知列表
if ($data) {
foreach ($data as $item) {
echo sprintf("短信发送成功phone:%s time:%s \n", $item['mobile'], date('Y-m-d H:i:s'));
sleep(mt_rand(1,3));
}
}
// if ($job->attempts() > 3) {
// //通过这个方法可以检查这个任务已经重试了几次了
// echo sprintf('发送短信失败过多');
// }
//如果任务执行成功后 记得删除任务不然这个任务会重复执行直到达到最大重试次数后失败后执行failed方法
$job->delete();
// 也可以重新发布这个任务
// $job->release(3); //$delay为延迟时间
}
public function failed($data){
// ...任务达到最大重试次数后,失败了
}
}

10
app/middleware.php Normal file
View File

@ -0,0 +1,10 @@
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
//\think\middleware\LoadLangPack::class,
// Session初始化
\think\middleware\SessionInit::class,
];

View File

@ -0,0 +1,35 @@
<?php
namespace app\middleware;
use Closure;
use app\service\Jwt as JwtService;
/**
* API登录认证需要先调用JWT解析用户信息
* Class ApiLogin
* @package app\middleware
*/
class ApiLogin
{
public function handle($request, Closure $next) {
$authorization = $request->authorization ?? '';
if (empty($authorization)) {
return json(['code' => 6001, 'msg' => '请填写token']);
}
if (!JwtService::validate($authorization)) {
return json(['code' => 6001, 'msg' => 'token验证失败或已失效']);
}
$userInfo = $request->user ?? [];
if (!isset($userInfo['user_id']) || empty($userInfo['user_id'])) {
return json(['code' => 6001, 'msg' => 'token已失效']);
}
// 自定义过期时间校验。
if(isset($userInfo['expire_time']) && time() >= $userInfo['expire_time']) {
return json(['code' => 6001, 'msg' => 'token已失效']);
}
return $next($request);
}
}

50
app/middleware/Auth.php Normal file
View File

@ -0,0 +1,50 @@
<?php
namespace app\middleware;
use Closure;
use app\model\AuthRule;
use tauthz\facade\Enforcer;
use think\facade\Cache;
class Auth
{
public function handle($request, Closure $next)
{
$auth = session('auth');
if (!$auth) {
return redirect(url('manager.login/index'));
}
$module = 'manager';
$controller = unCamelize(request()->controller());
$controller = str_replace($module.'.', '', $controller);
$controller = str_replace('.', '/', $controller);//兼容多层级目录 如 /manager/test/article/index
$action = unCamelize(request()->action());
$roles = Enforcer::getRolesForUser($auth['user_id']);
// $per = Enforcer::getPermissionsForUser($roles[0]);
// var_dump($controller);
// var_dump($action);
// var_dump($roles);
// var_dump($per);
// exit;
// return $next($request);//暂时停用权限校验
// var_dump($controller);
// var_dump($action);
// var_dump(Enforcer::hasPermissionForUser(1, $controller, 'group-make'));exit;
foreach ($roles as $role) {
// TODO 关注批量权限检测是否可用
//只需要有一个角色具有权限就放通 此处第一个参数不是用户 而是 角色 此方法是检测用户|角色是否具有某个权限的公用方法
if (Enforcer::hasPermissionForUser($role, $controller, $action)) {
return $next($request);
}
}
if (request()->isAjax()) {
return json(['code' => 4001, 'msg' => '没有权限']);
} else {
return view('/manager/error/jump')->assign('msg', '很抱歉,您还没有权限,请联系管理员开通!');
}
}
}

56
app/middleware/Csrf.php Normal file
View File

@ -0,0 +1,56 @@
<?php
namespace app\middleware;
use Closure;
use think\Request;
/**
* CSRF校验
*/
class Csrf
{
public function handle(Request $request, Closure $next)
{
if($request->isPost()){
$check = $request->checkToken();
if(false === $check) {
// return $this->csrfError($request);
}
}
return $next($request);
}
protected function csrfError($request, $msg = '非法请求, 用户身份认证失败!')
{
if($request->isAjax()) {
return json(['code' => 401, 'msg' => $msg], 200);
} else {
$referer = $_SERVER['HTTP_REFERER'] ?? null;
if (empty($referer)) {
$url = '/';
} else {
$domain = $request->domain();
$urlInfo = parse_url($referer);
$scheme = $urlInfo['scheme'] ?? '';
$requestSrc = '';
if (!empty($scheme)) {
$requestSrc = $scheme.'://'.($urlInfo['host'] ?? '');
}
if($domain != $requestSrc) {
$url = '/';
} else {
$url = 'javascript:history.back(-1);';
}
}
$errorData = [
'code'=> 401,
'msg' => $msg,
'data' => [],
'wait' => 5,
'url' => $url
];
return view('error/400', $errorData);
// 返回401视图 response type has html、json、jsonp、xml、file、view、redirect
}
}
}

37
app/middleware/JWT.php Normal file
View File

@ -0,0 +1,37 @@
<?php
namespace app\middleware;
use Closure;
use app\service\Jwt as JwtService;
/**
* 根据TOKEN解析用户信息
*
* Class JWT
* @package app\middleware
*/
class JWT
{
public function handle($request, Closure $next)
{
$authorization = $request->header('Authorization');
$tokenStr = $request->param('token/s', '');
if ($authorization) {
$authorization = str_replace('Bearer ', '', $authorization);
}
//优先取header中token
$token = $authorization ?: $tokenStr;
$userInfo = [];
if (!empty($token)) {
$userInfo = JwtService::parse($token);//token中携带的简易用户信息
}
$request->user = $userInfo;
// authorization用于移交ApiLogin认证
$request->authorization = $token;
return $next($request);
}
}

25
app/middleware/Login.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace app\middleware;
use Closure;
use think\Request;
/**
* 前台登录验证
*
* Class Login
* @package app\middleware
*/
class Login
{
public function handle(Request $request, Closure $next)
{
if (!session('frontend_auth')) {
$url = $request->url(true);
return redirect(url('login/index').'?url='.urlencode($url));
}
return $next($request);
}
}

11
app/model/Account.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace app\model;
use Exception;
use think\exception\ValidateException;
class Account extends Base
{
}

69
app/model/Attachment.php Normal file
View File

@ -0,0 +1,69 @@
<?php
namespace app\model;
use Exception;
use think\exception\ValidateException;
class Attachment extends Base
{
protected $name = 'file';
public const TYPE_DIR = 'dir';//目录
public const TYPE_IMG = 'image';//图片
public const TYPE_VIDEO = 'video';//视频
public const TYPE_FILE = 'file';//文件
public const ROOT_NAME = 'storage';//根目录名称
public const ROOT_PATH = "/".self::ROOT_NAME;//文件存放根路径
public static function list(): array
{
$where[] = ['src', 'like', '%'.self::ROOT_PATH."/"];
return self::findList($where);
}
/**
* 路径目录处理 会逐级检查路径上所有目录是否存在 不存在的目录全部创建[创建到数据库]
*
* @throws Exception
*/
public static function pathDirHandle(string $path): bool
{
$pathInfo = pathinfo($path);
$fullPath = isset($pathInfo['extension']) ? $pathInfo['dirname'] : $pathInfo['dirname']."/".$pathInfo['filename'];
// 全路径 如 /storage/dir1/dir2/dir3/dir4/ 注意前后都有/
$fullPath = $fullPath."/";
$pathArr = explode("/", trim($fullPath, "/"));
$insert = [];
$now = date('Y-m-d H:i:s');
try {
// 检测全路径上所有目录是否存在 不存在则创建
foreach ($pathArr as $k => $p) {
$currentPath = '/';
$currentArr = array_slice($pathArr, 0, $k);
if ($currentArr) {
$currentPath = "/".implode('/', $currentArr)."/";
}
if ($currentPath != '/' && self::where('path', $currentPath)->where('name', $p)->count() <= 0) {
$arr = [];
$arr['path'] = $currentPath;
$arr['name'] = $p;
$arr['created_at'] = $now;
$arr['is_dir'] = self::COMMON_ON;
$arr['type'] = self::TYPE_DIR;
$insert[] = $arr;
}
}
(new self())->saveAll($insert);
return true;
} catch (Exception $e) {
return false;
}
}
}

388
app/model/Base.php Normal file
View File

@ -0,0 +1,388 @@
<?php
namespace app\model;
use Exception;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;
use think\Paginator;
class Base extends Model
{
protected $autoWriteTimestamp = false;
// 布尔值数字关系
public const BOOL_FALSE = 0;
public const BOOL_TRUE = 1;
public const COMMON_ON = 1;
public const COMMON_OFF = 0;
//根据Id列表获取列表
public static function getListByIds($ids)
{
if (count($ids) == 0 || empty($ids)) {
return [];
}
return self::where('id', 'in', $ids)->select()->toArray();
}
//根据ID获取单条数据
public static function getById($id)
{
if ($id <= 0) {
return [];
}
return self::where('id', $id)->findOrEmpty()->toArray();
}
/**
* 通过ID查找记录
*
* @param int $id
* @param array $fields
* @param callable|null $call
* @return array|Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function findById(int $id, array $fields = [], callable $call = null)
{
$q = self::when(!empty($fields), function ($q) use ($fields) {
$q->field($fields);
});
if ($call !== null) {
$q = $call($q);
}
return $q->find($id);
}
/**
* 查找单个记录
*
* @param array $where
* @param array $fields
* @param callable|null $call
* @return array|Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function findOne(array $where = [], array $fields = [], callable $call = null)
{
$q = self::when(!empty($fields), function ($q) use ($fields) {
$q->field($fields);
})->where($where);
if ($call !== null) {
$q = $call($q);
}
return $q->find();
}
//根据ID更新数据
public static function updateById($id, $data)
{
return self::where('id', $id)->update($data);
}
//根据where条件和排序获取记录
public static function getListByWhereAndOrder($where, $order, $limit = 1)
{
return self::where($where)
->order($order)
->limit($limit)
->select()
->toArray();
}
/**
* 根据ID删除数据
*
* @param int $id
* @return bool
*/
public static function deleteById(int $id): bool
{
return self::where('id', $id)->delete();
}
/**
* 根据ID列表删除数据
*
* @param array $ids
* @return bool
*/
public static function deleteByIds(array $ids): bool
{
return self::whereIn('id', $ids)->delete();
}
/**
* 排序
*
* @param int $id 调整ID
* @param string $type 本次操作类型 向上、向下
* @param int $num 移动位数
* @param string $listType 列表的排序方式 默认为降序
* @param array $where 额外条件 如限制在指定分类下 where[] = ['category_id', '=', 6]
* @return array
* @throws Exception
*/
public static function sort(int $id, string $type, int $num = 1, string $listType = 'desc', array $where = []): array
{
$res = ['code' => 0, 'msg' => 'success'];
$item = self::getById($id);
if (!$item) {
$res['code'] = 1;
$res['msg'] = '记录不存在';
return $res;
}
if ($listType == 'desc') {
if ($type == 'down') {
$where[] = ['sort', '<', $item['sort']];
$order = "sort desc";
} else {
$where[] = ['sort', '>', $item['sort']];
$order = "sort asc";
}
} else {
if ($type == 'up') {
$where[] = ['sort', '<', $item['sort']];
$order = "sort desc";
} else {
$where[] = ['sort', '>', $item['sort']];
$order = "sort asc";
}
}
$forSortItems = self::getListByWhereAndOrder($where, $order, $num);
if (!empty($forSortItems)) {
$updateData = [];
$forSortCount = count($forSortItems);
for ($i = 0; $i < $forSortCount; $i++) {
if ($i == 0) {
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
} else {
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if (!empty($updateData)) {
$obj = new static();
$obj->saveAll($updateData);
return $res;
}
}
$res['code'] = 1;
$res['msg'] = '无需调整';
return $res;
}
/**
* 查询列表 [带分页 适用于后台]
*
* @param array $data 查询数据 格式如下
* [
* 'fields' => ['id','title','desc'],//查询字段
* 'where' => [
* ['name', 'like', '%thinkphp%'],
* ['title', 'like', '%thinkphp%'],
* ['id', '>', 0],
* ['status', '=', 1],
* ],//查询条件
* 'order' => ['order'=>'desc','id'=>'desc'],//排序
* 'size' => 50,//每页数量
* ]
* @param array $pageParams 分页参数 具体参考https://www.kancloud.cn/manual/thinkphp6_0/1037638
* @param callable|null $callback 复杂查询条件 使用闭包查询 此时建议data留空
* @return Paginator
* @throws DbException
*/
public static function findListWithPaginate(array $data = [], array $pageParams = [], callable $callback = null): Paginator
{
$q = new static();
$fields = isset($data['fields']) && !empty($data['fields']) ? $data['fields'] : [];
$where = isset($data['where']) && !empty($data['where']) ? $data['where'] : [];
$order = isset($data['order']) && !empty($data['order']) ? $data['order'] : [];
$limit = $data['size'] ?? 20;
if (count($where)) {
$q = $q->where($where);
}
if (count($fields)) {
$q = $q->field($fields);
}
if ($callback) {
$q = $callback($q);
}
if (count($order)) {
$q = $q->order($order);
}
$pageParams['list_rows'] = $limit;
return $q->paginate($pageParams);
}
/**
* 查询列表
*
* @param array $simpleWhere 简易查询条件
* @param array $fields 查询字段 []表示全部
* @param int $page 默认第一页 0不限制
* @param int $limit 限制条数 0不限制
* @param callable|null $callback 复杂的条件 使用闭包查询
* @param array $orders 键值对,排序
* @return array
* @throws Exception
*/
public static function findList(array $simpleWhere = [], array $fields = [], int $page = 1, int $limit = 0, callable $callback = null, array $orders = []): array
{
$q = new static();
$data = [
'total' => 0,
'current' => $page,
'size' => $limit,
'list' => new Collection(),
];
if (count($fields)) {
$q = $q->field($fields);
}
if (count($simpleWhere)) {
$q = $q->where($simpleWhere);
}
if ($callback) {
$q = $callback($q);
}
$data['total'] = $q->count();
if ($data['total']) {
if (count($orders)) {
$q = $q->order($orders);
}
if ($limit) {
if ($page) {
$q = $q->page($page);
}
$q = $q->limit($limit);
}
$data['list'] = $q->select();
}
return $data;
}
/**
* 获取路径
*
* @param int $pid
* @return string
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function getPath(int $pid): string
{
if ($pid == 0) {
$path = ',0,';
} else {
$parent = self::findById($pid);
if (empty($parent)) {
$path = ',0,';
} else {
$path = $parent['path'].$parent['id'].',';
}
}
return $path;
}
/**
* 刷新路径
*
* @param int $pid
* @param array $data 默认全部 若data不为空 至少包含[id,path, $pidField]
* @param string $pidField 父级ID字段名 默认 pid
* @throws Exception
*/
public static function refreshPath(int $pid = 0, array $data = [], string $pidField = 'pid')
{
$data = !empty($data) ? $data : self::column('id,path,'.$pidField);
$updateAllPaths = [];
self::recursionPath($pid, $data, $updateAllPaths);
(new static())->saveAll($updateAllPaths);
}
/**
* 获取递归最新路径
*
* @param int $pid
* @param array $data 全部数据 尽量传全部数据
* @param array $paths
*/
public static function recursionPath(int $pid, array $data, array &$paths = [])
{
foreach ($data as $k => $v) {
if ($pid == $v['pid']) {
$arr = [];
$arr['id'] = $v['id'];
if ($pid == 0) {
$arr['path'] = ',0,';
} else {
$arr['path'] = $paths[$v['pid']]['path'].$v['pid'].',';
}
$paths[$v['id']] = $arr;
unset($data[$k]);
self::recursionPath($v['id'], $data, $paths);
}
}
}
/**
* 获取所有后代ID[包含孙级] 仅对拥有path字段的表生效
*
* @param int $id
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function getAllChildrenIds(int $id): array
{
$item = self::find($id);
if ($item && isset($item['path'])) {
$path = $item['path'].$id.',';
return self::where('path', 'like', $path.'%')->column('id');
} else {
return [];
}
}
}

11
app/model/Business.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace app\model;
class Business extends Base
{
const state_reviewing = 0;
const state_on = 1;
const state_off = 2;
}

View File

@ -0,0 +1,16 @@
<?php
namespace app\model;
//商家和用户的链接表
class BusinessFlow extends Base
{
public function account()
{
return $this->hasOne(Account::class,"user_code","user_code");
}
public function business()
{
return $this->hasOne(Business::class,"code","business_code");
}
}

66
app/model/Category.php Normal file
View File

@ -0,0 +1,66 @@
<?php
namespace app\model;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 商家分类
* Class Disease
* @package app\model
*/
class Category extends Base
{
/**
* 根据父级ID 获取病种列表
*
* @param int $pid
* @param string[] $fields
* @return Disease[]|array|Collection
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function getListByPid(int $pid = 0, array $fields = ['pid', 'name', 'id'])
{
return self::where('pid', $pid)->order('id', 'desc')->field($fields)->select();
}
/**
* 获取全部病种列表
*
* @return Disease[]|array|Collection
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function getList()
{
return self::field('id,pid,name,commision')->order('id', 'desc')->order('id')->select();
}
/**
* 病种 xmSelect json数据
*
* @param int $pid
* @param array $selected
* @param array $disabled
* @return array|Disease[]|Collection
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function diseaseXmJson(int $pid = 0, array $selected = [], array $disabled = [])
{
$list = self::getListByPid($pid);
foreach ($list as $k => $m) {
$list[$k]['selected'] = in_array($m['id'], $selected);
$list[$k]['disabled'] = in_array($m['id'], $disabled);
}
return $list;
}
}

8
app/model/Comment.php Normal file
View File

@ -0,0 +1,8 @@
<?php
namespace app\model;
class Comment extends Base
{
//评论表
}

View File

@ -0,0 +1,8 @@
<?php
namespace app\model;
class CommentRule extends Base
{
//评论规则表
}

20
app/model/Coupon.php Normal file
View File

@ -0,0 +1,20 @@
<?php
namespace app\model;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 优惠券
* Class Coupon
* @package app\model
*/
class Coupon extends Base
{
//是否验证
const is_verificated_on = 1;//1已验证
const is_verificated_off = 0;//0未验证
}

21
app/model/CouponMain.php Normal file
View File

@ -0,0 +1,21 @@
<?php
namespace app\model;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 优惠券主表
* Class CouponMain
* @package app\model
*/
class CouponMain extends Base
{
const status_on = 0;//进行中
const status_off = 1;//停止
const on_shelf_on = 0;//上架状态
const on_shelf_off = 1;//下架状态
}

18
app/model/CouponType.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace app\model;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 优惠券类型
* Class CouponType
* @package app\model
*/
class CouponType extends Base
{
}

18
app/model/Deduction.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace app\model;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 扣费记录
* Class Deduction
* @package app\model
*/
class Deduction extends Base
{
}

129
app/model/File.php Normal file
View File

@ -0,0 +1,129 @@
<?php
namespace app\model;
use app\service\AliOss;
use Exception;
use think\facade\Config;
use think\Image;
class File extends Base
{
const IMG = 'image';
const VIDEO = 'video';
const FILE = 'file';
//获取文件类型
public static function getTypes()
{
return [
'image' => '图片',
'video' => '视频',
'file' => '文件'
];
}
//获取文件列表
public static function getList($type = '', $page = 1, $per = 20)
{
$limit = ($page - 1) * $per;
if ($type != '') {
if (!in_array($type, array_keys(self::getTypes()))) {
return [];
}
$items = self::where('type', $type)
->order('id desc');
} else {
$items = self::order('id desc');
}
$items = $items->limit($limit, $per)->select()->toArray();
foreach ($items as &$item) {
$item['sizeStr'] = sizeToStr($item['size']);
}
return $items;
}
//获取分页列表
public static function getListPage($type = '', $per = 20)
{
if ($type != '') {
if (!in_array($type, array_keys(self::getTypes()))) {
return [];
}
return self::where('type', $type)
->order('id desc')
->paginate([
'list_rows' => $per,
'query' => [
'type' => $type
]
], false);
} else {
return self::order('id desc')
->paginate([
'list_rows' => $per
], false);
}
}
//添加,$w_h图片尺寸大小单位像素只对type=img时有效
public static function add($file, $src, $md5, $type = 'image')
{
$realPath = public_path().ltrim($src, '/');
$oss = false;
if (is_file($realPath) && $type == 'image') {
$img = Image::open($realPath);
list($w, $h) = $img->size();
$w_h = $w.'px * '.$h.'px';
} else {
$w_h = '';
}
$now = date('Y-m-d H:i:s');
Attachment::pathDirHandle($src);
Config::load('extra/base', 'base');
$baseConfig = config('base');
if (isset($baseConfig['oss']) && $baseConfig['oss']!= "false" && $baseConfig['oss']!== false) {
$ossObject = AliOss::instance();
try {
$pathInfo = pathinfo($src);
$ossConfig = AliOss::config();
$bucket = $ossConfig['bucket'];
//是否存在
if (!$ossObject->doesObjectExist($bucket, ltrim($src, '/'))) {
//创建目录
$ossObject->createObjectDir($bucket, ltrim($pathInfo['dirname'], '/'));
$ossObject->uploadFile($bucket, ltrim($src, '/'), $realPath);
}
$oss = true;
} catch (Exception $e) {
\think\facade\Log::error('阿里云OSS上传文件失败 '.$e->getMessage());
}
}
// 将src中路径创建
return self::create([
'type' => $type,
'name' => $file->getOriginalName(),
'md5' => $md5,
'src' => $src,
'path' => isset(pathinfo($src)['dirname']) ? pathinfo($src)['dirname'].'/' : '',
'size' => $file->getSize(),
'suffix' => $file->getOriginalExtension(),
'mime_type' => $file->getOriginalMime(),
'created_at' => $now,
'updated_at' => $now,
'is_oss' => $oss,
'w_h' => $w_h
]);
}
//获取所有记录
public static function getAll()
{
return self::select()->toArray();
}
}

20
app/model/Log.php Normal file
View File

@ -0,0 +1,20 @@
<?php
namespace app\model;
class Log extends Base
{
//记录操作日志
public static function write($controller, $action, $content)
{
$auth = session('auth');
return self::create([
'member_id' => $auth['user_id'],
'name' => $auth['username'],
'ip' => request()->ip(),
'create_time' => time(),
'controller' => $controller,
'action' => $action,
'content' => $content
]);
}
}

6
app/model/LoginLog.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace app\model;
class LoginLog extends Base
{
}

81
app/model/Member.php Normal file
View File

@ -0,0 +1,81 @@
<?php
namespace app\model;
use think\facade\Db;
class Member extends Base
{
public const STATUS_NORMAL = 1;//正常
public const STATUS_DISABLE = 0;//禁用
public const ANENT_role_id = 2;//角色id 2 为代理商
public static function getList($limit = 40)
{
return self::alias('m')
->leftjoin('auth_group g', 'g.id=m.group_id')
->field('m.id,m.username,m.login_time,m.group_id,g.title')
->order('m.id', 'asc')
->paginate($limit);
}
/**
* 获取所有代理商
* */
public static function getAgentAll(){
$subQuery = Db::name('member')
->field('id,business_code,nickname')
->whereRaw('(find_in_set("'.Member::ANENT_role_id.'", roles))')
->buildSql();
return Db::table($subQuery . ' a')
->join("business b" ,"a.business_code = b.code")
->field("a.*")
->order('a.id', 'desc')
->select();
}
/**
* 根据角色分组返回用户
* @param int $groupId 角色分组ID
* @param int $limit 每页数量
*/
public static function getListByGroup($groupId, $limit = 40)
{
return self::alias('m')
->leftjoin('auth_group g', 'g.id=m.group_id')
->field('m.id,m.username,m.login_time,m.group_id,g.title')
->where('m.group_id', '=', $groupId)
->order('m.id', 'asc')
->paginate($limit);
}
//根据用户名获取管理账号
public static function getByUserName($username)
{
return self::where('username', trim($username))
->findOrEmpty()
->toArray();
}
//根据ID获取管理账户和相关权限
public static function getMemberAndRulesByID($memberId)
{
return self::alias('m')
->join('auth_group g', 'm.group_id = g.id', 'LEFT')
->field('m.group_id,g.rules')
->where('m.id', $memberId)
->findOrEmpty()
->toArray();
}
public static function updateCates($id, $cates)
{
$cates = implode(',', $cates);
$data = ['cates' => $cates];
self::updateById($id, $data);
}
}

71
app/model/Menu.php Normal file
View File

@ -0,0 +1,71 @@
<?php
namespace app\model;
use Exception;
class Menu extends Base
{
public const SHOW_YES = 1;
public const SHOW_NO = 0;
public const STATUS_NORMAL = 1;
public const STATUS_DISABLE = 0;
public const TYPE_MENU = 'menu';
public const TYPE_ACTION = 'action';
/**
* 默认操作
*
* @return string[]
*/
public static function defaultAction(): array
{
return [
'index' => '查看',
'add' => '添加',
'edit' => '编辑',
'del' => '删除',
'sort' => '排序',
'modify' => '属性设置',
];
}
/**
* 自从生成常规操作权限
*
* @param int $id
* @param string $name
* @param string $path
* @throws Exception
*/
public static function generate(int $id, string $name, string $path)
{
$actions = self::defaultAction();
$delete = [];
$insert = [];
$created = date('Y-m-d H:i:s');
foreach ($actions as $key => $action) {
$name = explode(':', $name)[0];
$delete[] = $name.':'.$key;
$arr = [];
$arr['title'] = $action;
$arr['pid'] = $id;
$arr['name'] = $name.':'.$key;
$arr['type'] = self::TYPE_ACTION;
$arr['path'] = $path.$id.',';
$arr['remark'] = sprintf("自动生成[%s][%s]操作", $name, $action);
$arr['created_at'] = $created;
$insert[] = $arr;
}
//删除已有常规操作
self::where('pid', $id)->whereIn('name', $delete)->delete();
//新增常规操作
(new self())->saveAll($insert);
}
}

18
app/model/Model.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace app\model;
class Model extends Base
{
//获取模型列表
public static function getList()
{
return self::order('sort asc')
->select()
->toArray();
}
public static function onAfterInsert($model)
{
$model->sort = $model->id;
$model->save();
}
}

8
app/model/PaymentLog.php Normal file
View File

@ -0,0 +1,8 @@
<?php
namespace app\model;
class PaymentLog extends Base
{
public const TYPE_ORDER = 'order';//订单支付
}

24
app/model/Recharge.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace app\model;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 充值记录
* Class Recharge
* @package app\model
*/
class Recharge extends Base
{
const state_off = 0;//未支付
const state_on = 1;//已支付
public function business()
{
return $this->hasOne(Business::class,"code","business_code")->bind(["business_name"]);
}
}

8
app/model/Role.php Normal file
View File

@ -0,0 +1,8 @@
<?php
namespace app\model;
class Role extends Base
{
public const STATUS_NORMAL = 1; //正常
public const STATUS_DISABLE = 0;//禁用
}

7
app/model/Rules.php Normal file
View File

@ -0,0 +1,7 @@
<?php
namespace app\model;
class Rules extends Base
{
}

40
app/model/Slide.php Normal file
View File

@ -0,0 +1,40 @@
<?php
namespace app\model;
class Slide extends Base
{
public static function delByIds($ids)
{
return self::whereIn('id', $ids)->delete();
}
//获取幻灯片列表
public static function getList()
{
return self::order("sort asc")
->select()
->toArray();
}
public static function onAfterInsert($slide)
{
$slide->sort = $slide->id;
$slide->save();
}
//获取轮播图涉及到的文件
public static function getFilesInUse()
{
$items = self::select()->toArray();
$data = [];
foreach ($items as $item) {
$src = trim($item['src']);
if (!empty($src)) {
$key = getKeyByPath($src);
$data[$key] = $src;
}
}
return $data;
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace app\model;
/**
* 轮播图显示位置
*
* Class SlidePosition
* @package app\model
*/
class SlidePosition extends Base
{
public static function allPosition()
{
return self::select();
}
}

54
app/model/System.php Normal file
View File

@ -0,0 +1,54 @@
<?php
namespace app\model;
class System extends Base
{
//获取友情链接上传图片尺寸
public static function getLinkImageSize()
{
$system = self::getSystem();
if(!empty($system['link_w']) && !empty($system['link_h'])){
$linkSize = $system['link_w'] . '像素 X ' . $system['link_h'] . '像素';
}else{
$linkSize = '';
}
return $linkSize;
}
//获取幻灯片上传尺寸
public static function getSlideImageSize()
{
$system = self::getSystem();
if(!empty($system['slide_w']) && !empty($system['slide_h'])){
$slideSize = $system['slide_w'] . '像素 X ' . $system['slide_h'] . '像素';
}else{
$slideSize = '';
}
if(!empty($system['slide_mobile_w']) && !empty($system['slide_mobile_h'])){
$slideMobileSize = $system['slide_mobile_w'] . '像素 X ' . $system['slide_mobile_h'] . '像素';
}else{
$slideMobileSize = '';
}
return [
'slide_size' => $slideSize,
'slide_mobile_size' => $slideMobileSize
];
}
//获取文章图片尺寸
public static function getArticleImageSize()
{
$system = self::getSystem();
if(!empty($system['article_w']) && !empty($system['article_h'])){
$articleSize = $system['article_w'] . '像素 X ' . $system['article_h'] . '像素';
}else{
$articleSize = '';
}
return $articleSize;
}
//获取系统配置信息
public static function getSystem()
{
return self::order('id asc')
->findOrEmpty()
->toArray();
}
}

View File

@ -0,0 +1,107 @@
<?php
namespace app\repository;
use app\exception\RepositoryException;
use app\service\Repository;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;
/**
* 账户域 相关操作(客户账号)
*
* Class AccountRepository
* @package app\repository
* @method self getInstance(Model $model = null) static
*/
class AccountRepository extends Repository
{
/**
* 获取用户列表
*
* @throws RepositoryException
*/
public function list(): ?array
{
return $this->findList();
}
/**
* 获取指定账户记录By手机号
*
* @param string $phone
* @param array $fields
* @return Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function infoByPhone(string $phone, array $fields = []): ?Model
{
$where[] = ['mobile', '=', $phone];
return $this->findOneByWhere($where, $fields);
}
/**
* 获取指定账户记录By用户名
*
* @param string $username
* @param array $fields
* @return Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function infoByUsername(string $username, array $fields = []): ?Model
{
$where[] = ['username', '=', $username];
return $this->findOneByWhere($where, $fields);
}
/**
* 通过微信小程序的openID查询
*
* @param string $openID
* @return array|Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function findByOpenID(string $openID)
{
return $this->model->where('openid', $openID)->find();
}
/**
* 修改密码
*
* @param int $accountId
* @param string $oldPwd
* @param string $newPwd
* @return bool
* @throws RepositoryException
*/
public function modifyPwd(int $accountId, string $oldPwd, string $newPwd): bool
{
if (!$user = $this->findById($accountId)) {
throw new RepositoryException('用户不存在');
}
if ($user['password'] != md5($oldPwd)) {
throw new RepositoryException('原密码错误');
}
$user->password = md5($newPwd);
return $user->save();
}
}

View File

@ -0,0 +1,115 @@
<?php
namespace app\repository;
use app\exception\RepositoryException;
use app\model\Business;
use app\model\CouponMain;
use app\model\Deduction;
use app\model\Recharge;
use app\service\Repository;
use think\Collection;
use think\Model;
/**
* 商家域 相关操作
*
* Class BusinessRepository
* @package app\repository
* @method self getInstance(Model $model = null) static
*/
class BusinessRepository extends Repository
{
/**
* 根据条件查询列表
*
* @param array $where 查询条件
* @param int $page 默认第一页 0不限制
* @param int $limit 限制条数 0不限制
* @param array $order
* @return array
* @throws RepositoryException
*/
public function businessList(array $where = [], int $page = 1, int $limit = 0, array $order = [])
{
$q = $this->model->alias("a")->field("id")->withJoin(["account" => ["avatar_url", "nick_name"], "business"]);
$data = [
'total' => 0,
'current' => $page,
'size' => $limit,
'list' => new Collection(),
];
if (count($where)) {
$q = $q->where($where);
}
if (count($order)) {
$q = $q->order($order);
}
$data['total'] = $q->count();
if ($data['total']) {
if ($limit) {
if ($page) {
$q = $q->page($page);
}
$q = $q->limit($limit);
}
$data['list'] = $q->select();
}
return $data;
}
/**
* 优惠券列表
*
* @param string $businessCode 商家code
* @param int $page 默认第一页 0不限制
* @param int $limit 限制条数 0不限制
* @param array $order
* @return array
* @throws RepositoryException
*/
public function businessCouponList($where, int $page = 1, int $limit = 0, array $order = ["create_time" => "desc", "id" => "desc"])
{
return CouponMain::findList($where, [], $page, $limit, null, $order);
}
/**
* 扣费记录
*
* @param string $businessCode 商家code
* @param int $page 默认第一页 0不限制
* @param int $limit 限制条数 0不限制
* @param array $order
* @return array
* @throws RepositoryException
*/
public function businessDeductionList($where, int $page = 1, int $limit = 0, array $order = ["create_time" => "desc", "id" => "desc"])
{
return Deduction::findList($where, [], $page, $limit, null, $order);
}
/**
* 充值记录
*
* @param string $businessCode 商家code
* @param int $page 默认第一页 0不限制
* @param int $limit 限制条数 0不限制
* @param array $order
* @return array
* @throws RepositoryException
*/
public function businessRechargeList($where, int $page = 1, int $limit = 0, array $order = ["create_time" => "desc", "id" => "desc"])
{
return Recharge::findList($where, [], $page, $limit, function ($q){
return $q->withJoin(["business"=>["business_name"]]);
}, $order);
}
/* 获取所有不是代理商的商家*/
public function getBusinessAll(){
return Business:: where("state", Business::state_on)->select();
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace app\repository;
use app\traits\cms\ArticleTrait;
use app\traits\cms\MenuTrait;
use app\traits\CmsCategoryTrait;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;
use app\service\Repository;
/**
* CMS 基础功能仓储
*
* Class CmsRepository
* @package app\repository
* @method self getInstance(Model $model = null) static
*/
class CmsRepository extends Repository
{
use CmsCategoryTrait;
use MenuTrait;
use ArticleTrait;
/**
* xmSelect下拉列表格式处理
* [['title' => 'aa', 'value' => 1, 'selected' => true, 'prefix' => '&nbsp;&nbsp;&nbsp;&nbsp;']]
*
* @param array $data 待处理的数据
* @param string $symbol 分隔符号 默认 &nbsp;
* @param int $repeatNum 重复次数 默认4
* @return array
*/
public function handleSelectedList(array $data, string $symbol = '&nbsp;', int $repeatNum = 4): array
{
$list = [];
foreach ($data as $item) {
$level = $item['level'] ?? 0;
$arr = $item;
$arr['children'] = $arr['children'] ?? [];
$arr['prefix'] = str_repeat($symbol, $level * $repeatNum);
$list[] = $arr;
}
return $list;
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace app\repository;
use app\exception\RepositoryException;
use app\model\CouponMain;
use app\service\Repository;
use think\Model;
/**
* 优惠券 相关操作
*
* Class CouponRepository
* @package app\repository
* @method self getInstance(Model $model = null) static
*/
class CouponRepository extends Repository
{
/**
* 优惠券列表
*
* @param string $businessCode 商家code
* @param array $order
* @return array
* @throws RepositoryException
*/
public function businessCouponModel($where)
{
return CouponMain::where($where);
}
}

View File

@ -0,0 +1,212 @@
<?php
namespace app\repository;
use app\model\SlidePosition;
use Exception;
use think\Model;
use app\model\Slide;
use think\Collection;
use app\service\Repository;
use think\db\exception\DbException;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
/**
* 运营领域 相关
*
* Class OperationRepository
* @package app\repository
* @method self getInstance(Model $model = null) static
*/
class OperationRepository extends Repository
{
/**
* 轮播位置
*
* @return string[][]
*/
public function slidePositions(): array
{
try {
return SlidePosition::allPosition()->toArray();
} catch (Exception $e) {
return [];
}
}
/**
* 获取轮播
*
* @param int $id
* @return array|Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function findSlideById(int $id)
{
return Slide::findById($id);
}
/**
* 轮播列表
*
* @param array $where
* @param array $fields
* @param int $page
* @param int $size
* @param callable|null $call
* @param array $orders
* @return array
* @throws Exception
*/
public function slideList(array $where=[], array $fields=[], int $page=1, int $size=20, callable $call=null, array $orders=[]): array
{
return Slide::findList($where, $fields, $page, $size, $call, $orders);
}
/**
* 更新轮播
*
* @param array $data
* @param int $id
* @return bool
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function updateSlide(array $data, int $id): bool
{
$item = (new Slide())->where('id', $id)->find();
if ($item) {
return $item->save($data);
}
return false;
}
/**
* 创建轮播
*
* @param array $data
* @return Slide
*/
public function createSlide(array $data): Slide
{
$data['created_at'] = date('y-m-d H:i:s');
return Slide::create($data);
}
/**
* 删除轮播图
*
* @param array $ids
* @return bool
*/
public function deleteSlides(array $ids): bool
{
return Slide::deleteByIds($ids);
}
/**
* 轮播位置是否存在
*
* @param string $position
* @param int $exceptId 需要排除的显示位置ID
* @return bool
*/
public function slidePositionExists(string $position, int $exceptId = 0): bool
{
return (new SlidePosition())->when($exceptId > 0, function ($q) use ($exceptId) {
$q->where('id', '<>', $exceptId);
})->where('key', $position)->count() > 0;
}
/**
* 根据显示位置查询相关的轮播图信息
*
* @param string $position 轮播图位置标识
* @param int $size 限制查询数量
* @throws Exception
*/
public function slideListByPosition(string $position, int $size=0): ?Collection
{
$where[] = ['position', '=', $position];
$orders = ['sort'=>'asc'];
return Slide::findList($where, [], 1, $size, null, $orders)['list'];
}
/**
* 轮播显示位置列表
*
* @param array $where
* @param array $fields
* @param int $page
* @param int $size
* @param callable|null $call
* @param array $orders
* @return array
* @throws Exception
*/
public function slidePositionList(array $where=[], array $fields=[], int $page=1, int $size=20, callable $call=null, array $orders=[]): array
{
return SlidePosition::findList($where, $fields, $page, $size, $call, $orders);
}
/**
* 更新轮播位置
*
* @param array $data
* @param int $id
* @return bool
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function updateSlidePosition(array $data, int $id): bool
{
$item = (new SlidePosition())->where('id', $id)->find();
if ($item) {
$item->save($data);
}
return false;
}
/**
* 创建轮播位置
*
* @param array $data
* @return SlidePosition
*/
public function createSlidePosition(array $data): SlidePosition
{
$data['created_at'] = date('y-m-d H:i:s');
return SlidePosition::create($data);
}
/**
* 删除轮播位置
*
* @param array $ids
* @return bool
*/
public function deleteSlidePositions(array $ids): bool
{
return SlidePosition::deleteByIds($ids);
}
/**
* 获取轮播位置
*
* @param int $id
* @return array|Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function findSlidePositionById(int $id)
{
return SlidePosition::findById($id);
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace app\repository;
use app\exception\RepositoryException;
use app\model\Recharge;
use app\service\Repository;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;
/**
* 充值户域 相关操作
* Class RechargeRepository
* @package app\repository
* @method self getInstance(Model $model = null) static
*/
class RechargeRepository extends Repository
{
/**
* 创建一个支付订单
* */
public function createOrder($businessCode, $money)
{
$data = [
"order_num" => createUuid(),
"business_code" => $businessCode,
"money" => $money,
"state" => Recharge::state_off,
"create_time" => date("Y-m-d H:i:s"),
"balance" => 0,
];
return Recharge::create($data);
}
}

9
app/service.php Normal file
View File

@ -0,0 +1,9 @@
<?php
use tauthz\TauthzService;
// 系统服务定义文件
// 服务在完成全局初始化之后执行
return [
TauthzService::class,
];

46
app/service/AliOss.php Normal file
View File

@ -0,0 +1,46 @@
<?php
namespace app\service;
use OSS\Core\OssException;
use OSS\OssClient;
use think\facade\Config;
use think\facade\Log;
class AliOss
{
private static $oss = null;
private function __construct()
{
}
private function __clone()
{
}
/**
* 阿里云OSS
*
*/
public static function config()
{
Config::load('extra/alioss', 'alioss');
return config('alioss');
}
// 阿里云OSS实例 单例模式
public static function instance(): ?OssClient
{
if (self::$oss == null) {
try {
$conf = self::config();
self::$oss = new OssClient($conf['accessKeyId'], $conf['accessKeySecret'], $conf['endpoint']);
} catch (OssException $e) {
Log::error('实例化阿里云OSS失败: ' . $e->getMessage());
return null;
}
}
return self::$oss;
}
}

64
app/service/Alipay.php Normal file
View File

@ -0,0 +1,64 @@
<?php
namespace app\service;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Log;
use think\facade\Config;
class Alipay
{
private static $app = null;
private function __construct()
{
}
private function __clone()
{
}
/**
* 支付宝配置
*
* @return array
*/
public static function config(): array
{
Config::load('extra/alipay', 'alipay');
$conf = config('alipay');
return [
'app_id' => trim($conf['appId']),
'notify_url' => trim($conf['notify_url']),
'return_url' => trim($conf['return_url']) ?? trim($conf['notify_url']),
'ali_public_key' => trim($conf['aliPubKey']),//注意 这里的是支付宝的公钥
// 加密方式: **RSA2**
'private_key' => trim($conf['priKey']),
// 使用公钥证书模式请配置下面两个参数同时修改ali_public_key为以.crt结尾的支付宝公钥证书路径
// 如(./cert/alipayCertPublicKey_RSA2.crt
// 'app_cert_public_key' => './cert/appCertPublicKey.crt', //应用公钥证书路径
// 'alipay_root_cert' => './cert/alipayRootCert.crt', //支付宝根证书路径
'log' => [ // optional
'file' => './logs/alipay.log',
'level' => 'debug', // 建议生产环境等级调整为 info开发环境为 debug
'type' => 'single', // optional, 可选 daily.
'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
],
'http' => [ // optional
'timeout' => 5.0,
'connect_timeout' => 5.0,
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
// 'mode' => 'dev', // optional,设置此参数,将进入沙箱模式
];
}
//支付宝支付实例 单例模式
public static function getInstance(): ?\Yansongda\Pay\Gateways\Alipay
{
if (self::$app == null) {
self::$app = Pay::alipay(self::config());
}
return self::$app;
}
}

201
app/service/Excel.php Normal file
View File

@ -0,0 +1,201 @@
<?php
namespace app\service;
use PhpOffice\PhpSpreadsheet\Shared\Date as EDate;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use think\file\UploadedFile;
class Excel
{
// 导出excel默认样式
public static array $excelStyle = [
'font' => [
'name' => '宋体',
],
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER, // 水平居中
'vertical' => Alignment::VERTICAL_CENTER, // 垂直居中
'wrapText' => true,
],
'borders' => [
'allBorders' => [
'borderStyle' => Border::BORDER_THIN,
'color' => ['rgb' => 'eeeeee'],
]
],
];
public static array $defaultSetting = [
'cell_width' => 30, // 默认列宽
'font_size' => 12, // 默认excel内容字体大小
];
//导出
static public function export($spreadsheet,$filename)
{
$writer = new Xlsx($spreadsheet);
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header('Content-Disposition:inline;filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Pragma: no-cache");
$writer->save('php://output');
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
exit;
}
public static function cancelTimeLimit()
{
ini_set('max_execution_time', '0');
ini_set("memory_limit", '-1');
set_time_limit(0);
}
/**
* 根据header字段获取可配置列的cellId列表
* 默认前26列为可配置列A~Z, $headerLength不能超过26 * 27 = 702
*
* @param int $headerLength
* @return array
*/
public static function getCellIds(int $headerLength): array
{
$defaultCellIds = range('A', 'Z', 1);
$cellIds = $defaultCellIds;
$loop = ceil($headerLength / 26);
if($loop>1) {
$maxPrefixIndex = ($loop - 2) >= 25 ? 25 : ($loop - 2);
for ($prefixIndex = 0; $prefixIndex<= $maxPrefixIndex; $prefixIndex++) {
$prefix = $defaultCellIds[$prefixIndex];
$cellIds = array_merge($cellIds, array_map(function ($val) use($prefix) {
return $prefix.$val;
}, $defaultCellIds));
}
}
return $cellIds;
}
/**
* 设置导出表数据
*
* @param Worksheet $sheet 工作表对象
* @param array $cellValues 数据信息,二维数组(ps若字段值需要指定样式以数组格式传递[$val, DataType::TYPE_STRING])。第二行开始填充
* @param array $header 表头信息, 第一行为表头
* @param string $sheetTitle 工作表标题
* @param array $cellWidthList 列宽样式,键值对,键名为列序号(从0开始计算)
* @param array $excelStyle 表数据样式
* @param array $defaultList 默认设置样式
* @param array $cellWrapList 列换行样式
* @return bool
*/
public static function setExcelCells(Worksheet $sheet, array $cellValues, array $header, string $sheetTitle = '数据列表', $cellWidthList = [], $excelStyle = [], $defaultList = [], $cellWrapList = []): bool
{
$defaultStyle = [
'font' => [
'name' => '宋体',
],
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER, // 水平居中
'vertical' => Alignment::VERTICAL_CENTER, // 垂直居中
'wrapText' => false,
],
'borders' => [
'allBorders' => [
'borderStyle' => Border::BORDER_THIN,
'color' => ['rgb'=>'eeeeee'],
]
],
];
$headerLength = count($header);
if($headerLength === 0) return false;
$cellIds = self::getCellIds($headerLength);
$lastCellId = $cellIds[$headerLength-1];
$contentIndex = 2;
foreach ($cellValues as $n => $itemCell) {
foreach ($itemCell as $i => $cellValue) {
if(is_array($cellValue)) {
$sheet->setCellValueExplicit($cellIds[$i] . $contentIndex, ...$cellValue);
} else {
$sheet->setCellValue($cellIds[$i] . $contentIndex, $cellValue);
}
}
$contentIndex++;
}
try {
$headerStr = 'A1:' . $lastCellId.'1';
$bodyStr = 'A2:' . $lastCellId . ($contentIndex - 1);
$defaultWidth = 24; // 默认列宽24个字符
$fontSize = 12; // 默认字体大小为12号
if(!empty($defaultList)) {
if(isset($defaultList['cell_width']) && is_numeric($defaultList['cell_width']) && $defaultList['cell_width'] > 0) {
$defaultWidth = $defaultList['cell_width'];
}
if(isset($defaultList['font_size']) && is_numeric($defaultList['font_size']) && $defaultList['font_size'] > 0) {
$fontSize = $defaultList['font_size'];
}
}
$sheet->setTitle(empty($sheetTitle) ? '数据列表': $sheetTitle);
$sheet->getDefaultColumnDimension()->setAutoSize($fontSize);
$sheet->getStyle($headerStr)->getFont()->setBold(false)->setSize($fontSize+2);
$sheet->getDefaultColumnDimension()->setWidth($defaultWidth);
$sheet->fromArray($header, null, 'A1');
$sheet->getStyle($headerStr)->applyFromArray($defaultStyle);
$sheet->getStyle($bodyStr)->applyFromArray(empty($excelStyle) ? $defaultStyle : $excelStyle);
// 自定义列宽
if(!empty($cellWidthList)) {
foreach ($cellWidthList as $cellId => $widthVal) {
if(isset($cellIds[$cellId]) && is_numeric($widthVal) && $widthVal > 0) {
$sheet->getColumnDimension($cellIds[$cellId])->setWidth($widthVal);
}
}
}
//自定义列是否换行
if(!empty($cellWrapList)) {
foreach ($cellWrapList as $cellId => $boolVal) {
if(isset($cellIds[$cellId])) {
$wrap = $boolVal ? true : false;
$sheet->getStyle($cellIds[$cellId])->getAlignment()->setWrapText($wrap);
}
}
}
return true;
} catch (\Exception $e) {
return false;
}
}
// excel导入时间转换
public static function getExcelTime($timeStr, $format = 'Y-m-d')
{
$timezone = ini_get('date.timezone');
$timeStr = trim($timeStr);
if (!empty($timeStr)) {
if (is_numeric($timeStr)) {
$toTimestamp = EDate::excelToTimestamp($timeStr, $timezone);
$timeStr = date($format, $toTimestamp);
} else {
$toTimestamp = strtotime($timeStr);
$timeStr = ($toTimestamp === false) ? '' : date($format, $toTimestamp);
}
} else {
$timeStr = '';
}
return $timeStr;
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace app\service;
use think\facade\Config as CConfig;
/**
* 扩展配置项工具类
* Class ExtraConfig
* @package app\service
*/
class ExtraConfig
{
private static string $extraDir = 'extra/';
/**
* 比率设置
* @return array|mixed
*/
public static function ratio()
{
CConfig::load(self::$extraDir.'ratio', 'ratio');
return config('ratio') ?? [];
}
/**
* 微信相关设置
* @return array|mixed
*/
public static function wechat()
{
CConfig::load(self::$extraDir.'wechat', 'wechat');
return config('wechat') ?? [];
}
/**
* 小程序个性装修配置
* @return array|mixed
*/
public static function miniProgram()
{
CConfig::load('extra/mini_program', 'mini_program');
return config('mini_program') ?? [];
}
/**
* 基础配置
*/
public static function base()
{
CConfig::load('extra/base', 'base');
return config('base') ?? [];
}
/**
* 阿里OSS配置
*/
public static function aliOss()
{
CConfig::load('extra/alioss', 'alioss');
return config('alioss') ?? [];
}
}

65
app/service/File.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace app\service;
use think\file\UploadedFile;
class File
{
//上传文件移动到上传文件夹
public static function move(UploadedFile $file)
{
$upload_path = 'storage/uploads/' . date('Ymd');
$path = app()->getRootPath() . $upload_path;
$filename = uniqid() . '.' . $file->extension();
$upload_filename = '/' . $upload_path . '/' . $filename;
return [$file->move($path, $filename), $file, $upload_filename];
}
/**
* 文件访问路径转换为完整的url
* @param string|null $fileUrl
* @param bool $ossAnalysis 是否进行OSS解析
* @return string
* @todo 若启用OOS存储需根据业务配置调整$fileDomain
*
*/
public static function convertCompleteFileUrl(?string $fileUrl, bool $ossAnalysis=true): string
{
if (empty($fileUrl)) {
return '';
}
if ($ossAnalysis) {
$fileDomain = self::getFileDomain();
} else {
$fileDomain = request()->domain();
}
$prefix = substr($fileUrl, 0, 4);
if (!($prefix == 'http')) {
$fileUrl = $fileDomain.'/'.ltrim($fileUrl, '/');
}
return $fileUrl;
}
/**
* 文件访问域名前缀
*
* @return string
*/
public static function getFileDomain(): string
{
$confBase = ExtraConfig::base();
$confOss = ExtraConfig::aliOss();
$isOss = $confBase['oss'] ?? 'false';
$ossDomain = $confOss['customDomain'] ?? '';
// 默认为当前域名
$fileDomain = request()->domain();
if ($isOss == 'true' && !empty($ossDomain)) {
$fileDomain = $ossDomain;
}
$fileDomain = trim($fileDomain);
return rtrim($fileDomain, '/');
}
}

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