中秋节快乐

This commit is contained in:
Alone
2024-09-14 17:00:49 +08:00
parent 610dee88cd
commit dff1b038b1
4286 changed files with 807503 additions and 6 deletions
+19
View File
@@ -0,0 +1,19 @@
APP_DEBUG = false
SYSTEM_SALT= YAdmin
[APP]
DEFAULT_TIMEZONE = Asia/Chongqing
[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = www_dj_com
USERNAME = 123456
PASSWORD = 123456
HOSTPORT = 3306
CHARSET = utf8mb4
DEBUG = false
PREFIX = qf_
[LANG]
default_lang = zh-cn
+2
View File
@@ -0,0 +1,2 @@
/.svn
/.vscode
+1
View File
@@ -0,0 +1 @@
+7
View File
@@ -0,0 +1,7 @@
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
+16 -6
View File
@@ -1,18 +1,28 @@
## 心悦搜
## 心悦搜
免费分享百万级网盘资源,致力打造顶尖网盘搜索引擎,让您畅享资源无忧!
## 更新日志
### v2
- UI改版:不再使用uniapp
- 优化Seo:增加后台配置seo参数、伪静态网址、网站地图等
- 自定义首页背景图、背景色等样式
- 优化搜索模式:支持精准搜索、模糊搜索、分词搜索
- 增加转存过滤删除广告的功能
- 增加批量导入转存功能
- 支持多网盘导入功能(目前仅夸克支持转存分享)
- 增加资源分类功能
注:鉴于数据库改动大,最快升级方式:1、重新搭建新项目;2、旧项目后台导出资源表格;3、新项目导入这个表格
## 演示
[前端体验](https://pan.xinyuedh.com)
<https://pan.xinyuedh.com>
[前端项目地址](https://ext.dcloud.net.cn/plugin?id=17278)
<https://ext.dcloud.net.cn/plugin?id=17278>
注:鉴于太多人不会uniapp,程序安装后默认已打包好uniapp,可正常使用;如需修改前端页面可自行查看以上地址。
## 后台安装教程
+22
View File
@@ -0,0 +1,22 @@
<?php
declare (strict_types = 1);
namespace app;
use think\Service;
/**
* 应用服务类
*/
class AppService extends Service
{
public function register()
{
// 服务注册
}
public function boot()
{
// 服务启动
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 添加自定义异常处理机制
// 其他错误交给系统处理
return parent::render($request, $e);
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace app;
// 应用请求对象类
class Request extends \think\Request
{
}
+697
View File
@@ -0,0 +1,697 @@
<?php
declare(strict_types=1);
namespace app\admin;
use think\App;
use think\facade\View;
use app\model\Admin as AdminModel;
use app\model\Access as AccessModel;
use app\model\Auth as AuthModel;
use app\model\Node as NodeModel;
use app\model\Group as GroupModel;
use app\model\Conf as ConfModel;
/**
* 控制器基础类
*/
abstract class QfShop
{
protected $model = null;
//搜索字段
protected $selectList = '*';
protected $selectDetail = '*';
//筛选字段
protected $searchFilter = [];
//更新字段
protected $updateFields = [];
//更新时的必须字段
protected $updateRequire = [];
//添加字段
protected $insertFields = [];
//添加时的必须字段
protected $insertRequire = [];
//excel查询字段 用来查询
protected $excelField = [
"join_id" => "编号",
];
//excel 表头
protected $excelTitle = "数据导出表";
//EXCEL 单元格字母
protected $excelCells = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA', 'AB', 'AC', 'AD'];
//主键key
protected $pk = '';
//表名称
protected $table = '';
//主键value
protected $pk_value = 0;
//模型
protected $adminModel;
protected $accessModel;
protected $authModel;
protected $nodeModel;
protected $groupModel;
protected $confModel;
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
protected $plat = 'all';
protected $version = 0;
protected $module;
protected $controller;
protected $action;
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
//TODO !!!如有特殊需求请重写下面的方法到子类,请勿修改此处!!! BEGIN.........//
/**
* 添加接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function add()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//校验Insert字段是否填写
$error = $this->validateInsertFields();
if ($error) {
return $error;
}
//从请求中获取Insert数据
$data = $this->getInsertDataFromRequest();
//添加这行数据
$this->insertRow($data);
return jok('添加成功');
}
/**
* 修改接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function update()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "参数必须填写", 400);
}
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//校验Update字段是否填写
$error = $this->validateUpdateFields();
if ($error) {
return $error;
}
//从请求中获取Update数据
$data = $this->getUpdateDataFromRequest();
//根据主键更新这条数据
$this->updateByPk($data);
return jok('修改成功');
}
/**
* 禁用接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function disable()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "参数必须填写", 400);
}
if (isInteger($this->pk_value)) {
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//单个操作
$this->disableBySingle();
} else {
//批量操作
$this->disableByMultiple();
}
return jok("禁用成功");
}
/**
* 启用接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function enable()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "参数必须填写", 400);
}
if (isInteger($this->pk_value)) {
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//单个操作
$this->enableBySingle();
} else {
//批量操作
$this->enableByMultiple();
}
return jok("启用成功");
}
/**
* 删除接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function delete()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (isInteger($this->pk_value)) {
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//单个操作
$this->deleteBySingle();
} else {
//批量操作
$this->deleteByMultiple();
}
return jok('删除成功');
}
/**
* 获取列表接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function getList()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//从请求中获取筛选数据的数组
$map = $this->getDataFilterFromRequest();
//从请求中获取排序方式
$order = $this->getorderfromRequest();
//设置Model中的 per_page
$this->setGetListPerPage();
//查询数据
$dataList = $this->model->getListByPage($map, $order, $this->selectList);
return jok('数据获取成功', $dataList);
}
/**
* 获取详情基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function detail()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("没有查询到数据", 404);
}
return jok('数据加载成功', $item);
}
/**
* 导出Excel基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function excel()
{
$error = $this->access();
if ($error) {
return $error;
}
$this->exportExcelData();
}
// !!!如有特殊需求请重写下面的方法到子类,请勿修改此处!!! END.........//
// 初始化
protected function initialize()
{
$this->module = "api";
$this->controller = $this->request->controller() ? $this->request->controller() : "Index";
$this->action = strtolower($this->request->action()) ? strtolower($this->request->action()) : "index";
View::assign('controller', strtolower($this->controller));
View::assign('action', strtolower($this->action));
$this->table = strtolower($this->controller);
$this->pk = $this->table . "_id";
$this->pk_value = input($this->pk);
$this->adminModel = new AdminModel();
$this->accessModel = new AccessModel();
$this->authModel = new AuthModel();
$this->nodeModel = new NodeModel();
$this->groupModel = new GroupModel();
$this->confModel = new ConfModel();
$configs = $this->confModel->select()->toArray();
$c = [];
foreach ($configs as $config) {
$c[$config['conf_key']] = $config['conf_value'];
}
config($c, 'qfshop');
}
/**
* 检测授权
*
* @return void
*/
protected function access()
{
if (!input("plat")) {
return jerr("plat参数为必须", 400);
}
$this->plat = input('plat');
if (!input("version")) {
return jerr("version参数为必须", 400);
}
$this->version = input('version');
if (!input("access_token")) {
return jerr("AccessToken为必要参数", 400);
}
$access_token = input("access_token");
$this->admin = $this->adminModel->getAdminByAccessToken($access_token);
if (!$this->admin) {
return jerr("登录过期,请重新登录", 401);
}
if ($this->admin['admin_status'] == 1) {
return jerr("你的账户被禁用,登录失败", 401);
}
}
/**
* 从请求中获取Request数据
*
* @return void
*/
protected function getInsertDataFromRequest()
{
$data = [];
foreach (input('post.') as $k => $v) {
if (in_array($k, $this->insertFields)) {
$data[$k] = $v;
}
}
return $data;
}
/**
* 校验Insert的字段
*
* @return void
*/
protected function validateInsertFields()
{
foreach ($this->insertRequire as $k => $v) {
if (!input($k)) {
return jerr($v, 400);
}
}
return null;
}
/**
* 从请求中获取Update数据
*
* @return void
*/
protected function getUpdateDataFromRequest()
{
$data = [];
foreach (input('post.') as $k => $v) {
if (in_array($k, $this->updateFields)) {
$data[$k] = $v;
}
}
return $data;
}
/**
* 校验Update的字段
*
* @return void
*/
protected function validateUpdateFields()
{
foreach ($this->updateRequire as $k => $v) {
if (!input($k)) {
return jerr($v, 400);
}
}
return null;
}
/**
* 按主键集合批量禁用 1,2,3,4
*
* @return void
*/
protected function disableByMultiple()
{
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->update([
$this->table . "_status" => 1,
$this->table . "_updatetime" => time(),
]);
}
/**
* 单个禁用 可传入自定义$map
* 默认按主键ID禁用
*
* @param array $map
* @return void
*/
protected function disableBySingle($map = null)
{
if ($map == null) {
$map = [$this->pk => $this->pk_value];
}
$this->model->where($map)->update([
$this->table . "_status" => 1,
$this->table . "_updatetime" => time(),
]);
}
/**
* 按主键集合批量启用 1,2,3,4
*
* @return void
*/
protected function enableByMultiple()
{
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->update([
$this->table . "_status" => 0,
$this->table . "_updatetime" => time(),
]);
}
/**
* 单个启用 可传入自定义$map
* 默认按主键ID启用
*
* @param array $map
* @return void
*/
protected function enableBySingle($map = null)
{
if ($map == null) {
$map = [$this->pk => $this->pk_value];
}
$this->model->where($map)->update([
$this->table . "_status" => 0,
$this->table . "_updatetime" => time(),
]);
}
/**
* 按主键集合批量删除1,2,3,4
*
* @return void
*/
protected function deleteByMultiple()
{
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->delete();
}
/**
* 单个删除 默认主键ID
*
* @param array $map
* @return void
*/
protected function deleteBySingle($map = null)
{
if ($map == null) {
$map = [$this->pk => $this->pk_value];
}
$this->model->where($map)->delete();
}
/**
* 根据主键ID获取一行数据
*
* @param int|null 主键ID
* @return array|null
*/
protected function getRowByPk($pk_value = null)
{
if (!$pk_value) {
$pk_value = $this->pk_value;
}
$item = $this->model->where($this->pk, $pk_value)->field($this->selectDetail)->find();
return $item ? $item->toArray() : null;
}
/**
* 根据主键ID更新数据
*
* @param array 需要更新的KV数组
* @param int|null 主键ID 默认$this->pk_value
* @param bool 是否更新_updatetime字段 默认TRUE
* @return void
*/
protected function updateByPk($data, $pk_value = null, $auto_updatetime = true)
{
if (!$pk_value) {
$pk_value = $this->pk_value;
}
if ($auto_updatetime) {
$data[$this->table . "_updatetime"] = time();
}
$this->model->where($this->pk, $this->pk_value)->update($data);
}
/**
* 添加一行数据
*
* @param array 需要添加的KV数组
* @param bool 是否自动记录_createtime和_updatetime字段 默认true
* @return int 添加返回的主键ID
*/
protected function insertRow($data, $auto_inserttime = true)
{
if ($auto_inserttime) {
$data[$this->table . "_updatetime"] = time();
$data[$this->table . "_createtime"] = time();
} else {
$data[$this->table . "_updatetime"] = 0;
$data[$this->table . "_createtime"] = 0;
}
$id = $this->model->insertGetId($data);
return $id;
}
/**
* 从请求中获取查询排序(默认主键DESC)
*
* @return void
*/
protected function getOrderFromRequest()
{
if (input('order')) {
$order = urldecode(input('order'));
} else {
$order = strtolower($this->controller) . "_id desc";
}
return $order;
}
/**
* 设置分页查询每页数量
*
* @param int|null 每页数量
* @return void
*/
protected function setGetListPerPage($per_page = null)
{
if ($per_page) {
$this->model->per_page = intval($per_page);
} else if (input('per_page')) {
$this->model->per_page = input('per_page');
} else {
$this->model->per_page = 10;
}
}
/**
* 获取查询列表的Where参数
*
* @return array
*/
protected function getDataFilterFromRequest()
{
$map = [];
$filter = input('post.');
foreach ($filter as $k => $v) {
if ($k == 'filter') {
$k = input('filter');
$v = input('keyword');
}
if ($v === '' || $v === null) {
continue;
}
if (array_key_exists($k, $this->searchFilter)) {
switch ($this->searchFilter[$k]) {
case "like":
array_push($map, [$k, 'like', "%" . $v . "%"]);
break;
case "=":
array_push($map, [$k, '=', $v]);
break;
default:
}
}
}
return $map;
}
protected function getExcelFields()
{
$excelField = [];
foreach ($this->excelField as $k => $v) {
if ($k == "*") {
continue;
} else {
array_push($excelField, [
$k, $v
]);
}
}
return $excelField;
}
/**
* 导出Excel
*
* @return string 下载文件名
*/
protected function exportExcelData($data)
{
$datalist = $data ? $data->toArray() : [];
$excelField = $this->getExcelFields();
$PHPExcel = new \PHPExcel(); //实例化
$PHPExcel
->getProperties() //获得文件属性对象,给下文提供设置资源
->setCreator("qfshop") //设置文件的创建者
->setLastModifiedBy("qfshop") //设置最后修改者
->setDescription("Export by qfshop"); //设置备注
$PHPSheet = $PHPExcel->getActiveSheet();
$PHPSheet->setTitle($this->excelTitle); //给当前活动sheet设置名称
$PHPSheet->mergeCells('A1:' . $this->excelCells[count($excelField) - 1] . "1");
$PHPSheet->setCellValue('A1', $this->excelTitle);
$PHPSheet->getRowDimension(1)->setRowHeight(40);
$PHPSheet->getStyle('A1')->getFont()->setSize(16)->setBold(true); //字体大小
$PHPSheet->getStyle('A1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER); //水平方向上对齐
$PHPSheet->getStyle('A1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER); //垂直方向上中间居中
$PHPSheet->getStyle('A1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER); //垂直方向上中间居中
if (count($excelField) > count($this->excelCells)) {
echo 'Error and you need check Excel Cells Keys...';
die;
}
$PHPSheet->getRowDimension(2)->setRowHeight(30);
for ($column = 0; $column < count($excelField); $column++) {
$PHPSheet->setCellValue($this->excelCells[$column] . "2", $excelField[$column][1]);
$PHPSheet->getStyle($this->excelCells[$column])->getNumberFormat()
->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);
for ($line = 0; $line < count($datalist); $line++) {
$string = $datalist[$line][$excelField[$column][0]];
$PHPSheet->getColumnDimension($this->excelCells[$column])->setWidth(20);
$PHPSheet->setCellValueExplicit($this->excelCells[$column] . ($line + 3), $string, \PHPExcel_Cell_DataType::TYPE_STRING);
}
}
//***********************画出单元格边框*****************************
$styleArray = array(
'borders' => array(
'inside' => array(
'style' => \PHPExcel_Style_Border::BORDER_THIN, //细边框
//'color' => array('argb' => 'FFFF0000'),
),
'outline' => array(
'style' => \PHPExcel_Style_Border::BORDER_THICK, //边框是粗的
//'color' => array('argb' => 'FFFF0000'),
),
),
);
$PHPSheet->getStyle('A2:' . $this->excelCells[count($excelField) - 1] . (count(
$datalist
) + 2))->applyFromArray($styleArray);
//***********************画出单元格边框结束*****************************
//设置全部居中对齐
$PHPSheet->getStyle('A1:' . $this->excelCells[count($excelField) - 1] . (count(
$datalist
) + 2))->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER)->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER)->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
//设置全部字体
$PHPSheet->getStyle('A1:' . $this->excelCells[count($excelField) - 1] . (count(
$datalist
) + 2))->getFont()->setName('微软雅黑');
$PHPWriter = \PHPExcel_IOFactory::createWriter($PHPExcel, "Excel2007"); //创建生成的格式
header('Content-Disposition: attachment;filename="' . $this->excelTitle . "_" . date('Y-m-d_H:i:s') . '.xlsx"'); //下载下来的表格名
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$PHPWriter->save("php://output"); //表示在$path路径下面生成demo.xlsx文件
exit;
return $this->excelTitle . "_" . date('Y-m-d_H:i:s') . '.xlsx"';
}
public function __call($method, $args)
{
return jerr("访问异常", 404);
}
}
+480
View File
@@ -0,0 +1,480 @@
<?php
namespace app\admin\controller;
use think\App;
use app\admin\QfShop;
use app\model\Admin as model;
use app\model\Sms as SmsModel;
use app\model\Validate as ValidateModel;
class Admin extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//查询字段
$this->selectList = "*";
$this->selectDetail = "*";
//筛选字段
$this->searchFilter = [
"admin_id" => "=",
"admin_account" => "like",
"admin_name" => "like",
"admin_truename" => "like",
"admin_status" => "=",
];
$this->insertFields = [
"admin_account", "admin_password", "admin_name", "admin_idcard", "admin_email", "admin_group", "admin_truename"
];
$this->updateFields = [
"admin_account", "admin_password", "admin_name", "admin_idcard", "admin_email", "admin_group", "admin_truename"
];
$this->insertRequire = [
'admin_name' => "用户昵称必须填写",
'admin_account' => "用户帐号必须填写",
'admin_password' => "密码必须填写",
'admin_group' => "用户组必须填写",
];
$this->updateRequire = [
'admin_name' => "用户昵称必须填写",
'admin_account' => "用户帐号必须填写",
'admin_group' => "用户组必须填写",
];
$this->excelField = [
"id" => "编号",
"account" => "帐号",
"name" => "昵称",
"idcard" => "身份证",
"email" => "邮箱",
"createtime" => "创建时间",
"updatetime" => "修改时间"
];
$this->model = new model();
}
public function add()
{
$error = $this->access();
if ($error) {
return $error;
}
$error = $this->validateInsertFields();
if ($error) {
return $error;
}
$data = $this->getInsertDataFromRequest();
$data['admin_ipreg'] = "127.0.0.1";
$admin = $this->model->getAdminByAccount($data["admin_account"]);
if ($admin) {
return jerr("帐号已存在,请重新输入");
}
$salt = getRandString(4);
$password = $data["admin_password"];
$password = encodePassword($password, $salt);
$data["admin_salt"] = $salt;
$data["admin_password"] = $password;
$this->insertRow($data);
return jok('用户添加成功');
}
public function update()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (!isInteger($this->pk_value)) {
return jerr("修改失败,参数错误", 400);
}
$item = $this->model->where($this->pk, $this->pk_value)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
if (intval($this->pk_value) == 1) {
return jerr("无法修改超管用户信息");
}
foreach ($this->updateRequire as $k => $v) {
if (!input($k)) {
return jerr($v);
}
}
$data = [];
foreach (input('post.') as $k => $v) {
if (in_array($k, $this->updateFields)) {
$data[$k] = $v;
}
}
$admin = $this->model->getAdminByAccount($data["admin_account"]);
if ($admin && $admin[$this->pk] != $item[$this->pk]) {
return jerr("帐号已存在,请重新输入");
}
if (input('new_password')) {
//设置密码
$salt = getRandString(4);
$password = input('new_password');
$password = encodePassword($password, $salt);
$data["admin_salt"] = $salt;
$data["admin_password"] = $password;
}
if ($this->admin['admin_group'] != 1) {
//除超级管理员组外 其他任何组不允许修改用户组
unset($data['admin_group']);
}
$data[$this->table . "_updatetime"] = time();
$this->model->where($this->pk, $this->pk_value)->update($data);
return jok('用户信息更新成功');
}
/**
* 禁用用户
*
* @return void
*/
public function disable()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "参数必须填写", 400);
}
if (isInteger($this->pk_value)) {
$map = [$this->pk => $this->pk_value];
$item = $this->model->where($map)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
if ($item["admin_group"] == 1) {
return jerr("超级管理员不允许操作!");
}
$this->model->where($map)->update([
$this->table . "_status" => 1,
$this->table . "_updatetime" => time(),
]);
} else {
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->where("admin_group > 1")->update([
$this->table . "_status" => 1,
$this->table . "_updatetime" => time(),
]);
}
return jok("禁用用户成功");
}
/**
* 启用用户
*
* @return void
*/
public function enable()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "参数必须填写", 400);
}
if (isInteger($this->pk_value)) {
$map = [$this->pk => $this->pk_value];
$item = $this->model->where($map)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
if ($item["admin_group"] == 1) {
return jerr("超级管理员不允许操作!");
}
$this->model->where($map)->update([
$this->table . "_status" => 0,
$this->table . "_updatetime" => time(),
]);
} else {
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->where("admin_group > 1")->update([
$this->table . "_status" => 0,
$this->table . "_updatetime" => time(),
]);
}
return jok("启用用户成功");
}
/**
* 删除用户
*
* @return void
*/
public function delete()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (isInteger($this->pk_value)) {
$map = [$this->pk => $this->pk_value];
$item = $this->model->where($map)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//
if ($item["admin_group"] == 1) {
return jerr("超级管理员不允许操作!");
}
$this->model->where($map)->delete();
} else {
$list = explode(',', $this->pk_value);
//批量删除只允许删除用户组不为1的用户
$this->model->where($this->pk, 'in', $list)->where("admin_group > 1")->delete();
}
return jok('删除用户成功');
}
public function detail()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
$item = $this->model->field($this->selectDetail)->where($this->pk, $this->pk_value)->find();
if (empty($item)) {
return jerr("没有查询到数据", 404);
}
return jok('数据加载成功', $item);
}
public function getList()
{
$error = $this->access();
if ($error) {
return $error;
}
$map = [];
$filter = input('post.');
foreach ($filter as $k => $v) {
if ($k == 'filter') {
$k = input('filter');
$v = input('keyword');
}
if ($v === '' || $v === null) {
continue;
}
if (array_key_exists($k, $this->searchFilter)) {
switch ($this->searchFilter[$k]) {
case "like":
array_push($map, [$k, 'like', "%" . $v . "%"]);
break;
case "=":
array_push($map, [$k, '=', $v]);
break;
default:
}
}
}
$order = strtolower($this->controller) . "_id desc";
if (input('order')) {
$order = urldecode(input('order'));
}
if (input('per_page')) {
$this->model->per_page = intval(input('per_page'));
}
$dataList = $this->model->getListByPage($map, $order, $this->selectList);
return jok('用户列表获取成功', $dataList);
}
public function login()
{
if (!input("admin_account")) {
return jerr('请确认帐号是否正确填写', 400);
}
if (!input("admin_password")) {
return jerr('请确认密码是否正确填写', 400);
}
if (!input("admin_code")) {
return jerr('请确认图形验证码是否填写', 400);
}
$plat = input("plat");
$admin_account = input("admin_account");
$admin_password = input("admin_password");
//验证图形验证码
$validateModel = new ValidateModel();
$error = $validateModel->validateImgCode(input('token'), input('admin_code'));
if ($error) {
return jerr('验证码错误', 400);
}
//登录获取用户信息
$admin = $this->model->login($admin_account, $admin_password);
if ($admin) {
//创建一个新的授权
$access = $this->accessModel->createAccess($admin['admin_id'], $plat);
if ($access) {
setCookie('access_token', $access['access_token'], time() + 3600, '/');
return jok('登录成功', ['access_token' => $access['access_token']]);
} else {
return jerr('登录系统异常');
}
} else {
return jerr('帐号或密码错误');
}
}
/**
* 退出登录
*
* @return void
*/
public function logout()
{
$access_token = input("access_token");
cookie('access_token', null);
$this->accessModel->where('access_token', $access_token)->update(["access_status" => 1]);
return jok('已退出登录');
}
/**
* 用户注册接口
*
* @return void
*/
public function reg()
{
if (!input("phone")) {
return jerr("手机号不能为空!", 400);
}
$phone = input("phone");
if (!input("code")) {
return jerr("短信验证码不能为空!", 400);
}
$code = input("code");
if (!input("password")) {
return jerr("密码不能为空!", 400);
}
$password = input("password");
$name = $phone;
if (input("name")) {
$name = input("name");
}
$smsModel = new SmsModel();
if ($smsModel->validSmsCode($phone, $code)) {
$admin = $this->model->where([
"admin_account" => $phone
])->find();
if ($admin) {
return jerr("该手机号已经注册!");
}
$result = $this->model->reg($phone, $password, $name);
if ($result) {
return jok("用户注册成功");
} else {
return jerr("注册失败,请重试!");
}
} else {
return jerr("短信验证码已过期,请重新获取");
}
}
public function motifyPassword()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!input("oldPassword")) {
return jerr("你必须要输入你的原密码!", 400);
}
if (!input("newPassword")) {
return jerr("你必须输入一个新的密码!", 400);
}
$old_password = input("oldPassword");
$new_password = input("newPassword");
if (strlen($new_password) < 6 || strlen($new_password) > 16) {
return jerr("新密码因为6-16位!");
}
if ($this->admin['admin_password'] != encodePassword($old_password, $this->admin['admin_salt'])) {
return jerr("原密码输入不正确,请重试!");
}
$result = $this->model->motifyPassword($this->admin['admin_id'], $new_password);
if ($result) {
return jok("密码已重置,请使用新密码登录");
} else {
return jerr("注册失败,请重试!");
}
}
/**
* 重置密码
*
* @return void
*/
public function resetPassword()
{
if (!input("phone")) {
return jerr("手机号不能为空!", 400);
}
if (!input("code")) {
return jerr("短信验证码不能为空!", 400);
}
if (!input("password")) {
return jerr("密码不能为空!", 400);
}
$phone = input("phone");
$code = input("code");
$password = input("password");
$smsModel = new SmsModel();
if ($smsModel->validSmsCode($phone, $code)) {
$admin = $this->model->where([
"admin_account" => $phone
])->find();
if (!$admin) {
return jerr("该手机号尚未注册!", 404);
}
$result = $this->model->motifyPassword($admin['admin_id'], $password);
if ($result) {
return jok("密码已重置,请使用新密码登录");
} else {
return jerr("注册失败,请重试!");
}
} else {
return jerr("短信验证码已过期,请重新获取");
}
}
/**
* 获取我的信息
*
* @return void
*/
public function getMyInfo()
{
$error = $this->access();
if ($error) {
return $error;
}
$myInfo = $this->admin;
foreach (['admin_password', 'admin_salt', 'admin_accesstoken', 'admin_tokentime', 'admin_status'] as $key) {
unset($myInfo[$key]);
}
return jok('数据获取成功', $myInfo);
}
public function updateMyInfo()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!input("admin_name")) {
return jerr("你确定飘到连名字都可以不要了吗?", 400);
}
$data = [
"admin_name" => input("admin_name"),
"admin_truename" => input("admin_truename"),
"admin_email" => input("admin_email"),
"admin_idcard" => input("admin_idcard"),
];
$this->model->where("admin_id", $this->admin['admin_id'])->update($data);
return jok("资料更新成功");
}
}
+221
View File
@@ -0,0 +1,221 @@
<?php
namespace app\admin\controller;
use think\App;
use think\facade\Filesystem;
use think\exception\ValidateException;
use app\admin\QfShop;
use app\model\Attach as AttachModel;
class Attach extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//筛选字段
$this->searchFilter = [
"attach_id" => "=", //相同筛选
"attach_key" => "like", //相似筛选
"attach_value" => "like", //相似筛选
"attach_desc" => "like", //相似筛选
"attach_readonly" => "=", //相似筛选
];
$this->model = new AttachModel();
}
/**
* 上传图片
*
* @return void
*/
public function uploadImage()
{
$error = $this->access();
if ($error) {
return $error;
}
try {
$file = request()->file('file');
try {
validate(['file' => 'filesize:' . config("qfshop.upload_max_image") . '|fileExt:' . config("qfshop.upload_image_type")])
->check(['file' => $file]);
$saveName = Filesystem::putFile('image', $file);
$attach_data = array(
'attach_path' => "/uploads/".$saveName,
'attach_name' => $file->getOriginalName(),
'attach_type' => $file->extension(),
'attach_size' => $file->getSize(),
'attach_admin' => $this->admin['admin_id']
);
$attach_id = $this->insertRow($attach_data);
$attach_data = $this->getRowByPk($attach_id);
if (input("?extend")) {
$attach_data['extend'] = input("extend");
}
return jok('上传成功!', $attach_data);
} catch (ValidateException $e) {
return jerr($e->getMessage());
}
} catch (\Exception $error) {
return jerr('上传文件失败,请检查你的文件!');
}
}
/**
* 删除图片
*
* @return void
*/
public function delete()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (isInteger($this->pk_value)) {
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//单个操作
$map = [$this->pk => $this->pk_value];
$res = $this->model->where($map)->delete();
if($res){
try {
unlink("./uploads/".$item['attach_path']);
} catch (\Throwable $th) {
//throw $th;
}
}
} else {
//批量操作
$list = explode(',', $this->pk_value);
foreach ($list as $key => $value) {
$item = $this->model->where("attach_id",$value)->find();
if($item){
try {
unlink("./uploads/".$item['attach_path']);
} catch (\Throwable $th) {
//throw $th;
}
}
}
$this->model->where($this->pk, 'in', $list)->delete();
}
return jok('删除成功');
}
/**
* 上传文件
*
* @return void
*/
public function uploadFile()
{
$error = $this->access();
if ($error) {
return $error;
}
try {
$file = request()->file('file');
try {
validate(['file' => 'filesize:' . config("qfshop.upload_max_file") . '|fileExt:' . config("qfshop.upload_file_type")])
->check(['file' => $file]);
$saveName = Filesystem::putFile('normal', $file);
$attach_data = array(
'attach_path' => $saveName,
'attach_type' => $file->extension(),
'attach_size' => $file->getSize(),
'attach_admin' => $this->admin['admin_id']
);
$attach_id = $this->insertRow($attach_data);
$attach_data = $this->getRowByPk($attach_id);
if (input("?extend")) {
$attach_data['extend'] = input("extend");
}
return jok('上传成功!', $attach_data);
} catch (ValidateException $e) {
return jerr($e);
}
} catch (\Exception $error) {
return jerr('上传文件失败,请检查你的文件!');
}
}
/**
* 富文本上传图片
*
* @return void
*/
public function uploads()
{
header("Content-Type: text/html; charset=utf-8");
$error = $this->access();
if ($error) {
return $error;
}
$CONFIG = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents("./static/admin/UEditor/config.json")), true);
$action = $_GET['action'];
switch ($action) {
case 'config':
$result = json_encode($CONFIG);
break;
/* 上传图片 */
case 'uploadimage':
/* 上传涂鸦 */
case 'uploadscrawl':
/* 上传视频 */
case 'uploadvideo':
/* 上传文件 */
case 'uploadfile':
try {
$file = request()->file('upfile');
try {
validate(['file' => 'filesize:' . config("qfshop.upload_max_image") . '|fileExt:' . config("qfshop.upload_image_type")])
->check(['file' => $file]);
$saveName = Filesystem::putFile('normal', $file);
$result = json_encode(array(
'original'=> $file->getOriginalName(),
'state'=> "SUCCESS",
'title'=> $file->getOriginalName(),
'url'=> "/uploads/".$saveName,
'type'=> $file->extension(),
));
} catch (ValidateException $e) {
$result = json_encode(array(
'state'=> $e->getMessage()
));
}
} catch (\Exception $error) {
$result = json_encode(array(
'state'=> '上传文件失败,请检查你的文件!'
));
}
break;
default:
$result = json_encode(array(
'state'=> '请求地址出错'
));
break;
}
/* 输出结果 */
if (isset($_GET["callback"])) {
if (preg_match("/^[\w_]+$/", $_GET["callback"])) {
echo htmlspecialchars($_GET["callback"]) . '(' . $result . ')';
} else {
echo json_encode(array(
'state'=> 'callback参数不合法'
));
}
} else {
echo $result;
}
die;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace app\admin\controller;
use think\App;
use app\admin\QfShop;
use app\model\Auth as AuthModel;
class Auth extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//筛选字段
$this->searchFilter = [
"auth_id" => "=", //相同筛选
];
$this->model = new AuthModel();
}
/**
* 清除访问日志
*
* @return void
*/
public function clean()
{
$error = $this->access();
if ($error) {
return $error;
}
$this->model->cleanAuth();
return jok('授权信息清理成功');
}
}
+205
View File
@@ -0,0 +1,205 @@
<?php
namespace app\admin\controller;
use think\App;
use app\admin\QfShop;
use app\model\Conf as ConfModel;
class Conf extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//筛选字段
$this->searchFilter = [
"conf_id" => "=", //相同筛选
"conf_key" => "like", //相似筛选
"conf_value" => "like", //相似筛选
"conf_title" => "like", //相似筛选
"conf_status" => "=", //相同筛选
"conf_type" => "=", //相同筛选
];
$this->insertFields = [
"conf_key", "conf_value", "conf_title", "conf_desc", "conf_status", "conf_type", "conf_spec", "conf_content", "conf_sort", "conf_system"
];
$this->updateFields = [
"conf_key", "conf_value", "conf_title", "conf_desc", "conf_status", "conf_type", "conf_spec", "conf_content", "conf_sort", "conf_system"
];
$this->insertRequire = [
'conf_title' => "参数名称必须填写",
'conf_key' => "参数字段必须填写",
];
$this->updateRequire = [
'conf_title' => "参数名称必须填写",
'conf_key' => "参数字段必须填写",
];
$this->model = new ConfModel();
}
/**
* 获取列表接口基类
*
* @return void
*/
public function getList()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//从请求中获取筛选数据的数组
$map = $this->getDataFilterFromRequest();
//从请求中获取排序方式
$order = "conf_sort desc, conf_id asc";
//设置Model中的 per_page
$this->setGetListPerPage();
//查询数据
$dataList = $this->model->getListByPage($map, $order, $this->selectList);
return jok('数据获取成功', $dataList);
}
/**
* 读取基本配置
*
* @return void
*/
public function getBaseConfig()
{
$error = $this->access();
if ($error) {
return $error;
}
$datalist = $this->model->where('conf_status', 1)->order("conf_sort desc ".$this->pk . " asc")->select();
foreach ($datalist as $key => $value) {
if($value['conf_content']){
$value['conf_content'] = explode("\n",$value['conf_content']);
}
}
return jok('', $datalist);
}
/**
* 更新基础配置
*
* @return void
*/
public function updateBaseConfig()
{
$error = $this->access();
if ($error) {
return $error;
}
foreach (input("post.") as $k => $v) {
$map["conf_key"] = $k;
$item = $this->model->where($map)->find();
if (empty($item)) {
continue;
}
if(is_array($v)){
$v = implode(",",$v);
}
$this->model->where("conf_key", $k)->update(["conf_value" => $v]);
}
return jok("配置修改成功");
}
/**
* 添加接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function add()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//校验Insert字段是否填写
$error = $this->validateInsertFields();
if ($error) {
return $error;
}
//从请求中获取Insert数据
$data = $this->getInsertDataFromRequest();
$res = $this->model->where('conf_key',$data['conf_key'])->find();
if ($res) {
return jerr("参数字段已存在");
}
//添加这行数据
$data['conf_value'] = '';
$this->insertRow($data);
return jok('添加成功');
}
/**
* 修改接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function update()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "参数必须填写", 400);
}
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//校验Update字段是否填写
$error = $this->validateUpdateFields();
if ($error) {
return $error;
}
//从请求中获取Update数据
$data = $this->getUpdateDataFromRequest();
$res = $this->model->where('conf_key',$data['conf_key'])->find();
if ($res['conf_id']!= input("conf_id") && $res) {
return jerr("参数字段已存在");
}
//根据主键更新这条数据
$this->updateByPk($data);
return jok('修改成功');
}
/**
* 删除接口基类
*
* @return void
*/
public function delete()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (isInteger($this->pk_value)) {
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
if($item['conf_system']==1){
return jerr("系统参数,禁止删除", 404);
}
//单个操作
$this->deleteBySingle();
} else {
//批量操作
return jerr("暂不支持批量删除", 400);
}
return jok('删除成功');
}
}
+13
View File
@@ -0,0 +1,13 @@
<?php
namespace app\admin\controller;
use app\admin\QfShop;
class Error extends QfShop
{
public function index()
{
return jerr("admin not found", 404);
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace app\admin\controller;
use think\App;
use think\facade\Filesystem;
use app\admin\QfShop;
use app\model\Feedback as FeedbackModel;
class Feedback extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//查询列表时允许的字段
$this->selectList = "*";
//查询详情时允许的字段
$this->selectDetail = "*";
$this->model = new FeedbackModel();
}
/**
* 获取列表接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function getList()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//从请求中获取筛选数据的数组
$map = $this->getDataFilterFromRequest();
//从请求中获取排序方式
$order = $this->getorderfromRequest();
//设置Model中的 per_page
$this->setGetListPerPage();
//查询数据
$dataList = $this->model->getListByPage($map, $order, $this->selectList);
return jok('数据获取成功', $dataList);
}
}
+264
View File
@@ -0,0 +1,264 @@
<?php
namespace app\admin\controller;
use think\App;
use app\admin\QfShop;
use app\model\Group as GroupModel;
class Group extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//筛选字段
$this->searchFilter = [
"group_id" => "=", //相同筛选
"group_name" => "like", //相似筛选
];
$this->insertFields = [
"group_name", "group_desc"
];
$this->updateFields = [
"group_name", "group_desc"
];
$this->insertRequire = [
'group_name' => "组名称必须填写"
];
$this->updateRequire = [
'group_name' => "组名称必须填写"
];
$this->model = new GroupModel();
}
/**
* 修改用户组
*
* @return void
*/
public function update()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (!isInteger($this->pk_value)) {
return jerr("修改失败,参数错误", 400);
}
$item = $this->model->where($this->pk, $this->pk_value)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
if ($item[$this->pk] == 1) {
return jerr("无法操作超级管理员组信息");
}
foreach ($this->updateRequire as $k => $v) {
if (!input($k)) {
return jerr($v);
}
}
$data = [];
foreach (input('post.') as $k => $v) {
if (in_array($k, $this->updateFields)) {
$data[$k] = $v;
}
}
if (!input($this->table . "_name")) {
return jerr("组名称必须填写", 400);
}
$data[$this->table . "_updatetime"] = time();
$this->model->where($this->pk, $this->pk_value)->update($data);
return jok('用户组信息更新成功');
}
/**
* 禁用用户组
*
* @return void
*/
public function disable()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "参数必须填写", 400);
}
if (isInteger($this->pk_value)) {
$map = [$this->pk => $this->pk_value];
$item = $this->model->where($map)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
if ($item[$this->pk] == 1) {
return jerr("无法操作超级管理员组信息");
}
$this->model->where($map)->update([
$this->table . "_status" => 1,
$this->table . "_updatetime" => time(),
]);
} else {
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->where("group_id > 1")->update([
$this->table . "_status" => 1,
$this->table . "_updatetime" => time(),
]);
}
return jok("禁用用户组成功");
}
/**
* 启用用户组
*
* @return void
*/
public function enable()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "参数必须填写", 400);
}
if (isInteger($this->pk_value)) {
$map = [$this->pk => $this->pk_value];
$item = $this->model->where($map)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
if ($item[$this->pk] == 1) {
return jerr("无法操作超级管理员组信息");
}
$this->model->where($map)->update([
$this->table . "_status" => 0,
$this->table . "_updatetime" => time(),
]);
} else {
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->where("group_id > 1")->update([
$this->table . "_updatetime" => time(),
]);
}
return jok("启用用户组成功");
}
/**
* 删除用户组
*
* @return void
*/
public function delete()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (isInteger($this->pk_value)) {
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
if ($item[$this->pk] == 1) {
return jerr("无法删除超级管理员组");
}
$this->deleteBySingle();
//删除对应ID的授权记录
$this->authModel->where([
"auth_group" => $this->pk_value
])->delete();
} else {
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->where("group_id > 1")->delete();
//删除对应ID的授权记录
$this->authModel->where("auth_group", "in", $list)->delete();
}
return jok('删除用户组成功');
}
/**
* 为用户组授权节点
*
* @return void
*/
public function authorize()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (!isInteger($this->pk_value)) {
return jerr("修改失败,参数错误", 400);
}
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("用户组信息查询失败,授权失败", 404);
}
$this->authModel->where([
"auth_group" => $this->pk_value
])->delete();
if ($item[$this->pk] == 1) {
return jerr("超级管理组无需授权!");
}
$node_ids = explode(",", input("node_ids"));
foreach ($node_ids as $node_id) {
if (intval($node_id) == 0) {
continue;
}
$this->authModel->insert([
"auth_group" => $this->pk_value,
"auth_node" => $node_id,
"auth_createtime" => time(),
"auth_updatetime" => time()
]);
}
return jok('用户组授权成功');
}
/**
* 获取用户组拥有的权限
*
* @return void
*/
public function getAuthorize()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (!isInteger($this->pk_value)) {
return jerr("修改失败,参数错误", 400);
}
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("用户组信息查询失败,授权失败", 404);
}
$myAuthorizeList = $this->authModel->where("auth_group", $this->pk_value)->select();
return jok('ok', $myAuthorizeList);
}
/**
* 获取所有用户组
*
* @return void
*/
public function getList()
{
$error = $this->access();
if ($error) {
return $error;
}
$dataList = $this->model->select();
return jok('用户组列表获取成功', $dataList);
}
}
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace app\admin\controller;
use app\admin\QfShop;
use think\facade\Config;
use think\facade\Cache;
use think\facade\Db;
use util\Time;
class Index extends QfShop
{
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace app\admin\controller;
use think\App;
use think\facade\Filesystem;
use app\admin\QfShop;
use app\model\Log as LogModel;
class Log extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//查询列表时允许的字段
$this->selectList = "*";
//查询详情时允许的字段
$this->selectDetail = "*";
$this->model = new LogModel();
}
/**
* 获取列表接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function getList()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//从请求中获取筛选数据的数组
$map = $this->getDataFilterFromRequest();
//从请求中获取排序方式
$order = "update_time desc";
//设置Model中的 per_page
$this->setGetListPerPage();
//查询数据
$dataList = $this->model->getListByPage($map, $order, $this->selectList);
return jok('数据获取成功', $dataList);
}
public function setDomain()
{
$error = $this->access();
if ($error) {
return $error;
}
$data = ['domain'=>input('domain')];
$this->model->where('id', input('id'))->update($data);
return jok('更新成功');
}
}
+213
View File
@@ -0,0 +1,213 @@
<?php
namespace app\admin\controller;
use think\App;
use app\admin\QfShop;
use app\model\Node as NodeModel;
class Node extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//筛选字段
$this->searchFilter = [
"node_id" => "=", //相同筛选
"node_show" => "=", //相同筛选
"node_title" => "like", //相似筛选
"node_desc" => "like", //相似筛选
"node_module" => "like", //相似筛选
"node_controller" => "like", //相似筛选
"node_action" => "like", //相似筛选
];
$this->insertFields = [
"node_title", "node_desc", "node_module", "node_action", "node_controller", "node_icon", "node_show", "node_pid", "node_order", "node_login", "node_access"
];
$this->updateFields = [
"node_title", "node_desc", "node_module", "node_action", "node_controller", "node_icon", "node_show", "node_pid", "node_order", "node_login", "node_access"
];
$this->insertRequire = [
'node_title' => "节点名称必须填写",
'node_module' => "节点模块必须填写",
];
$this->updateRequire = [
'node_title' => "节点名称必须填写",
'node_module' => "节点模块必须填写",
];
$this->model = new NodeModel();
}
/**
* 添加节点
*
* @return void
*/
public function add()
{
$error = $this->access();
if ($error) {
return $error;
}
$error = $this->validateInsertFields();
if ($error) {
return $error;
}
$data = $this->getInsertDataFromRequest();
$data['node_module'] = strtolower($data['node_module']);
$data['node_controller'] = input("node_controller") ? strtolower($data['node_controller']) : "";
$data['node_action'] = input("node_action") ? strtolower($data['node_action']) : "";
$this->insertRow($data);
return jok('用户添加成功');
}
/**
* 更新节点
*
* @return void
*/
public function update()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
if (!isInteger($this->pk_value)) {
return jerr("修改失败,参数错误", 400);
}
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
$error = $this->validateUpdateFields();
if ($error) {
return $error;
}
$data = $this->getUpdateDataFromRequest();
if($item['node_id'] == $data['node_pid']){
return jerr("不能选择自己为上级菜单", 404);
}
$data['node_module'] = strtolower($data['node_module']);
$data['node_controller'] = input("node_controller") ? strtolower($data['node_controller']) : "";
$data['node_action'] = input("node_action") ? strtolower($data['node_action']) : "";
$this->updateByPk($data);
return jok('节点信息更新成功');
}
/**
* 删除节点
*
* @return void
*/
public function delete()
{
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写");
}
if (isInteger($this->pk_value)) {
$map = [$this->pk => $this->pk_value];
$item = $this->model->where($map)->find();
if (empty($item)) {
return jerr("数据查询失败");
}
$this->deleteBySingle();
//删除对应ID的授权记录
$this->authModel->where("auth_node", $this->pk_value)->delete();
} else {
$this->deleteByMultiple();
//删除对应ID的授权记录
$list = explode(',', $this->pk_value);
$this->authModel->where("auth_node", 'in', $list)->delete();
}
return jok('删除节点成功');
}
/**
* 获取所有节点
*
* @return void
*/
public function getList()
{
$error = $this->access();
if ($error) {
return $error;
}
$order = $this->table . "_order desc," . $this->pk . " asc";
$map = [
"node_pid" => 0
];
$datalist = $this->model->where($map)->order($order)->select();
$subMap = $this->getDataFilterFromRequest();
for ($i = 0; $i < count($datalist); $i++) {
$subDatalist = $this->model->field($this->selectList)->where($subMap)->where($this->table . "_pid", $datalist[$i][$this->pk])->order($order)->select();
$datalist[$i]['sub'] = $subDatalist;
for ($j = 0; $j < count($datalist[$i]['sub']); $j++) {
$subDatalist2 = $this->model->field($this->selectList)->where($subMap)->where($this->table . "_pid", $datalist[$i]['sub'][$j][$this->pk])->order($order)->select();
$datalist[$i]['sub'][$j]['sub'] = $subDatalist2;
}
}
return jok('success', [
'data' => $datalist,
'map' => $map
]);
}
/**
* 显示到菜单中
*
* @return void
*/
public function show_menu()
{
$error = $this->access();
if ($error) {
return $error;
}
if (isInteger($this->pk_value)) {
$this->model->where($this->pk, $this->pk_value)->update([
$this->table . "_show" => 1,
$this->table . "_updatetime" => time(),
]);
} else {
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->update([
$this->table . "_show" => 1,
$this->table . "_updatetime" => time(),
]);
}
return jok("显示成功");
}
/**
* 从菜单中隐藏
*
* @return void
*/
public function hide_menu()
{
$error = $this->access();
if ($error) {
return $error;
}
if (isInteger($this->pk_value)) {
$this->model->where($this->pk, $this->pk_value)->update([
$this->table . "_show" => 0,
$this->table . "_updatetime" => time(),
]);
} else {
$list = explode(',', $this->pk_value);
$this->model->where($this->pk, 'in', $list)->update([
$this->table . "_show" => 0,
$this->table . "_updatetime" => time(),
]);
}
return jok("隐藏成功");
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace app\admin\controller;
use think\App;
use app\admin\QfShop;
use app\model\Sms as SmsModel;
use app\model\Validate as ValidateModel;
class Sms extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SmsModel();
}
/**
* 发送短信验证码
*
* @return void
*/
public function send()
{
//验证图形验证码
$validateModel = new ValidateModel();
$error = $validateModel->validateImgCode(input('token'), input('code'));
if ($error) {
return $error;
}
if (input("phone")) {
$phone = input('phone');
$code = cache("SMS_" . $phone);
if ($code) {
return jerr('发送短信太频繁,请稍候再试');
}
$code = rand(100000, 999999);
$error = $this->model->sendSms($phone, $code);
if ($error) {
return $error;
}
cache('SMS_' . $phone, $code, 300);
return jok('短信验证码已经发送至你的手机');
} else {
return jerr("手机号为必填信息,请填写后提交");
}
}
}
+447
View File
@@ -0,0 +1,447 @@
<?php
namespace app\admin\controller;
use think\App;
use think\facade\Filesystem;
use app\admin\QfShop;
use app\model\Source as SourceModel;
use app\model\SourceLog as SourceLogModel;
use quarkPlugin\QuarkPlugin;
class Source extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//查询列表时允许的字段
$this->selectList = "*";
//查询详情时允许的字段
$this->selectDetail = "*";
//筛选字段
$this->searchFilter = [];
$this->insertFields = [
//允许添加的字段列表
"source_category_id","title","description","url","status","is_delete","sort","is_top","vod_content","is_type"
];
$this->updateFields = [
//允许更新的字段列表
"source_category_id","title","description","url","status","is_delete","sort","is_top","vod_content","is_type"
];
$this->insertRequire = [
//添加时必须填写的字段
// "字段名称"=>"该字段不能为空"
"title"=>"资源名称必须填写",
"url"=>"资源地址必须填写",
];
$this->updateRequire = [
//修改时必须填写的字段
// "字段名称"=>"该字段不能为空"
"source_id"=>"资源ID必须填写",
"title"=>"资源名称必须填写",
"url"=>"资源地址必须填写",
];
$this->model = new SourceModel();
$this->SourceLogModel = new SourceLogModel();
}
/**
* 获取列表接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function getList()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//从请求中获取筛选数据的数组
$map = $this->getDataFilterFromRequest();
$map[] = ['is_delete','=',0];
if(!empty(input('source_category_id'))){
$map[] = ['source_category_id','=',input('source_category_id')];
}
empty(input('keyword')) ?: $map[] = ['title|description', 'like', '%' . input('keyword') . '%'];
//从请求中获取排序方式
$order = $this->getorderfromRequest();
//设置Model中的 per_page
$this->setGetListPerPage();
//查询数据
$dataList = $this->model->getListByPage($map, $order, $this->selectList);
return jok('数据获取成功', $dataList);
}
/**
* 添加接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function add()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//校验Insert字段是否填写
$error = $this->validateInsertFields();
if ($error) {
return $error;
}
//从请求中获取Insert数据
$data = $this->getInsertDataFromRequest();
//添加这行数据
$data["update_time"] = time();
$data["create_time"] = time();
$data["is_type"] = determineIsType($data["url"]);
$this->model->insertGetId($data);
return jok('添加成功');
}
/**
* 修改接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function update()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "参数必须填写", 400);
}
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//校验Update字段是否填写
$error = $this->validateUpdateFields();
if ($error) {
return $error;
}
//从请求中获取Update数据
$data = $this->getUpdateDataFromRequest();
//根据主键更新这条数据
$data["update_time"] = time();
$data["is_type"] = determineIsType($data["url"]);
$this->model->where($this->pk, $this->pk_value)->update($data);
return jok('修改成功');
}
/**
* 删除接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function delete()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
if (!$this->pk_value) {
return jerr($this->pk . "必须填写", 400);
}
//根据主键获取一行数据
$item = $this->getRowByPk();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
$this->model->where($this->pk, $this->pk_value)->delete();
return jok('删除成功');
}
// 判断文件编码
function detectFileEncoding($filename) {
$handle = fopen($filename, 'r');
$firstLine = fread($handle, 1024); // 读取文件的开头一部分内容
fclose($handle);
// 尝试使用不同的编码进行解码,并检查是否成功
if (mb_check_encoding($firstLine, 'UTF-8')) {
return 'UTF-8';
} elseif (mb_check_encoding($firstLine, 'GBK')) {
return 'GBK';
} else {
// 如果无法确定编码,则返回默认编码
return 'UTF-8'; // 或者根据需要返回其他默认编码
}
}
/**
* Excel导入
*
* @return void
*/
public function imports()
{
$error = $this->access();
if ($error) {
return $error;
}
// try {
$file = request()->file('file');
try {
validate(['file' => 'filesize:' . config("qfshop.upload_max_file") . '|fileExt:' . config("qfshop.upload_file_type")])
->check(['file' => $file]);
$saveName = Filesystem::putFile('excel', $file, 'excel.csv');
ini_set("memory_limit",-1);
$file_name = app()->getRootPath()."public/uploads/".$saveName;
$extension = pathinfo($file_name, PATHINFO_EXTENSION);
if ($extension == 'csv') {
$PHPReader = new \PHPExcel_Reader_CSV();
$encoding = $this->detectFileEncoding($file_name);
$PHPReader->setInputEncoding($encoding);
$PHPReader->setDelimiter(',');
} elseif ($extension == 'xlsx') {
$PHPReader = new \PHPExcel_Reader_Excel2007();
} elseif ($extension == 'xls') {
$PHPReader = new \PHPExcel_Reader_Excel5();
} else {
return jerr('不支持的文件类型');
}
// //读取excel文件
// $PHPReader = new \PHPExcel_Reader_CSV();
// //默认输入字符集// 判断文件编码
// $encoding = $this->detectFileEncoding($file_name);
// $PHPReader->setInputEncoding($encoding);
// //默认的分隔符
// $PHPReader->setDelimiter(',');
//载入文件
$objExcel = $PHPReader->load($file_name);
$excel_array = $objExcel ->getSheet(0)->toArray();
array_shift($excel_array); //删除第一个数组(标题);
$data = [];
$i = 0;
//删除这个文件
unlink("./uploads/".$saveName);
foreach ($excel_array as $k => $v) {
$patterns = '/^\d+\.|\d+\-/';
$title = '';
$url = '';
for ($index = 1; $index <= 3; $index++) {
// 检查 $v[$index] 是否存在
if (isset($v[$index]) && preg_match('/http[^ ]+/', $v[$index], $matches)) {
// 检查 $v[$index - 1] 是否存在
if (isset($v[$index - 1])) {
$title = preg_replace($patterns, '', $v[$index - 1]);
}
$url = $matches[0];
break;
}
}
$map = [];
$map[] = ['title', '=',$title];
$res = $this->model->where($map)->find();
if (empty($res) && $url) {
$data[$k]['title'] = $title;
$data[$k]['url'] = $url;
$data[$k]["is_type"] = determineIsType($url);
$data[$k]['source_category_id'] = input('source_category_id')??0;
$data[$k]['update_time'] = time();
$data[$k]['create_time'] = time();
$i++;
}
}
$this->model->insertAll($data);
if($i == 0){
return jok('无可导入的资源,请检查表格格式');
}
return jok('导入成功'.$i.'个资源');
} catch (ValidateException $e) {
return jerr($e->getMessage());
}
// } catch (\Exception $error) {
// return jerr('上传文件失败,请检查你的文件!');
// }
}
/**
* 导出
*
* @return void
*/
public function excel()
{
$error = $this->access();
if ($error) {
return $error;
}
//查询数据
$map = [];
$filter = input('');
foreach ($filter as $k => $v) {
if ($k == 'filter') {
$k = input('filter');
$v = input('keyword');
}
if ($v === '' || $v === null) {
continue;
}
if (array_key_exists($k, $this->searchFilter)) {
switch ($this->searchFilter[$k]) {
case "like":
array_push($map, [$k, 'like', "%" . $v . "%"]);
break;
case "=":
array_push($map, [$k, '=', $v]);
break;
default:
}
}
}
$field = 'title,url';
$dataList = $this->model->field($field)->where($map)->select();
$excelField = [
"title" => "资源名称",
"url" => "资源地址",
];
$data = $dataList->toArray();
$this->excelField = $excelField;
$this->exportExcelData($dataList);
print_r(12);
}
/**
* 一键转存并分享夸克资源
*
* @return void
*/
public function transfer()
{
$error = $this->access();
if ($error) {
return $error;
}
if(empty(input("type")) || empty(input("urls"))){
return jerr('参数不能为空');
}
$source_category_id = input('source_category_id')??0;
$urls = input("urls");
$urls = explode("\n", $urls);
// 去掉数组元素中的空白字符
$urls = array_map('trim', $urls);
// 过滤掉空值的数组元素
$urls = array_filter($urls);
$allData = array_map(function($item) {
$url = $item;
$code = '';
// 检查是否包含 '?pwd=' 提取码格式
if (strpos($item, '?pwd=') !== false) {
// 使用 '?pwd=' 分割链接和提取码
list($url, $code) = explode('?pwd=', $item, 2);
$url = trim($url); // 去掉 URL 中的空白字符
$code = trim($code); // 提取码去掉空白字符
}
// 检查是否包含逗号 ',' 提取码格式
else if (strpos($item, ',') !== false) {
// 使用 ',' 分割链接和提取码
list($url, $code) = explode(',', $item, 2);
$url = trim($url); // 去掉 URL 中的空白字符
$code = trim($code); // 提取码去掉空白字符
}
return [
'url' => $url, // 只取链接部分
'title' => '',
'code' => $code, // 提取码部分
];
}, $urls);
// 去重,使用 'url' 字段来去重
$uniqueUrls = [];
$allData = array_filter($allData, function($item) use (&$uniqueUrls) {
if (!in_array($item['url'], $uniqueUrls)) {
$uniqueUrls[] = $item['url']; // 添加到已处理的 URL 列表
return true; // 保留此项目
}
return false; // 去掉重复的项目
});
$quarkPlugin = new QuarkPlugin();
if(input("type")==2){
//转存分享导入
$res = $quarkPlugin->transfer($allData,$source_category_id);
}else{
// 直接导入
$res = $quarkPlugin->import($allData,$source_category_id);
}
return jok('已提交任务,稍后查看结果2',$res);
}
/**
* 全部转存
* 转存心悦搜剧资源
* @return void
*/
public function transferAll()
{
$error = $this->access();
if ($error) {
return $error;
}
if(empty(input('source_category_id'))){
return jerr('参数异常');
}
$quarkPlugin = new QuarkPlugin();
$quarkPlugin->transferAll(input('source_category_id'));
return jok('已提交任务,稍后查看结果');
}
/**
* 获取夸克网盘文件夹
*
* @return void
*/
public function getFiles()
{
$error = $this->access();
if ($error) {
return $error;
}
$quarkPlugin = new QuarkPlugin();
$result = $quarkPlugin->getFiles(Config('qfshop.quark_cookie'));
return jok('获取成功',$result);
}
}
+262
View File
@@ -0,0 +1,262 @@
<?php
namespace app\admin\controller;
use think\App;
use app\admin\QfShop;
use app\model\SourceCategory as SourceCategoryModel;
class SourceCategory extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//查询列表时允许的字段
$this->selectList = "*";
//查询详情时允许的字段
$this->selectDetail = "*";
//筛选字段
$this->searchFilter = [
"source_category_id" => "=",
"name"=>"like"
];
$this->insertFields = [
//允许添加的字段列表
"name","sort","status","image"
];
$this->updateFields = [
//允许更新的字段列表
"name","sort","status","image"
];
$this->insertRequire = [
//添加时必须填写的字段
// "字段名称"=>"该字段不能为空"
"name"=>"分类名称必须填写",
];
$this->updateRequire = [
//修改时必须填写的字段
// "字段名称"=>"该字段不能为空"
"name"=>"分类名称必须填写",
];
$this->model = new SourceCategoryModel();
}
/**
* 获取列表接口
*
* @return void
*/
public function getList()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//查询数据
$dataList = $this->model->order('sort', 'desc')->select();
return jok('数据获取成功', $dataList);
}
/**
* 获取详情基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function detail()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
$source_category_id = input("source_category_id");
if (!$source_category_id) {
return jerr("ID参数必须填写", 400);
}
//根据主键获取一行数据
$item = $this->model->where("source_category_id", $source_category_id)->field($this->selectDetail)->find();
if (empty($item)) {
return jerr("没有查询到数据", 404);
}
return jok('数据加载成功', $item);
}
/**
* 添加接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function add()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//校验Insert字段是否填写
$error = $this->validateInsertFields();
if ($error) {
return $error;
}
//从请求中获取Insert数据
$data = $this->getInsertDataFromRequest();
//添加这行数据
$data['create_time'] = time();
$data['update_time'] = time();
$this->model->insertGetId($data);
return jok('添加成功');
}
/**
* 修改接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function update()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
$source_category_id = input("source_category_id");
if (!$source_category_id) {
return jerr("ID参数必须填写", 400);
}
//根据主键获取一行数据
$item = $this->model->where("source_category_id", $source_category_id)->field($this->selectDetail)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//校验Update字段是否填写
$error = $this->validateUpdateFields();
if ($error) {
return $error;
}
//从请求中获取Update数据
$data = $this->getUpdateDataFromRequest();
//根据主键更新这条数据
$data['update_time'] = time();
$this->model->where("source_category_id", $source_category_id)->update($data);
return jok('修改成功');
}
/**
* 删除接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function delete()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
$source_category_id = input("source_category_id");
if (!$source_category_id) {
return jerr("ID参数必须填写", 400);
}
//根据主键获取一行数据
$item = $this->model->where("source_category_id", $source_category_id)->field($this->selectDetail)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
if ($item['is_sys']==1) {
return jerr("该类别不能删除");
}
//单个操作
$map = ["source_category_id" => $source_category_id];
$this->model->where($map)->delete();
return jok('删除成功');
}
/**
* 禁用接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function disable()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
$source_category_id = input("source_category_id");
if (!$source_category_id) {
return jerr("ID参数必须填写", 400);
}
if (isInteger($source_category_id)) {
//根据主键获取一行数据
$item = $this->model->where("source_category_id", $source_category_id)->field($this->selectDetail)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//单个操作
$map = ["source_category_id" => $source_category_id];
$this->model->where($map)->update([
"status" => 1,
"update_time" => time(),
]);
} else {
//批量操作
$list = explode(',', $source_category_id);
$this->model->where("source_category_id", 'in', $list)->update([
"status" => 1,
"update_time" => time(),
]);
}
return jok("禁用成功");
}
/**
* 启用接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function enable()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
$source_category_id = input("source_category_id");
if (!$source_category_id) {
return jerr("ID参数必须填写", 400);
}
if (isInteger($source_category_id)) {
//根据主键获取一行数据
$item = $this->model->where("source_category_id", $source_category_id)->field($this->selectDetail)->find();
if (empty($item)) {
return jerr("数据查询失败", 404);
}
//单个操作
$map = ["source_category_id" => $source_category_id];
$this->model->where($map)->update([
"status" => 0,
"update_time" => time(),
]);
} else {
//批量操作
$list = explode(',', $source_category_id);
$this->model->where("source_category_id", 'in', $list)->update([
"status" => 0,
"update_time" => time(),
]);
}
return jok("启用成功");
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace app\admin\controller;
use think\App;
use think\facade\Filesystem;
use app\admin\QfShop;
use app\model\SourceLog as SourceLogModel;
class SourceLog extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//查询列表时允许的字段
$this->selectList = "*";
//查询详情时允许的字段
$this->selectDetail = "*";
$this->model = new SourceLogModel();
}
/**
* 获取列表接口基类 子类自动继承 如有特殊需求 可重写到子类 请勿修改父类方法
*
* @return void
*/
public function getList()
{
//校验Access与RBAC
$error = $this->access();
if ($error) {
return $error;
}
//从请求中获取筛选数据的数组
$map = $this->getDataFilterFromRequest();
//从请求中获取排序方式
$order = $this->getorderfromRequest();
//设置Model中的 per_page
$this->setGetListPerPage();
//查询数据
$dataList = $this->model->getListByPage($map, $order, $this->selectList);
return jok('数据获取成功', $dataList);
}
}
+77
View File
@@ -0,0 +1,77 @@
<?php
namespace app\admin\controller;
use think\App;
use think\facade\Db;
use think\facade\Cache;
use app\admin\QfShop;
use app\model\Validate as ValidateModel;
class System extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
}
/**
* 获取图形验证码
*
* @return void
*/
public function getCaptcha()
{
// $error = $this->access();
// if ($error) {
// return $error;
// }
$validateModel = new ValidateModel();
$imgData = $validateModel->getImg();
$code = strtoupper($validateModel->getCode());
$token = sha1($code . time()) . rand(100000, 999999);
cache($token, $code, 60);
return jok('验证码生成成功', [
'img' => $imgData,
'token' => $token
]);
}
/**
* 清除缓存
*
* @return void
*/
public function clean()
{
$error = $this->access();
if ($error) {
return $error;
}
Cache::clear();
if($this->del_dir("../runtime/")){
return jok('缓存已清空');
}else{
return jerr('缓存清除失败');
}
}
function del_dir($dir) {
$dh=opendir($dir);
while ($file=readdir($dh)) {
if($file!="." && $file!="..") {
$fullpath=$dir."/".$file;
if(!is_dir($fullpath)) {
@unlink($fullpath);
} else {
$this->del_dir($fullpath);
}
}
}
closedir($dh);
if(rmdir($dir)) {
return true;
} else {
return false;
}
}
}
+92
View File
@@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
namespace app\api;
use think\App;
use think\facade\View;
use app\model\Conf as ConfModel;
use app\model\Token as TokenModel;
/**
* 控制器基础类
*/
abstract class QfShop
{
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
//访问XMLHttpRequest已被CORS政策阻止
header('Access-Control-Allow-Origin: *');
$this->confModel = new ConfModel();
$configs = $this->confModel->select()->toArray();
$c = [];
foreach ($configs as $config) {
$c[$config['conf_key']] = $config['conf_value'];
}
config($c, 'qfshop');
}
public function __call($method, $args)
{
return jerr("API接口方法不存在", 404);
}
/**
* 检测授权 获取当前用户登录信息
* @param $type false不提示登录失败状态
* @param user_id 顾客时为用户id
* @param action 操作者 顾客端为手机号,管理端为登录账号
* @param client_type 0=顾客 1=管理组 -1=游客
*/
protected function getLoginUser($type = true)
{
$is_login = true;
// 获取请求中的token
$access_token = request()->header('X-CSRF-TOKEN');
if (!$access_token) {
if($type){
return jerr("用户未登录", 401);
}else{
$is_login = false;
}
}
$Token = new TokenModel();
$user = $Token->getToken($access_token);
if (!$user) {
if($type){
return jerr("登录过期,请重新登录", 401);
}else{
$is_login = false;
}
}
if($is_login){
$user['action'] = $user['mobile'];
$user['client_type'] = 0;
unset($user['mobile']);
unset($user['status']);
return $user;
}else{
$user['client_type'] = -1;
return $user;
}
}
}
+13
View File
@@ -0,0 +1,13 @@
<?php
namespace app\api\controller;
use app\api\QfShop;
class Error extends QfShop
{
public function index()
{
return jerr("Error", 404);
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace app\api\controller;
use app\api\QfShop;
use Lizhichao\Word\VicWord;
class Index extends QfShop
{
public function index()
{
return jok("Hello World!");
}
public function search() {
$fc = new VicWord();
$keywords = input('keywords');
$keywords = $fc->getAutoWord($keywords);
$keywords = filterAndExtractWords($keywords);
return jok("Hello World!",$keywords);
}
}
+710
View File
@@ -0,0 +1,710 @@
<?php
namespace app\api\controller;
use think\App;
use think\facade\Cache;
use app\api\QfShop;
class Open extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
$this->url = "";
$this->is_type = 0;
$this->cookie = ""; //夸克登录凭证
$this->Authorization = ""; //阿里登录凭证
$this->expired_type = 1; //1分享永久 2临时
$this->to_pdir_fid = ""; //存入目标文件
$this->ad_fid = "";
$this->code = ""; //提取码
$this->isType = 0; //等于1时仅校验是否有效并提取资源信息
$this->urlHeader = array(
'Accept: application/json, text/plain, */*',
'Accept-Language: zh-CN,zh;q=0.9',
'content-type: application/json;charset=UTF-8',
'sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
'sec-ch-ua-mobile: ?0',
'sec-ch-ua-platform: "Windows"',
'sec-fetch-dest: empty',
'sec-fetch-mode: cors',
'sec-fetch-site: same-site',
'Referer: https://pan.quark.cn/',
'Referrer-Policy: strict-origin-when-cross-origin',
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
);
}
/**
*
*
* @return void
*/
public function index()
{
return jok('Hello World');
}
/**
* 获取夸克网盘文件夹
*
* @return void
*/
public function getFiles()
{
$this->cookie = input('cookie')??'';
$urlData = [];
$queryParams = [
'pr' => 'ucpro',
'fr' => 'pc',
'uc_param_str' => '',
'pdir_fid' => 0,
'_page' => 1,
'_size' => 50,
'_fetch_total' => 1,
'_fetch_sub_dirs' => 0,
'_sort' => 'file_type:asc,updated_at:desc',
];
$this->urlHeader[] = 'cookie: ' . $this->cookie;
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/sort", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
$res = json_decode($res, true);
if($res['status'] !== 200){
return jerr($res['message']=='require login [guest]'?'夸克未登录,请检查cookie':$res['message']);
}
return jok('获取成功',$res['data']['list']);
}
/**
* 一键转存并分享资源
*
* type 0 夸克 1阿里
*
* @return void
*/
public function transfer()
{
$url = input("url");
$this->code = input('code')??'';
$this->isType = input('isType')??0;
if($this->isType != 1){ //直接入口就不用cookie 防止账号异常
$this->cookie = input('cookie')??'';
$this->Authorization = input('Authorization')??'';
}
$this->expired_type = input('expired_type')??1;
$this->to_pdir_fid = input('to_pdir_fid')??"";
$this->ad_fid = input('ad_fid')??"";
if (strpos($url, '?entry=') !== false) {
$entry = preg_match('/\?entry=([^&]+)/', $url, $matches) ? $matches[1] : '';
$url = preg_match('/.*(?=\?entry=)/', $url, $matches) ? $matches[0] : '';
}
$substring = strstr($url, 's/');
if ($substring !== false) {
$pwd_id = substr($substring, 2); // 去除 's/' 部分
} else {
return jerr("资源地址格式有误");
}
$this->urlHeader[] = 'cookie: ' . $this->cookie;
$patterns = [
'pan.quark.cn' => 0,
'www.alipan.com' => 1,
'www.aliyundrive.com' => 1,
// 'pan.baidu.com' => 2,
'drive.uc.cn' => 3,
// 'pan.xunlei.com' => 4,
];
$url_type = -1; // 默认值为 -1
foreach ($patterns as $pattern => $type) {
if (strpos($url, $pattern) !== false) {
$url_type = $type;
break; // 一旦匹配成功,退出循环
}
}
$this->url = $url;
if ($url_type == 0) {
//夸克
if(empty($this->cookie) && $this->isType==0){
jerr("参数有误");
}
$this->transferQuark(strtok($pwd_id, '#'));
} else if($url_type == 1){
//阿里
if(empty($this->Authorization) && $this->isType==0){
jerr("参数有误");
}
$this->transferAlipan($pwd_id);
} else if($url_type == 2){
//百度
// $this->transferBaidu($pwd_id);
} else if($url_type == 3){
//UC
$this->transferUc($pwd_id);
} else {
return jerr("资源地址格式有误");
}
}
/**
* 夸克 - 一键转存并分享资源
*
* @return void
*/
public function transferQuark($pwd_id){
//获取要转存夸克资源的stoken
$infoData = $this->getStoken($pwd_id);
if($this->isType == 1){
$urls['title'] = $infoData['title'];
$urls['share_url'] = $this->url;
return jok('检验成功', $urls);
}
$stoken = $infoData['stoken'];
//获取要转存夸克资源的详细内容
$detail = $this->getShare($pwd_id,$stoken);
$fid_list = [];
$fid_token_list = [];
$title = $detail['share']['title']; //资源名称
foreach ($detail['list'] as $key => $value) {
$fid_list[] = $value['fid'];
$fid_token_list[] = $value['share_fid_token'];
}
//转存资源到指定文件夹
$task_id = $this->getShareSave($pwd_id,$stoken,$fid_list,$fid_token_list);
//转存后根据task_id获取转存到自己网盘后的信息
$retry_index = 0;
$myData = '';
while ($myData=='' || $myData['status'] != 2) {
$myData = $this->getShareTask($task_id, $retry_index);
$retry_index++;
// 可以添加一个最大重试次数的限制,防止无限循环
if ($retry_index > 50) {
break;
}
}
try {
//删除转存后可能有的广告
$banned = Config('qfshop.quark_banned')??''; //如果出现这些字样就删除
if(!empty($banned)){
$bannedList = explode(',', $banned);
$pdir_fid = $myData['save_as']['save_as_top_fids'][0];
$dellist = [];
$plist = $this->getPdirFid($pdir_fid);
if(!empty($plist)){
foreach ($plist as $key => $value) {
// 检查$value['file_name']是否包含$bannedList中的任何一项
$contains = false;
foreach ($bannedList as $item) {
if (strpos($value['file_name'], $item) !== false) {
$contains = true;
break;
}
}
if ($contains) {
$dellist[] = $value['fid'];
}
}
if(count($plist) === count($dellist)){
//要删除的资源数如果和原数据资源数一样 就全部删除并终止下面的分享
$this->deletepdirFid([$pdir_fid]);
return jerr("资源内容为空");
}else{
if (!empty($dellist)) {
$this->deletepdirFid($dellist);
}
}
}
}
} catch (Exception $e) {
}
//分享资源并拿到更新后的task_id
$task_id = $this->getShareBtn($myData['save_as']['save_as_top_fids'],$title);
//根据task_id拿到share_id
$retry_index = 0;
$myData = '';
while ($myData=='' || $myData['status'] != 2) {
$myData = $this->getShareTask($task_id, $retry_index);
$retry_index++;
// 可以添加一个最大重试次数的限制,防止无限循环
if ($retry_index > 50) {
break;
}
}
//根据share_id 获取到分享链接
$share = $this->getSharePassword($myData['share_id']);
$share['fid'] = $share['first_file']['fid'];
return jok('转存成功', $share);
}
/**
* 阿里 - 一键转存并分享资源
*
* @return void
*/
public function transferAlipan($share_id)
{
$data = [];
$infos = $this->getAlipan1($share_id);
if($this->isType == 1){
$urls['title'] = $infos['share_name'];
$urls['share_url'] = $this->url;
return jok('检验成功', $urls);
}
//通过分享id获取file_id
$file_infos = $infos['file_infos'];
//通过分享id获取X-Share-Token
$share_token = $this->getAlipan2($share_id);
$data3['requests'] = [];
$data3['resource'] = 'file';
foreach ($file_infos as $key=>$value) {
$data3['requests'][$key]['body']['auto_rename'] = true;
$data3['requests'][$key]['body']['file_id'] = $value['file_id'];
$data3['requests'][$key]['body']['share_id'] = $share_id;
$data3['requests'][$key]['body']['to_drive_id'] = '2008425230';
$data3['requests'][$key]['body']['to_parent_file_id'] = '66a20824c3846d890f6542c6aac2c79822d2a64f';
$data3['requests'][$key]['headers']['Content-Type'] = 'application/json';
$data3['requests'][$key]['id'] = $key.'';
$data3['requests'][$key]['method'] = 'POST';
$data3['requests'][$key]['url'] = '/file/copy';
}
//保存
$responses = $this->getAlipan3($data3,$share_token);
$data4['drive_id'] = '2008425230';
$data4['expiration'] = '';
$data4['share_pwd'] = '';
$data4['file_id_list'] = [];
foreach ($responses as $key=>$value){
$data4['file_id_list'][] = $value['body']['file_id'];
}
//分享
$share = $this->getAlipan4($data4);
$data['share_url'] = $share['share_url'];
$data['title'] = $share['share_title'];
return jok('转存成功', $data);
}
/**
* UC- 一键转存并分享资源
*
* @return void
*/
public function transferUc($pwd_id){
$infoData = $this->getStokenUc($pwd_id);
if($this->isType == 1){
$urls['title'] = $infoData['title'];
$urls['share_url'] = $this->url;
return jok('检验成功', $urls);
}else{
return jerr('暂不支持转存');
}
}
/**
* 获取要转存资源的stoken
*
* @return void
*/
public function getStoken($pwd_id)
{
$urlData = array(
'passcode' => '',
'pwd_id' => $pwd_id,
);
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/token?pr=ucpro&fr=pc&uc_param_str=", "POST",json_encode($urlData), $this->urlHeader)['body'];
$res = json_decode($res, true);
if($res['status'] !== 200){
return jerr($res['message']);
}
$data = $res['data'];
return $data;
}
/**
* 获取要转存资源的详细内容
*
* @return void
*/
public function getShare($pwd_id,$stoken)
{
$urlData = array();
$queryParams = [
"pr" => "ucpro",
"fr" => "pc",
"uc_param_str" => "",
"pwd_id" => $pwd_id,
"stoken" => $stoken,
"pdir_fid" => "0",
"force" => "0",
"_page" => "1",
"_size" => "100",
"_fetch_banner" => "1",
"_fetch_share" => "1",
"_fetch_total" => "1",
"_sort" => "file_type:asc,updated_at:desc"
];
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/detail", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
$res = json_decode($res, true);
if($res['status'] !== 200){
return jerr($res['message']);
}
return $res['data'];
}
/**
* 转存资源到指定文件夹
*
* @return void
*/
public function getShareSave($pwd_id,$stoken,$fid_list,$fid_token_list)
{
$to_pdir_fid = $this->to_pdir_fid??"";
$urlData = array(
'fid_list' => $fid_list,
'fid_token_list' => $fid_token_list,
'to_pdir_fid' => $to_pdir_fid,
'pwd_id' => $pwd_id,
'stoken' => $stoken,
'pdir_fid' => "0",
'scene' => "link",
);
$queryParams = [
"entry" => "update_share",
"pr" => "ucpro",
"fr" => "pc",
"uc_param_str" => ""
];
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/save", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
$res = json_decode($res, true);
if($res['status'] !== 200){
return jerr($res['message']=='require login [guest]'?'夸克未登录,请检查cookie':$res['message']);
}
return $res['data']['task_id'];
}
/**
* 分享资源拿到task_id
*
* @return void
*/
public function getShareBtn($fid_list,$title)
{
if(!empty($this->ad_fid)){
$fid_list[] = $this->ad_fid;
}
$urlData = array(
'fid_list' => $fid_list,
'expired_type' => $this->expired_type,
'title' => $title,
'url_type' => 1,
);
$queryParams = [
"pr" => "ucpro",
"fr" => "pc",
"uc_param_str" => ""
];
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
$res = json_decode($res, true);
if($res['status'] !== 200){
return jerr($res['message']);
}
return $res['data']['task_id'];
}
/**
* 根据task_id拿到自己的资源信息
*
* @return void
*/
public function getShareTask($task_id,$retry_index)
{
$urlData = array();
$queryParams = [
"pr" => "ucpro",
"fr" => "pc",
"uc_param_str" => "",
"task_id" => $task_id,
"retry_index" => $retry_index
];
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/task", "GET", json_encode($urlData), $this->urlHeader, $queryParams)['body'];
$res = json_decode($res, true);
if($res['status'] !== 200){
return jerr($res['message']);
}
return $res['data'];
}
/**
* 根据share_id 获取到分享链接
*
* @return void
*/
public function getSharePassword($share_id)
{
$urlData = array(
'share_id' => $share_id,
);
$queryParams = [
"pr" => "ucpro",
"fr" => "pc",
"uc_param_str" => ""
];
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/share/password", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
$res = json_decode($res, true);
if($res['status'] !== 200){
return jerr($res['message']);
}
return $res['data'];
}
/**
* 删除指定资源
*
* @return void
*/
public function deletepdirFid($filelist)
{
$urlData = array(
'action_type' => 2,
'exclude_fids' => [],
'filelist' => $filelist,
);
$queryParams = [
"pr" => "ucpro",
"fr" => "pc",
"uc_param_str" => ""
];
curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/delete", "POST", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
}
/**
* 获取夸克网盘指定文件夹内容
*
* @return void
*/
public function getPdirFid($pdir_fid)
{
$urlData = [];
$queryParams = [
'pr' => 'ucpro',
'fr' => 'pc',
'uc_param_str' => '',
'pdir_fid' => $pdir_fid,
'_page' => 1,
'_size' => 200,
'_fetch_total' => 1,
'_fetch_sub_dirs' => 0,
'_sort' => 'file_type:asc,updated_at:desc',
];
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/sort", "GET", json_encode($urlData), $this->urlHeader,$queryParams)['body'];
$res = json_decode($res, true);
if($res['status'] !== 200){
return [];
}
return $res['data']['list'];
}
/**
* 阿里-0-通过分享id获取file_id
*
* @return void
*/
public function getAlipan1($share_id)
{
$urlData = [
'share_id' => $share_id,
];
$urlHeader = array(
'Content-Type: application/json',
);
$res = curlHelper("https://api.aliyundrive.com/adrive/v3/share_link/get_share_by_anonymous", "POST", json_encode($urlData),$urlHeader)['body'];
$res = json_decode($res, true);
if(!isset($res['file_infos'])){
return jerr($res['message']??'转存失败1');
}
return $res;
}
/**
* 阿里-0-通过分享id获取X-Share-Token
*
* @return void
*/
public function getAlipan2($share_id)
{
$urlData = array(
'share_id' => $share_id,
);
$urlHeader = array(
'Accept: application/json, text/plain, */*',
'Accept-Encoding: gzip, deflate, br, zstd',
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Authorization: '.$this->Authorization,
'Content-Type: application/json',
'Origin: https://www.alipan.com',
'Priority: u=1, i',
'Referer: https://www.alipan.com/',
'Sec-Ch-Ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
'Sec-Ch-Ua-Mobile: ?0',
'Sec-Ch-Ua-Platform: "Windows"',
'Sec-Fetch-Dest: empty',
'Sec-Fetch-Mode: cors',
'Sec-Fetch-Site: same-site',
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
'X-Canary: client=web,app=share,version=v2.3.1'
);
$res = curlHelper("https://api.aliyundrive.com/v2/share_link/get_share_token", "POST", json_encode($urlData), $urlHeader)['body'];
$res = json_decode($res, true);
if(!isset($res['share_token'])){
return jerr($res['message']??'转存失败2');
}
return $res['share_token'];
}
/**
* 阿里-1-保存
*
* @return void
*/
public function getAlipan3($urlData,$share_token)
{
$urlHeader = array(
'Accept: application/json, text/plain, */*',
'Accept-Encoding: gzip, deflate, br, zstd',
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Authorization: '.$this->Authorization,
'Content-Type: application/json',
'Origin: https://www.alipan.com',
'Priority: u=1, i',
'Referer: https://www.alipan.com/',
'Sec-Ch-Ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
'Sec-Ch-Ua-Mobile: ?0',
'Sec-Ch-Ua-Platform: "Windows"',
'Sec-Fetch-Dest: empty',
'Sec-Fetch-Mode: cors',
'Sec-Fetch-Site: same-site',
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
'X-Canary: client=web,app=share,version=v2.3.1',
'X-Share-Token: '.$share_token
);
$res = curlHelper("https://api.aliyundrive.com/adrive/v4/batch", "POST", json_encode($urlData), $urlHeader)['body'];
$res = json_decode($res, true);
if(!isset($res['responses'])){
return jerr($res['message']??'转存失败3');
}
return $res['responses'];
}
/**
* 阿里-2-分享
*
* @return void
*/
public function getAlipan4($urlData)
{
$urlHeader = array(
'Accept: application/json, text/plain, */*',
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Authorization: '.$this->Authorization,
'Content-Type: application/json',
'Origin: https://www.alipan.com',
'Priority: u=1, i',
'Referer: https://www.alipan.com/',
'Sec-Ch-Ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
'Sec-Ch-Ua-Mobile: ?0',
'Sec-Ch-Ua-Platform: "Windows"',
'Sec-Fetch-Dest: empty',
'Sec-Fetch-Mode: cors',
'Sec-Fetch-Site: same-site',
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
'X-Canary: client=web,app=share,version=v2.3.1'
);
$res = curlHelper("https://api.aliyundrive.com/adrive/v2/share_link/create", "POST", json_encode($urlData), $urlHeader)['body'];
$res = json_decode($res, true);
return jerr($res);
if(!isset($res['share_url'])){
return jerr($res['message']??'转存失败4');
}
return $res;
}
/**
* UC 00000
*
* @return void
*/
public function getStokenUc($pwd_id)
{
$urlData = array(
'passcode' => '',
'pwd_id' => $pwd_id,
);
$urlHeader = array(
'Accept: application/json, text/plain, */*',
'Accept-Language: zh-CN,zh;q=0.9',
'content-type: application/json;charset=UTF-8',
'sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
'sec-ch-ua-mobile: ?0',
'sec-ch-ua-platform: "Windows"',
'sec-fetch-dest: empty',
'sec-fetch-mode: cors',
'sec-fetch-site: same-site',
'Referer: https://drive.uc.cn/',
'Referrer-Policy: strict-origin-when-cross-origin',
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
);
$res = curlHelper("https://pc-api.uc.cn/1/clouddrive/share/sharepage/token?pr=UCBrowser&fr=pc", "POST",json_encode($urlData),$urlHeader)['body'];
$res = json_decode($res, true);
if($res['status'] !== 200){
return jerr($res['message']);
}
$data = $res['data'];
return $data;
}
}
+628
View File
@@ -0,0 +1,628 @@
<?php
namespace app\api\controller;
use think\App;
use app\api\QfShop;
use app\model\Source as SourceModel;
use app\model\Days as DaysModel;
class Other extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
//第三方转存接口地址
$this->url = "https://pan.xinyuedh.com";
$this->model = new SourceModel();
$this->cookie = Config('qfshop.quark_cookie');
}
public function Alone_search2()
{
$searchdata = input('');
if (empty($searchdata['alone_title'])) {
return jerr("请输入要看的内容");
}
$type = $searchdata['type']??0;
$title = $searchdata['alone_title'];
$searchList = []; //查询的结果集
$num_total = $type?2:20; //最多想要几条结果
$num_success = 0;
// 处理第2个源
foreach (source2($title) as $value) {
if ($num_success >= $num_total) {
break; // 有效结果数量已达到,则跳出循环
}
// 如果 URL 不存在则新增 $value
if (!$this->urlExists($searchList, $value['url'])) {
$searchList[] = $value;
$num_success++;
}
}
// 处理第4个源
if ($num_success < $num_total) {
foreach (source4($title) as $value) {
if ($num_success >= $num_total) {
break; // 有效结果数量已达到,则跳出循环
}
// 如果 URL 不存在则新增 $value
if (!$this->urlExists($searchList, $value['url'])) {
$searchList[] = $value;
$num_success++;
}
}
}
// 处理第3个源
if ($num_success < $num_total) {
foreach (source3($title) as $value) {
if ($num_success >= $num_total) {
break; // 有效结果数量已达到,则跳出循环
}
// 如果 URL 不存在则新增 $value
if (!$this->urlExists($searchList, $value['url'])) {
$searchList[] = $value;
$num_success++;
}
}
}
// 处理第1个源 第一个源放最后
if ($num_success < $num_total) {
foreach (source1($title) as $value) {
if ($num_success >= $num_total) {
break; // 有效结果数量已达到,则跳出循环
}
// 如果 URL 不存在则新增 $value
if (!$this->urlExists($searchList, $value['url'])) {
$searchList[] = $value;
$num_success++;
}
}
}
return jok('临时资源获取成功',$searchList);
}
/**
* 全网搜索 该接口仅用于微信自动回复
*
* @return void
*/
public function Alone_search()
{
$searchdata = input('post.');
if (empty($searchdata['alone_title'])) {
return jerr("请输入要看的内容");
}
$title = $searchdata['alone_title'];
$map[] = ['status', '=', 1];
$map[] = ['is_delete', '=', 0];
$map[] = ['is_time', '=', 1];
$map[] = ['title|description', 'like', '%' . trim($title) . '%'];
$urls = $this->model->where($map)->field('source_id as id, title, url')->order('update_time', 'desc')->limit(5)->select()->toArray();
if (!empty($urls)) {
// 获取所有需要更新的ID
$ids = [];
foreach ($urls as $item) {
$ids[] = $item['id'];
}
// 更新数据库中的 update_time 字段
if (!empty($ids)) {
$this->model->whereIn('source_id', $ids)->update(['update_time' => time()]);
}
return jok('临时资源获取成功',$urls);
}
$searchList = []; //查询的结果集
$datas = []; //最终数据
$num_total = 2; //最多想要几条结果
$num_success = 0;
// 处理第2个源
foreach (source2($title) as $value) {
if ($num_success >= $num_total) {
break; // 有效结果数量已达到,则跳出循环
}
// 如果 URL 不存在则新增 $value
if (!$this->urlExists($searchList, $value['url'])) {
$searchList[] = $value;
$this->processUrl($value, $num_success, $datas);
}
}
// 处理第4个源
if ($num_success < $num_total) {
foreach (source4($title) as $value) {
if ($num_success >= $num_total) {
break; // 有效结果数量已达到,则跳出循环
}
// 如果 URL 不存在则新增 $value
if (!$this->urlExists($searchList, $value['url'])) {
$searchList[] = $value;
$this->processUrl($value, $num_success, $datas);
}
}
}
// 处理第3个源
if ($num_success < $num_total) {
foreach (source3($title) as $value) {
if ($num_success >= $num_total) {
break; // 有效结果数量已达到,则跳出循环
}
// 如果 URL 不存在则新增 $value
if (!$this->urlExists($searchList, $value['url'])) {
$searchList[] = $value;
$this->processUrl($value, $num_success, $datas);
}
}
}
// 处理第1个源 第一个源放最后
if ($num_success < $num_total) {
foreach (source1($title) as $value) {
if ($num_success >= $num_total) {
break; // 有效结果数量已达到,则跳出循环
}
// 如果 URL 不存在则新增 $value
if (!$this->urlExists($searchList, $value['url'])) {
$searchList[] = $value;
$this->processUrl($value, $num_success, $datas);
}
}
}
return jok('临时资源获取成功',$datas);
}
// 检查 URL 是否已存在(忽略查询参数)
public function urlExists($searchList, $urlToCheck) {
// 解析待检查的 URL
$parsedUrlToCheck = parse_url($urlToCheck);
foreach ($searchList as $item) {
$parsedUrl = parse_url($item['url']);
// 比较 scheme, host 和 path
if ($parsedUrlToCheck['scheme'] === $parsedUrl['scheme'] &&
$parsedUrlToCheck['host'] === $parsedUrl['host'] &&
$parsedUrlToCheck['path'] === $parsedUrl['path']) {
return true;
}
}
return false;
}
/**
* 临时资源转存
*
* @return void
*/
public function processUrl($value, &$num_success, &$datas)
{
$substring = strstr($value['url'], 's/');
if ($substring === false) {
return; // 模拟 continue 行为
}
$pwd_id = substr($substring, 2); // 去除 's/' 部分
$urlData = array(
'cookie' => $this->cookie,
'url' => $value['url'],
'expired_type' => 2,
'to_pdir_fid' => '61bad1e1380d47c78d6f5d86c877efb9', //存入目标文件
'ad_fid' => '3b57147245774d88bafba7f43152f4bd', //分享时带上这个文件
);
$res = curlHelper($this->url."/api/open/transfer", "POST", $urlData)['body'];
$res = json_decode($res, true);
if($res['code'] !== 200){
return; // 模拟 continue 行为
}
$patterns = '/^\d+\./';
$title = preg_replace($patterns, '', $value['title']);
// 添加资源到系统中
$data["title"] =$title;
$data["url"] =$res['data']['share_url'];
$data["is_type"] = determineIsType($data["url"]);
$data["fid"] =$res['data']['fid']??'';
$data["is_time"] = 1;
$data["update_time"] = time();
$data["create_time"] = time();
$this->model->insertGetId($data);
$datas[] =$data;
$num_success++;
}
/**
* 十分钟后清除临时资源
*
* @return void
*/
public function delete_search()
{
// 搜索条件
$map[] = ['is_time', '=', 1];
$map[] = ['update_time', '<=', time() - (30 * 60)];
$abc = $this->model->where($map)->select();
$this->model->where($map)->chunk(100, function ($order) {
foreach ($order as $value) {
$deles = $value->toArray();
$filelist = [];
$filelist[] = $deles['fid'];
$urlData = array(
'action_type' => 2,
'exclude_fids' => [],
'filelist' => $filelist,
);
$urlHeader = array(
'Accept: application/json, text/plain, */*',
'Accept-Language: zh-CN,zh;q=0.9',
'content-type: application/json;charset=UTF-8',
'sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
'sec-ch-ua-mobile: ?0',
'sec-ch-ua-platform: "Windows"',
'sec-fetch-dest: empty',
'sec-fetch-mode: cors',
'sec-fetch-site: same-site',
'Referer: https://pan.quark.cn/',
'Referrer-Policy: strict-origin-when-cross-origin',
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'cookie: '.$this->cookie,
);
$res = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file/delete?pr=ucpro&fr=pc&uc_param_str=", "POST", json_encode($urlData), $urlHeader)['body'];
$res = json_decode($res, true);
if($res['status'] == 200){
$this->model->where('fid', $deles['fid'])->delete();
}
}
});
return jok('临时资源删除成功',$abc);
}
public function alone_zhuanshu22222()
{
$list = [];
try {
$result = curlHelper("https://duanju.niurl.cn/api.php", "GET")['body'];
$list = json_decode($result, true);
$list = $list['data'];
} catch (Exception $e) {
}
if (count($list) > 100) {
$list = array_slice($list, 0, 100); // 如果超过100位,则截取前100位
}
$list = array_reverse($list);
foreach ($list as $key => $value){
//如果资源不是今天或者昨天的 就跳过 只采集今天昨天的资源
if($value['addtime'] != date('Y-m-d') && $value['addtime'] != date('Y-m-d', strtotime('-1 day'))){
continue;
}
//如已有此资源 跳过
$detail = $this->model->where('title', $value['name'])->find();
if(!empty($detail)){
continue;
}
$url = $value['url'];
$substring = strstr($url, 's/');
if ($substring !== false) {
$pwd_id = substr($substring, 2); // 去除 's/' 部分
} else {
//资源地址格式有误
continue;
}
$urlData = array(
'cookie' => Config('qfshop.quark_cookie'),
'url' => $url,
);
$res = curlHelper($this->url."/api/open/transfer", "POST", $urlData)['body'];
$res = json_decode($res, true);
if($res['code'] !== 200){
continue;
}
//添加资源到系统中
$data["title"] = $value['name'];
$data["url"] = $res['data']['share_url'];
$data["update_time"] = time();
$data["create_time"] = time();
$this->model->insertGetId($data);
}
return jok('123456');
}
public function alone_zhuanshu()
{
$list = [];
$add_num = 0;
$parameters = array(
'',
'',
'',
'6fbefc1f535f48a38cbb580f9553fcea', //4月夸克文件夹fid
'6da509da98124e1d98cd3aa70f1ad7fa',
'2b805566aee0430ca6a3a0ba995685bd',
'93996a5d87b64c36849c442374fd1bbf',
'499e29a766704e00ac0e6e3d1c7b252a',
'4c69edb70454496688813de3cd6a27f8',
'fed17385093446b78e8c2f286f683100',
'38233cc7b14148fea33ea9998c19dc22',
'70c3c5d7a1cc442eb998428893b00e94'
);
// try {
// $result = curlHelper("https://duanju.niurl.cn/api.php", "GET")['body'];
// $list = json_decode($result, true);
// $list = $list['data'];
// } catch (Exception $e) {
// }
try {
$list1 = [];
$result = curlHelper("https://kuoapp.com/duanju/get.php?day=".date('Y-m-d'), "GET")['body'];
$res1 = json_decode($result, true);
if (is_array($res1) && array_keys($res1) === range(0, count($res1) - 1)) {
$list1 = $res1;
}
$list2 = [];
$result = curlHelper("https://kuoapp.com/duanju/get.php?day=".date('Y-m-d', strtotime('-1 day')), "GET")['body'];
$res2 = json_decode($result, true);
if (is_array($res2) && array_keys($res2) === range(0, count($res2) - 1)) {
$list2 = $res2;
}
$list = array_merge($list1, $list2); // 合并两个数组
} catch (Exception $e) {
}
if (count($list) > 100) {
$list = array_slice($list, 0, 100); // 如果超过100位,则截取前100位
}
$list = array_reverse($list);
foreach ($list as $key => $value){
// 如果资源不是今天或者昨天的 就跳过 只采集今天昨天的资源
if($value['addtime'] != date('Y-m-d') && $value['addtime'] != date('Y-m-d', strtotime('-1 day'))){
continue;
}
//如已有此资源 跳过
$value['name'] = str_replace(["\u0000", "\x00", "\0"], '', $value['name']);
$detail = $this->model->where('title', $value['name'])->find();
if(!empty($detail)){
continue;
}
//整理数据 按天创建夸克文件夹
$dateString = $value['addtime']; // 哪一天的资源 如:2024-04-01
$timestamp = strtotime($dateString); // 将日期转换为时间戳
$newDateString = date('n月j日', $timestamp); // 夸克文件夹的名称 格式: 4月1日
$month = date('n', $timestamp); //月份 格式:4
$DaysModel = new DaysModel();
$fids = $DaysModel->where(["time"=>$dateString])->find();
if (!$fids){
//去创建文件夹获取fid
$urlData = array(
'dir_init_lock' => false,
'dir_path' => "",
'file_name' => $newDateString,
'pdir_fid' => $parameters[$month-1],
);
$urlHeader = array(
'Accept: application/json, text/plain, */*',
'Accept-Language: zh-CN,zh;q=0.9',
'content-type: application/json;charset=UTF-8',
'sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
'sec-ch-ua-mobile: ?0',
'sec-ch-ua-platform: "Windows"',
'sec-fetch-dest: empty',
'sec-fetch-mode: cors',
'sec-fetch-site: same-site',
'Referer: https://pan.quark.cn/',
'Referrer-Policy: strict-origin-when-cross-origin',
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'cookie: '.Config('qfshop.quark_cookie'),
);
$quark = curlHelper("https://drive-pc.quark.cn/1/clouddrive/file?pr=ucpro&fr=pc&uc_param_str=", "POST", json_encode($urlData), $urlHeader)['body'];
$quark = json_decode($quark, true);
if($quark['status'] !== 200){
continue;
}
$fid = $quark['data']['fid'];
$DaysModel->insert([
"fid" => $fid,
"time" => $dateString,
]);
$fids = $DaysModel->where(["time"=>$dateString])->find();
}
//最终我要获取 $fids['fid'] 这个参数
$url = $value['url'];
$substring = strstr($url, 's/');
if ($substring !== false) {
$pwd_id = substr($substring, 2); // 去除 's/' 部分
} else {
//资源地址格式有误
continue;
}
$urlData = array(
'cookie' => Config('qfshop.quark_cookie'),
'url' => $url,
'to_pdir_fid' => $fids['fid']??''
);
$res = curlHelper($this->url."/api/open/transfer", "POST", $urlData)['body'];
$res = json_decode($res, true);
if($res['code'] !== 200){
continue;
}
//添加资源到系统中
$data["title"] = $value['name'];
$data["url"] = $res['data']['share_url'];
$addtime = time();
if(!empty($value['addtime'])){
$addtime = $value['addtime'].' '.date('H:i');
$addtime = strtotime($addtime);
}
$data["update_time"] = $addtime;
$data["create_time"] = $addtime;
$data["source_category_id"] = 1;
$this->model->insertGetId($data);
$add_num++;
}
return jok(date('Y-m-d H:i').' Added number of resources',$add_num);
}
public function aaaa()
{
$dateString = date('Y-m-d');
$timestamp = strtotime($dateString); // 将日期转换为时间戳
$newDateString = date('n月j日', $timestamp); // 夸克文件夹的名称 格式: 6月1日
$month = date('n', $timestamp); //月份 格式:6
$list = [];
try {
$list1 = [];
$result = curlHelper("https://kuoapp.com/duanju/get.php?day=".date('Y-m-d'), "GET")['body'];
$res1 = json_decode($result, true);
if (is_array($res1) && array_keys($res1) === range(0, count($res1) - 1)) {
$list1 = $res1;
}
$list2 = [];
$result = curlHelper("https://kuoapp.com/duanju/get.php?day=".date('Y-m-d', strtotime('-1 day')), "GET")['body'];
$res2 = json_decode($result, true);
if (is_array($res2) && array_keys($res2) === range(0, count($res2) - 1)) {
$list2 = $res2;
}
$list = array_merge($list1, $list2); // 合并两个数组
} catch (Exception $e) {
}
return jok('123456',date('H:i'));
}
/**
* 在线观看接口 该接口仅用于微信自动回复
*
* @return void
*/
public function Alone_online()
{
if(!Config('qfshop.mp4_online')){
return jok('在线资源地址', []);
}
// 获取输入数据
$searchdata = input('');
if (empty($searchdata['alone_title'])) {
return jerr("请输入要看的内容");
}
$title = $searchdata['alone_title'];
// 定义请求头
$urlHeader = [
'cookie: thinkphp_show_page_trace=0|0; pwmd5=9c2c9cc26c93ed2d7560cfc4ae4d4ac3; userid=312; usergroup=1; username=18339988501; usertime=2024-08-06+15%3A41%3A26; usersin=04e882c0b3f468fba62a5d1f03174aea',
'Content-Type: application/json'
];
// 查询参数
$queryParams = [
'page' => 1,
'limit' => 1,
'name' => $title,
'type' => '',
];
// 发送GET请求
$res = curlHelper("https://vvc.qeduanju.cn/promote/list.html", "GET", json_encode([]), $urlHeader, $queryParams)['body'];
$res = json_decode($res, true);
// 检查响应并处理数据
if ($res && $res['code'] == 0 && $res['count'] > 0) {
$data = [];
$ids = [];
foreach ($res['data'] as $value) {
$data[] = [
'id' => $value['id'],
'title' => $value['name']
];
$ids[] = $value['id'];
}
// POST请求的数据
$urlData = [
"id" => $ids,
"pzid" => 283
];
// 发送POST请求
$res2 = curlHelper("https://vvc.qeduanju.cn/promote/dwz.html", "POST", json_encode($urlData), $urlHeader, $queryParams)['body'];
$res2 = json_decode($res2, true);
if ($res2 && $res2['code'] == 0) {
$finalData = [];
foreach ($res2['data'] as $value) {
foreach ($data as &$item) {
if ($item['id'] == $value['id']) {
$finalData[] = [
'title' => '【在线观看】'.$item['title'],
'url' => $value['url']
];
}
}
}
return jok('在线资源地址', $finalData);
}
}
// 如果没有找到匹配数据,返回空数据
return jok('在线资源地址', []);
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace app\api\controller;
use app\api\QfShop;
use app\model\Source as SourceModel;
use app\model\SourceCategory as SourceCategoryModel;
class Search extends QfShop
{
public function index()
{
$SourceModel = new SourceModel();
$data = $SourceModel->getList(input(''));
return jok('获取成功',$data);
}
public function getDetail()
{
$SourceModel = new SourceModel();
$data = $SourceModel->getDetail(input(''));
return jok('获取成功',$data);
}
public function getNew()
{
$SourceModel = new SourceModel();
$data = input('');
$data['page_size'] = $data['page_size']??20;
$data = $SourceModel->getNew($data);
return jok('获取成功',$data);
}
public function getHot()
{
$SourceModel = new SourceModel();
$data = $SourceModel->getHot(input(''));
return jok('获取成功',$data);
}
public function getCategory()
{
$SourceCategoryModel = new SourceCategoryModel();
$data = $SourceCategoryModel->getList(input(''));
return jok('获取成功',$data);
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace app\api\controller;
use think\App;
use app\api\QfShop;
use think\facade\Cache;
use Carbon\Carbon;
use quarkPlugin\QuarkPlugin;
use app\model\SourceCategory as SourceCategoryModel;
class Source extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
}
public function day()
{
// 当前日期
$currentDate = Carbon::today()->toDateString();
// 缓存键名
$cacheKey = 'api_alone_date_' . $currentDate;
// 检查缓存中是否存在该键
if (Cache::has($cacheKey)) {
return jerr("该接口今天已经执行过,请1小时后再试!");
}
Cache::set($cacheKey, time(), 2400);
$SourceCategoryModel = new SourceCategoryModel();
$map[] = ['is_update', '=', 1];
$data = $SourceCategoryModel->where($map)->column('source_category_id');
$ids = implode(',', $data);
$quarkPlugin = new QuarkPlugin();
$quarkPlugin->transferAll($ids,2);
return jok('已提交任务,稍后查看结果');
}
}
+150
View File
@@ -0,0 +1,150 @@
<?php
namespace app\api\controller;
use think\App;
use app\api\QfShop;
use app\model\User as Usermodel;
use app\model\Ads as Adsmodel;
use app\model\Feedback as FeedbackModel;
use app\model\SourceCategory as SourceCategoryModel;
class Tool extends QfShop
{
/**
* 系统配置参数
*
* @return void
*/
public function getConfig()
{
$data = [
'app_name' => Config('qfshop.app_name'),
'qcode' => getimgurl(Config('qfshop.qcode')),
'logo' => getimgurl(Config('qfshop.logo')),
'app_description' => Config('qfshop.app_description'),
];
return jok('获取成功',$data);
}
/**
* 上传图片
*
* @return void
*/
public function Upload()
{
// 获取当前登录的用户信息
$userInfo = $this->getLoginUser();
try {
$file = request()->file('file');
} catch (\Exception $error) {
return jerr('上传文件失败,请检查你的文件!');
}
$Usermodel = new Usermodel();
$data = $Usermodel->Upload($file, $userInfo);
return jok('上传成功',$data);
}
/**
* 根据广告位关键词获取广告图片列表
*
* @return void
*/
public function getAdsCode()
{
$Adsmodel = new Adsmodel();
$data = $Adsmodel->getAdsCode(input(''));
return jok('获取成功',$data);
}
/**
* 用户反馈
*
* @return void
*/
public function feedback()
{
$data = input('');
if (empty($data['content'])) {
return jerr("请输入要看的内容");
}
$FeedbackModel = new FeedbackModel();
$FeedbackModel->save(['content' => $data['content']]);
return jok('已反馈');
}
/**
* 获取首页排行榜数据
*
* @return void
*/
public function ranking()
{
$channel = input('channel');
$is_m = input('is_m')??0;
if (empty($channel)) {
return [];
}
// 使用 ThinkPHP 提供的 runtime_path() 函数获取 runtime 目录路径
$cacheDir = runtime_path('cache'); // runtime/cache 目录
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0755, true); // 确保缓存目录存在
}
// 根据 channel 值生成缓存文件名
$cacheFile = $cacheDir . "ranking_data_{$channel}.cache";
$cacheTime = 12*3600; // 缓存时间为 12 小时
// 检查缓存文件是否存在且在缓存时间内
if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $cacheTime) {
// 从缓存中读取数据
$data = json_decode(file_get_contents($cacheFile), true);
} else {
$data = [];
if (!empty($channel)) {
$queryParams = array(
"area" => "全部",
"year" => "全部",
"channel" => $channel,
"rank_type" => "最热",
"cate" => "全部",
"from" => "hot_page",
"start" => 0,
"hit" => Config('qfshop.ranking_num') ?? 1,
);
$res = curlHelper("https://biz.quark.cn/api/trending/ranking/getYingshiRanking", "GET", null, [], $queryParams)['body'];
$res = json_decode($res, true);
try {
foreach ($res['data']['hits']['hit']['item'] as $key => $value) {
$data[] = array(
"title" => $value['title'],
"src" => $value['src'],
"ranking" => $value['ranking'],
"hot_score" => $value['hot_score'],
"desc" => $value['desc'],
);
}
} catch (Exception $error) {
$data = [];
}
// 将数据缓存到文件中
file_put_contents($cacheFile, json_encode($data));
}
}
if($is_m==1){
$ranking_m_num = Config('qfshop.ranking_m_num') ?? 6;
$data = array_slice($data, 0, $ranking_m_num);
}
return jok('获取成功', $data);
}
}
+78
View File
@@ -0,0 +1,78 @@
<?php
namespace app\api\controller;
use think\App;
use app\api\QfShop;
use EasyWeChat\Factory;
use EasyWeChat\OfficialAccount\Application;
use app\model\Source as SourceModel;
class Wechat extends QfShop
{
/*
微信公众平台配置如下:
微信公众平台-基本配置-生成AppSecret并设置ip白名单
启用服务器配置即可
URL:你的域名/api/wechat/serve
Token:自行生成
EncodingAESKey:随机生成即可
消息加解密方式:推荐即可
*/
private $config = [
'app_id' => 'wx7d0373771cf5e395',//公众号appid
'secret' => '3e9fefc1ccc573afb4141bf2e4e6ac3b',//公众号secret
'token' => 'aDA3Ve61uNpn5xXKgPm49wtqL2ZlvDac', //Token 自行生成32字符串 英文或数字
'aes_key' => 'r0HkOAEGKkaYdJLvaCy9ldtgzhMzDUJYPoLxUc62OMA' //微信公众平台生成后填写到这里
];
public function serve()
{
// 创建一个微信公众账号实例,使用指定的配置
$app = Factory::officialAccount($this->config);
// 设置消息处理回调函数
$app->server->push(function ($message) {
// 检查用户消息内容中是否包含“搜剧”关键字
if (strpos($message['Content'], '搜') !== false) {
// 去除“搜剧”关键字和空格,提取用户输入的剧名
$newString = str_replace(['搜剧', ' '], '', $message['Content']);
$newString = str_replace(['搜', ' '], '', $message['Content']);
// 实例化资源模型,并搜索匹配的剧名
$SourceModel = new SourceModel();
$list = $SourceModel->where('title', 'like', '%' . $newString . '%')->limit(5)->select();
// 构建回复内容
if (!$list->isEmpty()) {
$content = "";
foreach ($list as $item) {
if ($content) {
$content = $content."\n".$item['title']."\n".$item['url']."\n --------------------";
} else {
$content = $item['title']."\n".$item['url']."\n --------------------";
}
}
// 添加操作步骤说明
$content = $content."\n 步骤:点击上方链接-打开网盘-点立即查看-点右下角保存-打开文件-按文件名排序即可从第一集开始-自动-全集播放";
} else {
// 如果没有找到匹配的剧名,提示用户减少关键词尝试搜索
$content = "未找到,减少关键词尝试搜索。";
}
return $content; // 返回匹配结果或提示信息
}
// 如果不匹配条件,返回空字符串或不做任何回复
return '';
});
// 开始处理微信服务器的请求并返回响应
$response = $app->server->serve();
$response->send(); // 发送响应
}
}
+4
View File
@@ -0,0 +1,4 @@
[2024-04-07T15:46:10.672053+08:00] EasyWeChat.DEBUG: Request received: {"method":"GET","uri":"https://pan.xinyuedh.com/api/wechat?s=%2Fapi%2Fwechat","content-type":null,"content":""}
[2024-04-07T15:46:10.719415+08:00] EasyWeChat.DEBUG: Server response created: {"content":"success"}
[2024-04-07T15:46:38.369913+08:00] EasyWeChat.DEBUG: Request received: {"method":"GET","uri":"https://pan.xinyuedh.com/api/wechat?s=%2Fapi%2Fwechat","content-type":null,"content":""}
[2024-04-07T15:46:38.377289+08:00] EasyWeChat.DEBUG: Server response created: {"content":"success"}
+973
View File
@@ -0,0 +1,973 @@
<?php
/**
* 输出正常JSON
*
* @param string 提示信息
* @param array 输出数据
* @return json
*/
function jok($message = 'success', $data = null)
{
header("content-type:application/json;chartset=uft-8");
if ($data) {
echo json_encode(["code" => 200, "message" => $message, 'data' => $data]);
} else {
echo json_encode(["code" => 200, "message" => $message, 'data' => $data??'']);
}
die;
}
/**
* 输出错误JSON
*
* @param string 错误信息
* @param int 错误代码
* @return json
*/
function jerr($message = 'error', $code = 500)
{
header("content-type:application/json;chartset=uft-8");
echo json_encode(["code" => $code, "message" => $message]);
die;
}
/**
* 密码+盐 加密
*
* @param string 明文密码
* @param string 盐
* @return string
*/
function encodePassword($password, $salt)
{
return sha1($password . $salt . $password . $salt);
}
/**
* 密码校验 6-16
*
* @param string 明文密码
* @return boolean 是否校验通过
*/
function isValidPassword($password)
{
return preg_match('/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?!.*\s).{6,}/', $password);
}
/**
* 获取随机字符
*
* @param int $len
* @return void
*/
function getRandString($len)
{
$string = '';
$randString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for ($i = 0; $i < $len; $i++) {
$string .= $randString[rand(0, strlen($randString) - 1)];
}
return $string;
}
/**
* 生成唯一会议编码
* @param string $prefix 头部
* @return string
*/
function get_order_no($prefix = 'QF')
{
$order_no = $prefix;
$order_no .= mb_strtoupper(dechex(date('m')), 'utf-8');
$order_no .= date('d') . mb_substr(time(), -5, null, 'utf-8');
$order_no .= mb_substr(microtime(), 2, 5, 'utf-8');
return $order_no;
}
/**
* 获取随机字母
*
* @param int 长度
* @return string
*/
function getRandChar($len)
{
$string = '';
$randString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for ($i = 0; $i < $len; $i++) {
$string .= $randString[rand(0, strlen($randString) - 1)];
}
return $string;
}
/**
* 驼峰转下划线
* @param $camelCaps
* @param string $separator
* @return string
*/
function uncamelize($camelCaps, $separator = '_')
{
return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
}
/**
* 遍历类的方法
*
* @param string 指定的类名称
* @return array
*/
function getClassMethods($class)
{
$array_result = [];
$array_all = get_class_methods($class);
if ($parent_class = get_parent_class($class)) {
$array_parent = get_class_methods($parent_class);
$array_result = array_diff($array_all, $array_parent);
} else {
$array_result = $array_all;
}
return $array_result;
}
/**
* 获取包含协议和端口的域名
*
* @return string
*/
function getFullDomain()
{
// return ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? $_SERVER['REQUEST_SCHEME']) . "://" . $_SERVER['HTTP_HOST'];
return "http://" . $_SERVER['HTTP_HOST'];
}
/**
* 图片地址转绝对路径
*
* @return string
*/
function getimgurl($img)
{
$result = '';
if($img){
// $url = ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? $_SERVER['REQUEST_SCHEME']) . "://" . $_SERVER['HTTP_HOST'];
$url = "http://" . $_SERVER['HTTP_HOST'];
if(is_array($img)){
$result = [];
foreach ($img as $key => $value) {
if(!preg_match("/^http(s)?:\\/\\/.+/", $value)){
$result[] = $url.$value;
}else{
$result[] = $value;
}
}
}else{
if(!preg_match("/^http(s)?:\\/\\/.+/", $img)){
$result = $url.$img;
}else{
$result = $img;
}
}
}
return $result;
}
/**
* 替换编辑器内容中的文件地址
* @param string $content 编辑器内容
* @return string
*/
function app_replace_content_file_url($content)
{
\phpQuery::newDocumentHTML($content);
$pq = pq(null);
$domain = request()->host();
$images = $pq->find("img");
if ($images->length) {
foreach ($images as $img) {
$img = pq($img);
$imgSrc = $img->attr("src");
if(!preg_match("/^http(s)?:\\/\\/.+/", $imgSrc)){
$img->attr("src", getimgurl($imgSrc));
}
}
}
$links = $pq->find("a");
if ($links->length) {
foreach ($links as $link) {
$link = pq($link);
$href = $link->attr("href");
if(!preg_match("/^http(s)?:\\/\\/.+/", $href)){
$img->attr("href", getimgurl($imgSrc));
}
}
}
$content = $pq->htmlOuter();
\phpQuery::$documents = null;
return $content;
}
/**
* 获取客户端IP
*
* @return string
*/
function getClientIp()
{
foreach (array(
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR'
) as $key) {
if (array_key_exists($key, $_SERVER)) {
foreach (explode(',', $_SERVER[$key]) as $ip) {
$ip = trim($ip);
if ((bool) filter_var(
$ip,
FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6
// FILTER_FLAG_NO_PRIV_RANGE |
// FILTER_FLAG_NO_RES_RANGE
)) {
return $ip;
}
}
}
}
return null;
}
/**
* 取文本中间
*
* @param string 原始字符串
* @param string 左边字符串
* @param string 右边字符串
* @return string
*/
function getSubstr($str, $leftStr, $rightStr)
{
$left = strpos($str, $leftStr);
$right = strpos($str, $rightStr, $left);
if ($left < 0 or $right < $left) return '';
return substr($str, $left + strlen($leftStr), $right - $left - strlen($leftStr));
}
/**
* 获取操作系统
*
* @return string
*/
function getOs()
{
if (empty($_SERVER['HTTP_USER_AGENT'])) {
return 'Other';
}
$agent = strtolower($_SERVER['HTTP_USER_AGENT']);
if (strpos($agent, 'windows nt')) {
$platform = 'Windows';
} elseif (strpos($agent, 'macintosh')) {
$platform = 'MacOS';
} elseif (strpos($agent, 'ipod')) {
$platform = 'iPod';
} elseif (strpos($agent, 'ipad')) {
$platform = 'iPad';
} elseif (strpos($agent, 'iphone')) {
$platform = 'iPhone';
} elseif (strpos($agent, 'android')) {
$platform = 'Android';
} elseif (strpos($agent, 'unix')) {
$platform = 'Unix';
} elseif (strpos($agent, 'linux')) {
$platform = 'Linux';
} else {
$platform = 'Other';
}
return $platform;
}
/**
* 获取浏览器
*
* @return void
*/
function getBrowser()
{
if (empty($_SERVER['HTTP_USER_AGENT'])) {
return 'Unknown';
}
$agent = $_SERVER["HTTP_USER_AGENT"];
if (strpos($agent, 'MSIE') !== false || strpos($agent, 'rv:11.0')) //ie11判断
{
return "IE";
} else if (strpos($agent, 'Firefox') !== false) {
return "Firefox";
} else if (strpos($agent, 'Chrome') !== false) {
return "Chrome";
} else if (strpos($agent, 'Opera') !== false) {
return 'Opera';
} else if ((strpos($agent, 'Chrome') == false) && strpos($agent, 'Safari') !== false) {
return 'Safari';
} else {
return 'Unknown';
}
}
/**
* 是否手机请求
*
* @return boolean
*/
function isMobileRequest()
{
$_SERVER['ALL_HTTP'] = isset($_SERVER['ALL_HTTP']) ? $_SERVER['ALL_HTTP'] : '';
$mobile_browser = '0';
if (preg_match('/(up.browser|up.link|mmp|symbian|smartphone|midp|wap|phone|iphone|uc|qq|wechat|micro|messenger|ipad|ipod|android|xoom)/i', strtolower($_SERVER['HTTP_USER_AGENT'])))
$mobile_browser++;
if ((isset($_SERVER['HTTP_ACCEPT'])) and (strpos(strtolower($_SERVER['HTTP_ACCEPT']), 'application/vnd.wap.xhtml+xml') !== false))
$mobile_browser++;
if (isset($_SERVER['HTTP_X_WAP_PROFILE']))
$mobile_browser++;
if (isset($_SERVER['HTTP_PROFILE']))
$mobile_browser++;
$mobile_ua = strtolower(substr($_SERVER['HTTP_USER_AGENT'], 0, 4));
$mobile_agents = array(
'w3c ', 'acs-', 'alav', 'alca', 'amoi', 'audi', 'avan', 'benq', 'bird', 'blac',
'blaz', 'brew', 'cell', 'cldc', 'cmd-', 'dang', 'doco', 'eric', 'hipt', 'inno',
'ipaq', 'java', 'jigs', 'kddi', 'keji', 'leno', 'lg-c', 'lg-d', 'lg-g', 'lge-',
'maui', 'maxo', 'midp', 'mits', 'mmef', 'mobi', 'mot-', 'moto', 'mwbp', 'nec-',
'newt', 'noki', 'oper', 'palm', 'pana', 'pant', 'phil', 'play', 'port', 'prox',
'qwap', 'sage', 'sams', 'sany', 'sch-', 'sec-', 'send', 'seri', 'sgh-', 'shar',
'sie-', 'siem', 'smal', 'smar', 'sony', 'sph-', 'symb', 't-mo', 'teli', 'tim-',
'tosh', 'tsm-', 'upg1', 'upsi', 'vk-v', 'voda', 'wap-', 'wapa', 'wapi', 'wapp',
'wapr', 'webc', 'winw', 'winw', 'xda', 'xda-'
);
if (in_array($mobile_ua, $mobile_agents))
$mobile_browser++;
if (strpos(strtolower($_SERVER['ALL_HTTP']), 'operamini') !== false)
$mobile_browser++;
// Pre-final check to reset everything if the user is on Windows
if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows') !== false)
$mobile_browser = 0;
// But WP7 is also Windows, with a slightly different characteristic
if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows phone') !== false)
$mobile_browser++;
if ($mobile_browser > 0)
return true;
else
return false;
}
/**
* 身份证号验证
* @param $id
* @return bool
*/
function isIDCard($id)
{
$id = strtoupper($id);
$regx = "/(^\d{15}$)|(^\d{17}([0-9]|X)$)/";
$arr_split = array();
if (!preg_match($regx, $id)) {
return FALSE;
}
if (15 == strlen($id)) //检查15位
{
$regx = "/^(\d{6})+(\d{2})+(\d{2})+(\d{2})+(\d{3})$/";
@preg_match($regx, $id, $arr_split);
//检查生日日期是否正确
$dtm_birth = "19" . $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
if (!strtotime($dtm_birth)) {
return FALSE;
} else {
return TRUE;
}
} else { //检查18位
$regx = "/^(\d{6})+(\d{4})+(\d{2})+(\d{2})+(\d{3})([0-9]|X)$/";
@preg_match($regx, $id, $arr_split);
$dtm_birth = $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
if (!strtotime($dtm_birth)) //检查生日日期是否正确
{
return FALSE;
} else {
//检验18位身份证的校验码是否正确。
//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
$arr_int = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
$arr_ch = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
$sign = 0;
for ($i = 0; $i < 17; $i++) {
$b = (int) $id[$i];
$w = $arr_int[$i];
$sign += $b * $w;
}
$n = $sign % 11;
$val_num = $arr_ch[$n];
if ($val_num != substr($id, 17, 1)) {
return FALSE;
} else {
return TRUE;
}
}
}
}
/**
* 是否是整数
*
* @param string 输入内容
* @return boolean
*/
function isInteger($input)
{
return (ctype_digit(strval($input)));
}
/**
* 获取一个key摘要
*
* @param string 原始key
* @return string
*/
function getTicket($key)
{
return sha1($key . (env('SYSTEM_SALT') ?? 'qfshop') . $key);
}
/**
* 通用CURL请求函数
*
* @param string $url URL地址
* @param string $method 请求方法, 支持GET/POST/PUT/DELETE/PATCH/TRACE/OPTIONS/HEAD 默认POST
* @param mixed $data 请求数据包体
* @param array $header 请求头 数组
* @param array $queryParams 查询参数 数组
* @param string $cookies 请求COOKIES字符串
* @param int $timeout 请求超时时间,默认30秒
* @return array 响应数组,包括header, body, detail, error
*/
function curlHelper($url, $method = 'POST', $data = null, $header = [], $queryParams = "", $cookies = "", $timeout = 60)
{
// 构建查询参数
if (!empty($queryParams)) {
$queryString = http_build_query($queryParams);
$url .= '?' . $queryString;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_COOKIE, $cookies);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // 设置超时时间
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置连接超时时间
// 根据请求方法设置选项
switch (strtoupper($method)) {
case "POST":
curl_setopt($ch, CURLOPT_POST, true);
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
break;
case "PUT":
case "DELETE":
case "PATCH":
case "TRACE":
case "OPTIONS":
case "HEAD":
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
break;
case "GET":
default:
curl_setopt($ch, CURLOPT_HTTPGET, true);
break;
}
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
curl_close($ch);
return ['error' => $error];
}
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$output = [
'header' => substr($response, 0, $headerSize),
'body' => substr($response, $headerSize),
'detail' => curl_getinfo($ch)
];
curl_close($ch);
return $output;
}
/**
* 模拟表单上传文件请求
* @param $$url 提交地址
* @param $data 提交数据
* @param $cookies 如设置了Content-Type将被自动覆写为formdata
* ex.
* $data = ['file'=>new \CURLFile(realpath($file_dir)),appid"=>"1234"];
* $result = curl_form($url,$data);
* @return mixed
*/
function curlForm($url, $data = null, $header = [], $cookies = "")
{
$header[] = 'Content-Type: multipart/form-data';
return curlHelper($url, "POST", $data, $header, $cookies);
}
/**
* 多维数组合并(支持多数组)
* @param arraylist arrayMergeMulti(['1'=>'1','2'=>'2','3'=>'3'],['4'=>'4','5'=>'5','6'=>'6'])
* @return array
*/
function arrayMergeMulti()
{
//获取当前方法捕获到的所有参数数组
$args = func_get_args();
$array = [];
foreach ($args as $arg) {
if (is_array($arg)) {
foreach ($arg as $k => $v) {
if (is_array($v)) {
$array[$k] = isset($array[$k]) ? $array[$k] : [];
$array[$k] = arrayMergeMulti($array[$k], $v);
} else {
$array[$k] = $v;
}
}
}
}
return $array;
}
/**
* 对查询结果集进行排序
* @access public
* @param array $list 查询结果
* @param string $field 排序的字段名
* @param array $sortBy 排序类型
* asc正向排序 desc逆向排序 nat自然排序
* @return array|bool
*/
function listSortBy($list, $field, $sortBy = 'asc')
{
if (is_array($list)) {
$refer = $resultSet = [];
foreach ($list as $i => $data) {
$refer[$i] = &$data[$field];
}
switch ($sortBy) {
case 'asc': // 正向排序
asort($refer);
break;
case 'desc': // 逆向排序
arsort($refer);
break;
case 'nat': // 自然排序
natcasesort($refer);
break;
}
foreach ($refer as $key => $val) {
$resultSet[] = &$list[$key];
}
return $resultSet;
}
return false;
}
/**
* 格式化字节大小
* @param number $size 字节数
* @param int $float 小数保留位数
* @param string $delimiter 数字和单位分隔符
* @return string 格式化后的带单位的大小
*/
function formatBytes($size, $float = 2, $delimiter = '')
{
$units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
return round($size, $float) . $delimiter . $units[$i];
}
/**
* 生成标准UUID
*
* @return string
*/
function getUuid()
{
mt_srand((float) microtime() * 10000);
$uuid = sprintf('%04X%04X-%04X-%04X-%04X-%04X%04X%04X', mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(16384, 20479), mt_rand(32768, 49151), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535));
return $uuid;
}
/**
* 判断是否为空参数
* @param mixed $parm
* @return bool
*/
function is_empty_parm(&$parm)
{
return !(isset($parm) && '' !== $parm);
}
/**
* 返回当前账号openid
* $openid wxapp_openid wechat_openid
* @return string
*/
function get_client_openid($user_id, $openid)
{
return \think\facade\Db::name('user')->where('user_id', $user_id)->value($openid);
}
/**
* 产生数字与字母混合随机字符串
* @param int $len 数值长度,默认6位
* @return string
*/
function get_randstr($len = 6)
{
$chars = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2',
'3', '4', '5', '6', '7', '8', '9',
];
$charsLen = count($chars) - 1;
shuffle($chars);
$output = '';
for ($i = 0; $i < $len; $i++) {
$output .= $chars[mt_rand(0, $charsLen)];
}
return $output;
}
/**
* 产生随机数值
* @param int $len 数值长度,默认8位
* @return string
*/
function rand_number($len = 8)
{
$chars = str_repeat('123456789', 3);
if ($len > 10) {
$chars = str_repeat($chars, $len);
}
$chars = str_shuffle($chars);
return mb_substr($chars, 0, $len, 'utf-8');
}
/**
* 智能字符串模糊化
* @param string $str 被模糊的字符串
* @param int $len 模糊的长度
* @return string
*/
function auto_hid_substr(string $str, $len = 3)
{
if (empty($str)) {
return null;
}
$sub_str = mb_substr($str, 0, 1, 'utf-8');
for ($i = 0; $i < $len; $i++) {
$sub_str .= '*';
}
if (mb_strlen($str, 'utf-8') <= 2) {
$str = $sub_str;
}
$sub_str .= mb_substr($str, -1, 1, 'utf-8');
return $sub_str;
}
/**
* 多维数组,根据某个特定字段过滤重复值
* @return array
*/
function assoc_unique($arr, $key) {
$tmp_arr = array();
foreach ($arr as $k => $v) {
if (in_array($v[$key], $tmp_arr)) {//搜索$v[$key]是否在$tmp_arr数组中存在,若存在返回true
unset($arr[$k]);
} else {
$tmp_arr[] = $v[$key];
}
}
sort($arr); //sort函数对数组进行排序
return $arr;
}
function getDom($url)
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$html = curl_exec($ch);
curl_close($ch);
$dom = new DOMDocument();
@$dom->loadHTML($html);
return $dom;
}
/**
* 过滤标点符号并提取词语
*
* @param array $result 分词结果
* @return array 过滤后的词汇
*/
function filterAndExtractWords(array $result)
{
// 定义要过滤掉的符号,包括标点符号和其他符号
$pattern = '/[\p{P}\p{S}]/u';
// 提取词语、过滤掉符号并删除空的词语
$filteredWords = array();
foreach ($result as $item) {
$word = preg_replace($pattern, '', $item[0]);
// 只保留非空的词汇
if (!empty($word)) {
$filteredWords[] = $word;
}
}
return $filteredWords;
}
/**
* 高亮显示关键词
* @param string $title 原始标题
* @param string $searchTitle 搜索标题
* @return string 带有高亮的标题
*/
function highlightKeywords($title, $searchTitle)
{
// 使用正则表达式来高亮所有关键词
foreach ($searchTitle as $keyword) {
$title = preg_replace('/(' . preg_quote($keyword, '/') . ')/i', '<span>$1</span>', $title);
}
return $title;
}
/**
* 判断是哪个网盘
* @return array
*/
function determineIsType($url) {
// 判断 $url 中包含的域名并返回对应的 is_type
if (strpos($url, 'alipan.com') !== false) {
return 1;
} elseif (strpos($url, 'baidu.com') !== false) {
return 2;
} elseif (strpos($url, 'uc.cn') !== false) {
return 3;
} elseif (strpos($url, 'xunlei.com') !== false) {
return 4;
} else {
// 默认值是夸克网盘,返回 0
return 0;
}
}
/**
* 网络资源搜索源一
* @return array
*/
function source1($title)
{
$d = [];
return $d;
}
/**
* 网络资源搜索源二(5条线路)
* 每个线路只取第一个
* @return array
*/
function source2($title)
{
$urlDefault = "http://s.kkkob.com"; //http://s.kkkob.com
$url2 = [];
$res = curlHelper($urlDefault."/v/api/getToken", "GET")['body'];
$res = json_decode($res, true);
$token = $res['token'] ?? '';
if(empty($token)){
return $url2;
}
$urlData = array(
'name' => $title,
'token' => $token
);
$urlHeader = array('Content-Type: application/json');
// 定义正则表达式模式
$pattern = '/https:\/\/pan\.quark\.cn\/[^\s]*/';
//线路2
$res = curlHelper($urlDefault."/v/api/getJuzi", "POST", json_encode($urlData), $urlHeader)['body'];
$res = json_decode($res, true);
if (!empty($res['list'] ?? [])) {
foreach ($res['list'] as $key => $value) {
if(preg_match($pattern, $value['answer'], $matches)){
// 匹配成功,$matches[0] 包含了匹配到的链接
$link = $matches[0];
$url2[] = [
'title' => preg_replace('/\s*[\(]?(夸克)?[\)]?\s*/u', '', $value['question']),
'url' => $link
];
break;
}
}
}
if(!empty($url2)){
return $url2;
}
//线路4
$res = curlHelper($urlDefault."/v/api/getXiaoyu", "POST", json_encode($urlData), $urlHeader)['body'];
$res = json_decode($res, true);
if (!empty($res['list'] ?? [])) {
foreach ($res['list'] as $key => $value) {
if(preg_match($pattern, $value['answer'], $matches)){
// 匹配成功,$matches[0] 包含了匹配到的链接
$link = $matches[0];
$url2[] = [
'title' => preg_replace('/\s*[\(]?(夸克)?[\)]?\s*/u', '', $value['question']),
'url' => $link
];
break;
}
}
}
// //线路1
// $res = curlHelper($urlDefault."/v/api/search", "POST", json_encode($urlData), $urlHeader)['body'];
// $res = json_decode($res, true);
// if (!empty($res['list'] ?? [])) {
// $item = $res['list'][0];
// // 使用正则表达式进行匹配
// if (preg_match($pattern, $item['answer'], $matches)) {
// // 匹配成功,$matches[0] 包含了匹配到的链接
// $link = $matches[0];
// $url2[] = [
// 'title' => '①'.preg_replace('/\s*[\(]?(夸克)?[\)]?\s*/u', '', $item['question']),
// 'url' => $link
// ];
// }
// }
return $url2;
}
/**
* 网络资源搜索源三
* @return array
*/
function source3($title)
{
$url3 = [];
$url = 'https://www.qileso.com/tag/quark?s='.$title;
$dom = getDom($url);
$finder = new DomXPath($dom);
// 查询class值为list-group post-list mt-3的元素
$nodes =$finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' list-group post-list mt-3 ')]//a");
if ($nodes->length > 0) {
$firstNode =$nodes->item(0);
$href = $firstNode->getAttribute('href');
$dom = getDom($href);
$finder = new DomXPath($dom);
// 查询包含特定前缀的href属性的所有<a>标签
$nodes =$finder->query("//@*[starts-with(., 'https://pan.quark.cn/s/')]");
if ($nodes->length > 0) {
$firstNode =$nodes->item(0);
$value = $firstNode->value;
// 查询<title>元素
$nodes =$finder->query("/html/head/title");
if ($nodes->length > 0) {
$titleNode =$nodes->item(0);
$titleText =$titleNode->textContent;
// 去掉 " - 奇乐搜" 部分
$title = preg_replace('/ - 奇乐搜|网盘|夸克/', '', $titleText);
}
$url3[] = [
'title' => '②'.$title,
'url' => $value
];
}
}
return $url3;
}
/**
* 网络资源搜索源四
* @return array
*/
function source4($title)
{
$url = 'https://www.pansearch.me/search?keyword='.urlencode($title).'&pan=quark';
$dom = getDom($url);
$finder = new DomXPath($dom);
// 使用 XPath 查询选择具有特定类名的元素
$nodes =$finder->query('//div[contains(concat(" ", normalize-space(@class), " "), " whitespace-pre-wrap ") and contains(concat(" ", normalize-space(@class), " "), " break-all ")]');
$results = [];
foreach ($nodes as $node) {
// 获取元素的内容,包括其子元素
$content = $node->textContent;
// Initialize an associative array to store parsed data
$parsedItem = [
'title' => '',
'url' => ''
];
// Use regular expressions to extract the title and url
if (preg_match('/名称:(.*?)\n\n描述:/s', $content, $titleMatch)) {
$parsedItem['title'] = '「推荐」'.trim($titleMatch[1]);
}
if (preg_match('/链接:(https:\/\/pan\.quark\.cn\/s\/[a-zA-Z0-9]+)/', $content, $urlMatch)) {
$parsedItem['url'] = trim($urlMatch[1]);
}
if ($parsedItem['title'] && $parsedItem['url']) {
$results[] = $parsedItem;
}
if (count($results) >= 3) {
break;
}
}
return $results;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
// 事件定义文件
return [
'bind' => [
],
'listen' => [
'AppInit' => [],
'HttpRun' => [],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
'subscribe' => [
],
];
+45
View File
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace app\index;
use think\App;
use EasyWeChat\Factory;
use app\model\Conf as ConfModel;
use app\model\User as UserModel;
/**
* 控制器基础类
*/
abstract class QfShop
{
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
$this->confModel = new ConfModel();
$configs = $this->confModel->select()->toArray();
$c = array_column($configs, 'conf_value', 'conf_key');
config($c, 'qfshop');
}
}
+32
View File
@@ -0,0 +1,32 @@
// <?php
// namespace app\index\controller;
// use app\index\QfShop;
// use think\facade\View;
// class Error extends QfShop
// {
// public function __call($method, $args)
// {
// $error = $this->authorize();
// if ($error) {
// return $error;
// }
// View::assign('wechat', $this->wechat);
// if (file_exists(app_path() . "/view/" . strtolower($this->request->controller()) . "/" . $method . ".html")) {
// if (key_exists('callback', $args)) {
// View::assign('callback', $args['callback']);
// } else {
// View::assign('callback', '/admin');
// }
// return View::fetch();
// } else {
// return 404;
// }
// }
// public static function show($msg = null)
// {
// View::assign('msg', $msg);
// return View::fetch("/error");
// }
// }
+164
View File
@@ -0,0 +1,164 @@
<?php
namespace app\index\controller;
use think\App;
use think\facade\View;
use think\facade\Request;
use think\facade\Cache;
use app\index\QfShop;
use app\model\Source as SourceModel;
use app\model\SourceCategory as SourceCategoryModel;
class Index extends QfShop
{
public function __construct(App $app)
{
parent::__construct($app);
$this->SourceModel = new SourceModel();
$this->SourceCategoryModel = new SourceCategoryModel();
}
/**
* @description: 首页
* @param {*}
* @return {*}
*/
public function index()
{
$rankList = $this->SourceCategoryModel->field('name,image')->where([['status','=',0],['is_sys','=',1]])->order('sort desc')->select();
$newList = [];
if(config("qfshop.ranking_type") == 0 && config("qfshop.home_new") == 0){
//最新榜
$map[] = ['status', '=', 1];
$map[] = ['is_time', '=', 0];
$map[] = ['is_delete', '=', 0];
$newList = $this->SourceModel->order(['create_time' => 'desc'])
->field('title,create_time as time')
->where($map)
->limit(Config('qfshop.ranking_num') ?? 1)
->select()->each(function($item,$key){
$item['times'] = substr($item['time'], 5, 5);
unset($item['time']);
return $item;
});
}
View::assign('newList', $newList);
View::assign('config', config("qfshop"));
View::assign('rankList', $rankList);
View::assign('fixed', 1);
View::assign('category_id', 0);
return View::fetch('/news/index');
}
/**
* @description: 搜索列表
* @param {*}
* @return {*}
*/
public function list($name,$page=1,$cate='')
{
$data['page_no'] = $page;
$data['page_size'] = 40;
$data['title'] = $name;
$data['category_id'] = $cate;
$list = $this->SourceModel->getList($data);
$rankList = $this->SourceCategoryModel->field('name,image')->where([['status','=',0],['is_sys','=',1]])->order('sort desc')->select();
$category = $this->SourceCategoryModel->field('name,source_category_id as id')->where([['status','=',0]])->order('sort desc')->select();
View::assign('rankList', $rankList);
View::assign('category', $category);
View::assign('list', $list);
View::assign('config', config("qfshop"));
View::assign('keyword', $data['title']);
View::assign('page_size', $data['page_size']);
View::assign('page_no', $data['page_no']);
View::assign('category_id', $data['category_id']);
return View::fetch('/news/list');
}
/**
* @description: 详情
* @param {*}
* @return {*}
*/
public function detail($id)
{
if(empty($id)){
return redirect('/');
}
$data['id'] = $id;
$detail = $this->SourceModel->getDetail($data);
if(empty($detail)){
return redirect('/');
}
$rankList = $this->SourceCategoryModel->field('name,image')->where([['status','=',0],['is_sys','=',1]])->order('sort desc')->select();
View::assign('rankList', $rankList);
View::assign('detail', $detail);
View::assign('config', config("qfshop"));
View::assign('category_id', 0);
return View::fetch('/news/detail');
}
public function show()
{
$data = input('');
$this->SourceModel = new SourceModel();
// 搜索条件
$map = [];
$map[] = ['status', '=', 1];
$map[] = ['is_time', '=', 0];
if(!empty($data['type'])){
// 将 $data['type'] 转换为时间戳
$dayStart = strtotime($data['type']);
$dayEnd = $dayStart + 86400; // 86400 秒 = 24 小时
// 添加日期范围条件,只统计所选日期的记录
$map[] = ['create_time', 'between', [$dayStart, $dayEnd]];
View::assign('day', date('n月j日', $dayStart));
}else{
// 获取今天的时间戳范围
$todayStart = strtotime(date('Y-m-d'));
$todayEnd = $todayStart + 86400; // 86400 秒 = 24 小时
// 添加日期范围条件,只统计今天的记录
$map[] = ['create_time', 'between', [$todayStart, $todayEnd]];
View::assign('day',date('n月j日'));
}
$result = $this->SourceModel->field('source_id as id,source_category_id,title,url,create_time as time,is_time')->where($map)->select()->each(function($item,$key){
$item['times'] = substr($item['time'], 0, 10);
unset($item['time']);
return $item;
})->toArray();
View::assign('list', $result);
return View::fetch();
}
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace app\index\controller;
use think\Response;
use think\facade\Request;
use app\model\Source as SourceModel;
class Sitemap
{
public function index()
{
// 检查是否有缓存
$sitemap = cache('sitemap');
if (!$sitemap) {
$SourceModel = new SourceModel();
$map[] = ['status', '=', 1];
$map[] = ['is_delete', '=', 0];
$map[] = ['is_time', '=', 0];
$urls = $SourceModel->where($map)->field('source_id, update_time')->order('update_time', 'desc')->limit(10000)->select();
// 创建 XML 内容
$xml = '<?xml version="1.0" encoding="UTF-8"?>';
$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
$xml .= '<url>';
$xml .= '<loc>'.Request::domain().'</loc>'; // 网站 URL
$xml .= '<lastmod>'.date('Y-m-d').'</lastmod>'; // 最后修改时间
$xml .= '<changefreq>daily</changefreq>'; // 页面更新频率
$xml .= '<priority>1.0</priority>'; // 优先级
$xml .= '</url>';
foreach ($urls as $url) {
$xml .= '<url>';
$xml .= '<loc>'.Request::domain().'/d/'.$url['source_id'].'.html</loc>';
$xml .= '<lastmod>' . date('Y-m-d', strtotime($url['update_time'])) . '</lastmod>';
$xml .= '<priority>0.8</priority>';
$xml .= '</url>';
}
$xml .= '</urlset>';
// 缓存 sitemap 1 小时 3600
cache('sitemap', $xml, 86400);
$sitemap = $xml;
}
return Response::create($sitemap, 'xml')->header(['Content-Type' => 'application/xml']);
}
}
+13
View File
@@ -0,0 +1,13 @@
<?php
use think\facade\Route;
Route::get('s/<name>-<page?>-<cate?>','index/index/list',[],['name' => '.+', 'id' => '\d+', 'cate' => '\d+']);
Route::get('d/:id','index/index/detail');
Route::get('sitemap.xml', 'index/sitemap/index');
+9
View File
@@ -0,0 +1,9 @@
<div class="footerBox">
<div class="box">
<p>{$config.footer_dec|raw}</p>
<p>
{$config.footer_copyright|raw}
<a href="/sitemap.xml" target="_blank">网站地图</a>
</p>
</div>
</div>
+175
View File
@@ -0,0 +1,175 @@
<script src="/static/index/js/vue.global.min.js"></script>
<script src="/static/index/js/index.full.min.js"></script>
<script src="/static/index/js/axios.min.js"></script>
<script>
const { createApp, ref, onMounted, onUnmounted } = Vue;
const { ElButton, ElMessage } = ElementPlus;
const app = createApp({
setup() {
// 定义响应式数据
const elementOpacity = ref(0);
const scrollThreshold = ref(150); // 动态设置的滚动阈值
const keyword = ref('{$keyword??''}');
const qcodeVisible = ref(false);
const layerVisible = ref(false);
const content = ref('');
const load = ref(false)
const drawer = ref(false)
const rankList = ref([]);
const rankDj = ref([]);
const is_m = ref(0);
const newList = ref([]);
// 公共消息方法
const showMessage = (message, type = 'info') => {
ElMessage({
message,
type,
plain: true,
});
};
// 滚动监听方法
const handleScroll = () => {
const scrollTop = window.scrollY || document.documentElement.scrollTop;
elementOpacity.value = scrollTop >= scrollThreshold.value
? Math.min((scrollTop - scrollThreshold.value) / 100, 1)
: Math.max(1 - (scrollThreshold.value - scrollTop) / 100, 0);
const boxElement = document.querySelector('.listBox .screen .fixed .box');
if (boxElement.style.display === 'block' && is_m.value) {
boxElement.style.display = 'none'; // 隐藏元素
}
};
// 搜索按钮点击事件
const searchBtn = () => {
if (!keyword.value) {
return showMessage('请输入你要搜索的内容~', 'error');
}
const currentUrl = window.location.href;
const targetUrl = `/s/${keyword.value}.html`;
if (currentUrl.includes('/s/') || currentUrl.includes('/d/')) {
window.location.href = targetUrl;
} else {
window.open(targetUrl, '_blank');
}
};
// 保存按钮点击事件
const saveBtn = async () => {
if (!content.value) {
return showMessage('请输入你想看的资源信息~', 'error');
}
if (load.value) return;
load.value = true;
try {
const response = await axios.post('/api/tool/feedback', { content: content.value });
showMessage(response.data.message, response.data.code === 200 ? 'success' : 'error');
if (response.data.code === 200) {
layerVisible.value = false;
content.value = '';
}
} finally {
load.value = false;
}
};
const setnum = (num) => (num / 10000).toFixed(2) + 'W';
const goLink = (event,id) => {
event.preventDefault();
window.location.href = `/d/${id}.html`;
}
const changeBtn = (e) => {
const category_id = `{$category_id}`;
if(category_id){
window.location.href = `/s/${keyword.value}-${e}-${category_id}.html`;
}else{
window.location.href = `/s/${keyword.value}-${e}.html`;
}
};
const copyText = async(event,title,url,code) => {
event.preventDefault();
var text = '标题:'+title+'\n链接:'+url
if (code) text += `\n提取码:${code}`;
text += `\n由【${'{$config.app_name}'}${window.location.hostname}】供网盘分享链接`;
try {
// 优先使用 navigator.clipboard
await navigator.clipboard.writeText(text);
showMessage('复制成功', 'success');
} catch (err) {
// 如果 navigator.clipboard 失败,使用 document.execCommand 作为回退
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed'; // 避免滚动
textArea.style.opacity = 0;
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
const successful = document.execCommand('copy');
if (successful) {
showMessage('复制成功', 'success');
} else {
throw new Error('复制失败');
}
} catch (err) {
showMessage('复制失败,请手动复制', 'error');
}
document.body.removeChild(textArea);
}
}
const selectBtn = () => {
const boxElement = document.querySelector('.listBox .screen .fixed .box');
// 切换 display 属性,显示或隐藏
if (boxElement.style.display === 'none' || boxElement.style.display === '') {
boxElement.style.display = 'block'; // 显示
} else {
boxElement.style.display = 'none'; // 隐藏
}
}
const handleDeviceType = () => {
const isMobile = window.matchMedia('(max-width: 768px)').matches;
if (isMobile) {
// 手机端的逻辑
is_m.value = 1
} else {
// 电脑端的逻辑
is_m.value = 0
}
};
// 组件挂载时添加滚动监听
onMounted(() => {
handleDeviceType();
window.addEventListener('scroll', handleScroll);
window.addEventListener('resize', handleDeviceType);
});
// 组件卸载时移除滚动监听
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll);
window.removeEventListener('resize', handleDeviceType);
});
// 返回数据和方法
return { elementOpacity, scrollThreshold, keyword, searchBtn, rankList,newList, setnum, qcodeVisible, layerVisible, content, saveBtn, rankDj,goLink,changeBtn,copyText,drawer,selectBtn,is_m };
}
})
.use(ElementPlus) // 使用 Element Plus
.mount('#app'); // 挂载 Vue 实例
</script>
+71
View File
@@ -0,0 +1,71 @@
<div class="headerBox">
<div class="bg" {notempty name="fixed"}:style="{ opacity: elementOpacity }"{/notempty}></div>
<div class="box">
<a href="/" class="logoBox" {notempty name="fixed"}:style="{ opacity: elementOpacity }"{/notempty}>
{notempty name="config.logo"}
<img class="logo" src="{$config.logo}"></img>
{/notempty}
{if condition="$config.app_name && $config.app_name_hide!=1"}
<div class="title">{$config.app_name}</div>
{/if}
</a>
<div class="search" {notempty name="fixed"}:style="{ opacity: elementOpacity }"{/notempty}>
<input type="text" v-model="keyword" placeholder="输入关键字进行搜索" @keyup.enter="searchBtn" confirm-type="search" @confirm="searchBtn">
<div class="btn" @click="searchBtn">
<i class="iconfont icon-sousuo"></i>
</div>
</div>
<div class="navs">
{notempty name="config.qcode"}
<div class="item" @click="qcodeVisible = true">加入群聊</div>
{/notempty}
{empty name="config.app_demand"}
<div class="item" @click="layerVisible = true">提交需求</div>
{/empty}
<div class="btns" v-html="`{$config.app_links}`"></div>
<div class="iconfont icon-caidan" @click="drawer = true"></div>
</div>
</div>
</div>
<div class="headerKox"></div>
<el-dialog
v-model="qcodeVisible"
width="300"
>
<img src="{$config.qcode}" style="width: 100%" />
</el-dialog>
<el-dialog
v-model="layerVisible"
width="300"
>
<div class="layerBox">
<div class="vname">提交需求</div>
<el-input
v-model="content"
placeholder="请输入你想看的资源信息~"
type="textarea"
resize='none'
></el-input>
<div class="vbtn" @click="saveBtn">提交</div>
</div>
</el-dialog>
<el-dialog
v-model="drawer"
width="300"
center
>
<div class="drawer">
{notempty name="config.qcode"}
<div class="item" @click="qcodeVisible = true">加入群聊</div>
{/notempty}
{empty name="config.app_demand"}
<div class="item" @click="layerVisible = true">提交需求</div>
{/empty}
<div class="btns" v-html="`{$config.app_links}`"></div>
</div>
</el-dialog>
+27
View File
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{notempty name="config.app_icon"}
<link rel="icon" href="{$config.app_icon}" />
{/notempty}
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width,user-scalable=no,maximum-scale=1.0">
<title>{if condition="isset($detail) && $detail.title"}{$detail.title} - {$config.app_name}{else /}{$config.app_name}{notempty name="$config.app_title"} - {$config.app_title}{/notempty}{/if}</title>
<meta name="keywords" content="{notempty name="detail"}{$detail.title},{/notempty}{$config.app_keywords}" />
<meta name="description" content="{notempty name="detail"}{$detail.title} - {/notempty}{$config.app_description}" />
<link rel="stylesheet" href="/static/index/css/index.min.css">
<link rel="stylesheet" href="/static/index/css/app.css">
<link rel="stylesheet" href="/static/index/css/m.css">
{$config.seo_statistics|raw}
<style>
:root {
--theme-color: {$config.home_color|default='#3e3e3e'};
--theme-theme: {$config.home_theme|default='#133ab3'};
--theme-background: {$config.home_background|default='#fafafa'};
--theme-other_background: {$config.other_background|default='#ffffff'};
}
{$config.home_css}
</style>
+310
View File
@@ -0,0 +1,310 @@
<!DOCTYPE html>
<html dir="ltr" lang="zh">
<head>
<meta charset="utf-8">
<meta name="theme-color" content="#fff">
<meta name="viewport" content="initial-scale=1, minimum-scale=1, width=device-width">
<title>提示</title>
<style>
a {
color: var(--link-color);
}
body {
--background-color: #fff;
--error-code-color: var(--google-gray-700);
--google-blue-100: rgb(210, 227, 252);
--google-blue-300: rgb(138, 180, 248);
--google-blue-600: rgb(26, 115, 232);
--google-blue-700: rgb(25, 103, 210);
--google-gray-100: rgb(241, 243, 244);
--google-gray-300: rgb(218, 220, 224);
--google-gray-500: rgb(154, 160, 166);
--google-gray-50: rgb(248, 249, 250);
--google-gray-600: rgb(128, 134, 139);
--google-gray-700: rgb(95, 99, 104);
--google-gray-800: rgb(60, 64, 67);
--google-gray-900: rgb(32, 33, 36);
--heading-color: var(--google-gray-900);
--primary-button-fill-color-active: var(--google-blue-700);
--primary-button-fill-color: var(--google-blue-600);
--primary-button-text-color: #fff;
--text-color: var(--google-gray-700);
background: var(--background-color);
color: var(--text-color);
word-wrap: break-word;
}
html {
-webkit-text-size-adjust: 100%;
font-size: 125%;
}
.icon {
background-repeat: no-repeat;
background-size: 100%;
}
@media (prefers-color-scheme: dark) {
body.captive-portal,
body.dark-mode-available,
body.neterror,
body.supervised-user-block,
.offline body {
--background-color: var(--google-gray-900);
--error-code-color: var(--google-gray-500);
--heading-color: var(--google-gray-500);
--link-color: var(--google-blue-300);
--primary-button-fill-color-active: rgb(129, 162, 208);
--primary-button-fill-color: var(--google-blue-300);
--primary-button-text-color: var(--google-gray-900);
--text-color: var(--google-gray-500);
}
}
</style>
<style>
button {
border: 0;
border-radius: 4px;
box-sizing: border-box;
color: var(--primary-button-text-color);
cursor: pointer;
float: right;
font-size: .875em;
margin: 0;
padding: 8px 16px;
transition: box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
}
[dir='rtl'] button {
float: left;
}
.ssl button {
background: var(--primary-button-fill-color);
}
button:active {
background: var(--primary-button-fill-color-active);
outline: 0;
}
h1 {
color: var(--heading-color);
font-size: 1.6em;
font-weight: normal;
line-height: 1.25em;
margin-bottom: 16px;
}
h2 {
font-size: 1.2em;
font-weight: normal;
}
.icon {
height: 72px;
margin: 0 0 40px;
width: 72px;
}
.interstitial-wrapper {
box-sizing: border-box;
font-size: 1em;
line-height: 1.6em;
margin: 14vh auto 0;
max-width: 600px;
width: 100%;
}
#main-message>p {
display: inline;
}
.nav-wrapper {
margin-top: 51px;
}
.nav-wrapper::after {
clear: both;
content: '';
display: table;
width: 100%;
}
@media (max-width: 700px) {
.interstitial-wrapper {
padding: 0 10%;
}
}
@media (max-width: 420px) {
button,
[dir='rtl'] button {
float: none;
font-size: .825em;
font-weight: 500;
margin: 0;
width: 100%;
}
button {
padding: 16px 24px;
}
.interstitial-wrapper {
padding: 0 5%;
}
.nav-wrapper {
margin-top: 30px;
}
}
@media (min-width: 240px) and (max-width: 420px) and (min-height: 401px),
(min-width: 421px) and (min-height: 240px) and (max-height: 560px) {
body .nav-wrapper {
background: var(--background-color);
bottom: 0;
box-shadow: 0 -22px 40px var(--background-color);
left: 0;
margin: 0 auto;
max-width: 736px;
padding-left: 24px;
padding-right: 24px;
position: fixed;
right: 0;
width: 100%;
z-index: 2;
}
.interstitial-wrapper {
max-width: 736px;
}
}
@media (max-width: 420px) and (orientation: portrait),
(max-height: 560px) {
body {
margin: 0 auto;
}
button,
[dir='rtl'] button,
button.small-link {
font-family: Roboto-Regular, Helvetica;
font-size: .933em;
margin: 6px 0;
transform: translatez(0);
}
.nav-wrapper {
box-sizing: border-box;
padding-bottom: 8px;
width: 100%;
}
h1 {
font-size: 1.5em;
margin-bottom: 8px;
}
.icon {
margin-bottom: 5.69vh;
}
.interstitial-wrapper {
box-sizing: border-box;
margin: 7vh auto 12px;
padding: 0 24px;
position: relative;
}
.interstitial-wrapper p {
font-size: .95em;
line-height: 1.61em;
margin-top: 8px;
}
}
@media (min-width: 421px) and (min-height: 500px) and (max-height: 560px) {
.interstitial-wrapper {
margin-top: 10vh;
}
}
@media (min-height: 400px) and (orientation:portrait) {
.interstitial-wrapper {
margin-bottom: 145px;
}
}
@media (min-height: 299px) {
.nav-wrapper {
padding-bottom: 16px;
}
}
@media (min-height: 500px) and (max-height: 650px) and (max-width: 414px) and (orientation: portrait) {
.interstitial-wrapper {
margin-top: 7vh;
}
}
@media (min-height: 650px) and (max-width: 414px) and (orientation: portrait) {
.interstitial-wrapper {
margin-top: 10vh;
}
}
.ssl .icon {
background-image: -webkit-image-set(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAABAlBMVEUAAADcRTfcRDfdRET/gIDcRjr/ZmbjVTncRDfcRTfcRDfdRDzgSTncRDjeSDvcRTjbRDfbRDjeRzvcRjfbRjjcRTjcRTjcRTfdRTfcRDjdRTjcRTjbRDjbRTjbRTjbRTfcRjjdRDrcRjfbRTjZQzfcRDjZRDfZRzbWQzXXRDXXQzbXQzbWQjXYSDvWQjbbRDfOQDPSQTTUQjXCPDDNPzPJPjLGPTHVQjXMPzPRQTTWQjXLPzPDPDHYQzbAOzDTQTXHPTLIPjK8Oi++Oy/FPTHEPTHPQDTQQDTUQTXBPDDKPjK/OzC9Oi/////PQDPRQDS3OS66OS7TQTTEPDHXQjbMPjMBhLaWAAAAL3RSTlMA4tgPAhYFCcL98B4x9ie1+s49WICbqXNKZY3pjuqcgVdLZnL2qKg9zmXpjfontV8LANsAAAJrSURBVHhe7ZTnduIwFAY3ARIgBAg9vW1v173ROylby/u/yso2Fx3MNaxs9h/zAHM+Sfa8+M/s2LFjx+3tdjwH+/sHWxHVAerb8KSyANnUFkRXwLiK78llgJHJxRalwSMd11OGOeV4nsM9FO0dxhJdw4LrOJ6jYy46PoohqgEHatE9JViiFNWTPIElTpIRRXcQ4C6aJ3EJAS4TkUQXsMJFFE++CCsU8xFEBSAoiHsaQNIQ7yuQCFe3DiHUhftKIlzdKoRSFe0r8sXDAkSoumkIigYaIOkIfeWi56EESFm8r1w0fFIl4epWgBA9qOMpmirCfeWijtoa9WSx6taAELFBRl/vilS3BJRIbRk9/VFTsLrifUXRuNfXLU0y/7m6p0CKxqN+v6lJU/k3eJxu7Os5LWKDHi1tYstKG1zON1X3DGiRMR80Mx3fdCbc1+bQe3o2SJrYXcV0fFMxL9xXiz0987BBtux65qaCeF8lHCR3FabBTQ3xvk4M1yN5B/Mw2+urew8hTP1BM38Qnu5evK8gMw+7IcfH9E3ZlEBfMSO//Kf35+Cm6ua+rhbSYDeEa9CUyW3qK1HIjj5DBz8dWd0bWCd6Ult/uMPEr+BmbV/JHrVG/a9MsEybV5fsK50R3frmBFXtCtVXmt73H4PhQ4t9k9rkJ55tYXwZrO4rCEUfPHfUEcuaZC/umw97TfaVpslu2tCb2lRWnBlKFtf+huwrjaa6Pxv7RfgW7nubJPtKI/X0puQO4k/Pfe/ovtLY7KbxVwve0/sE3VeaLosIbkEDvt8Hoq/hKGwQYvoq5OMnoq/hLAbgc/FVn33PX7pAfE5QHR6fAAAAAElFTkSuQmCC) 1x,
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAMAAADQmBKKAAABTVBMVEUAAADcRDf/ZmbcRjrjVTn/gIDdRETdRDzZQzbXQzXWQzbXQjbWQzXZRDbbRDnWQjXWQzXYSDvbRTjcRTjbRTfcRjfcRTjcRTjdRjncRTfdRTndRTfdRDrbRTjcRDnbRDfbRDjbRjfcRjfbRTjcRTjdRTjbRjjcRTjcRDjcRjncRTncRTndRDnbRTjcRDfZQzbcRTfgSTncRDfcRjjZQzjcRTfVRDbcRDjcRDjWQzXeRzvbRDjXRDXXQzbXQzbbRDfeSDvWQjbVQjXIPjLOQDPXQjbCPDDNPzPUQTXRQTS5OS7QQDTUQjW3OS7SQTTPQDTFPDHJPjK2OC26OS7HPjHOPzPLPjLMPjPRQDTGPDHTQTTEPTHLPzPGPTG7Oi/HPTLKPjLTQTXYQza9Oi/MPzPFPTHDPDHBPDC/OzC+Oy+8Oi/AOzDWQjX////bRDd3undHAAAAQnRSTlMA2AUWCQIPHj39wvbO8DH64ifqqYFmtrVMc1lKS5x0nY6PWKqbjYDpZXWCZ1py8Jv9McJXV+KA9qioPc5l6Y36J7VmcHe8AAAFWUlEQVR4XuzWS4rCQBSG0euz56ISgiaEjHwgGhAhDnRF3/6HDY1Ia5WPjP4a3LOKY28555xzzjnnnHPOuSyzpPR7vb6lZAUrS8hgB7uBpaMEKC0Zhz3A/mCpaPjTWCK23GwtCcMjN8ehpWDN3doS8HPi7vRjejX/1CbX8qA1sdGZB+eRaW14sjGp8YQnk7EpVQQqE7peCFyupjMnYm4yGVGZ7q1EyTZbEEche2uUbLMlL5W6t4Zkm22Ikm02561c89aQbLNTPpgq3hqSbbbmo1r41rhW8NaAaLMzvjITvDUg2WzFlyrBWwOCzc6Jkm12QQcL3Vtlmy3opFC9VbbZJR0tNW+Vbbahs0b41rhc8FbVZqdEyTb724t5/bYNA3G4e+80NYI0gGFkvaR779KKZUWuFKe7nlIsT5X//2M5VMZiZB9DQj74xW8ffrwjP90Mb/07Vf5CbXYJg0BtO4toKS9vhYHGY1vDZg28FQY6tBZls8tYBehwNLTyt1nhrTDQaDQcWAux2SJWAxpOBpWMWSvm4q0w0Gg4nFQqFTd/m72HlYBYQJV+w83bZu9jRaDJYEB4osjJ02aFt8JASUBRq+PlarMrWBGI8lQajVanXA5kopUcvBUEGrCAWhSoXs3PZtewKhA/MMbTbcpEa7l4KwwURZSHANnVnGz2CVYGmg6oZ1u1XGy2hNWBCA8BogE1m7Zl+ShNVMrdW2Wg/v+Amr2eRYCcGLBZU2+FgcSBESDfdZxdwGbNvBUGihKgnk1OjPAEwS5gsybeCgNNdTQLyAtqtRCwWQNvhYH4ndjtNnlAnlet1uIQsFl9b4WBpgNyaUCEJ45DwGa1vRUGanU6nMcmB+ZSnlosES3nvm/tUpGm1tFPd5DDAyKFBJGpzRaxSjW5J0o8/MAQ4ZEyKua/b+0Np175blMERDuaECFBZGqzBaxY9iAjIMbDK01U0OVZxcplE6BIjLzFRixgQDwflCJaXcC+1ToKyOYHFvCOljPiNmvurTBRI+oQoGTk2Z1YQyIeiWhlEftWnx8Yf8RcyiMCEkyhic2u4xOWSw9MBBQENTQFI83a+iL2rdgpJ1rms45mByYzhbDNwt6qTtTlQC7r6FT/CLRQ02ZLWKc8OmK+LzooCykhKpl4q7p+7B/d0SjNggRbqGOzm1gPqL3PX3niZakOQsenf1PDWzWAxr+JBtEDQxnnJTISNmvurfBK75t45bORBNGSobcqb9DqBCjdQOl5E370xthbYaDRiIjRDxKQwJk9a+o2u431gYZERBo/kcBIfvJ/TrSt6K1b+kDUHMkra2V3j5zRlprNbmADILbQ65S/z2ggyY82zL0VXsdQnnLdhSOKQzWbLWADIMpDgOrd3q958QiigrG3wusYzmNbXmY4sh+tangrVJ2Dgy97X9v0CmILzzIHcj3ZPTL+h6DN7mhYR5nxHI4mtKNbLCAmaX9QDDKFO6C36hDttcdJQFGLeTWRIupocGOj62cBb9WqesLTFwfm000MQgqz9lDLW+Hve35HM9Fnqw9HetBkNsF6+Yaet8Jf0+xbka0XbYspSMIg+5D8/8psnqdYv3qso1vsS9Hy6SaGQ6AYHP9ngLdqllVpiIB8RygRQjGEdOsc4K26RGzk6YTxjhbDDdzXcfwC8Fbd8glPnR4Y62gBAM/a1WybfYVNyyUBiZFPXYCAH70GvFW7nFRHH7EgyI8uAd6qXZ7NAqoilG6ZKuBH184D3qpdAQlIWp0p9dE7wFv1q8Y6+njLoPl+9P4C4K0GRKSjgTyywvoAeKtBxVWU6YhorovcvA14q0HtouwU0Fw/+jzN8w/cQ/zg6ug2/QAAAABJRU5ErkJggg==) 2x);
}
</style>
</head>
<body id="body" class="ssl extended-reporting-has-checkbox">
<div class="interstitial-wrapper">
<div id="main-content">
<div class="icon" id="icon"></div>
<div id="main-message">
<h1>提示</h1>
<p>{$msg}</p>
</div>
</div>
<div class="nav-wrapper">
<a href="javascript:history.go(-1);"><button id="primary-button">好的,我知道了</button></a>
</div>
</div>
<style>
html {
direction: ltr;
}
body {
font-family: system-ui, PingFang SC, STHeiti, sans-serif;
font-size: 75%;
}
button {
font-family: system-ui, PingFang SC, STHeiti, sans-serif;
}
</style>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="/assets/uni.4906e6f8.css">
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title>心悦搜剧-免费分享百万级网盘资源,致力打造顶尖网盘搜索引擎,让您畅享资源无忧!</title>
<meta name="keywords" content="心悦搜剧、短剧搜索、影视资源、在线短剧">
<meta name="description" content="免费分享百万级网盘资源,致力打造顶尖网盘搜索引擎,让您畅享资源无忧!">
<link rel="icon" href="/assets/logo-DQLPqAxx.png" />
<script src="./static/config.js"></script>
<!--preload-links-->
<!--app-context-->
<script type="module" crossorigin src="/assets/index-CICgbd-2.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BLVVqZ0m.css">
</head>
<body>
<div id="app"><!--app-html--></div>
<script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script>
<script>LA.init({id:"3HsdT1GaTQzE091Y",ck:"3HsdT1GaTQzE091Y",hashMode:true})</script>
</body>
</html>
+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body>
<div>
<h4>【{$day} | 短剧每日更新】</h4>
{volist name="list" id="vo"}
{$key+1}、{$vo.title}<br/>
{/volist}
<br/>
</div>
</body>
</html>
+123
View File
@@ -0,0 +1,123 @@
{include file="common/header"}
</head>
<body>
<div class="headBg" style="background-image: url({$config.home_bg});"></div>
<div id="app" v-cloak>
{include file="common/head"}
<div class="searchBox searchDetail">
<div class="search">
<input type="text" v-model="keyword" placeholder="输入关键字进行搜索" @keyup.enter="searchBtn" confirm-type="search" @confirm="searchBtn">
<div class="btn" @click="searchBtn">
<i class="iconfont icon-sousuo"></i>
</div>
</div>
</div>
<div class="listBox detailBox">
<div class="left">
<h3>详情</h3>
<div class="box details">
{notempty name="detail.vod_pic"}
<div class="pic">
<img src="{$detail.vod_pic}" />
</div>
{/notempty}
<div class="title">{$detail.title}</div>
<div class="cat">
<div class="l">资源分类</div>
<div class="r">
{if condition="$detail.category && $detail.category.name"}
{$detail.category.name}
{else /}
其它
{/if}
</div>
</div>
<div class="cat">
<div class="l">资源描述</div>
<div class="r">
{if condition="$detail.vod_content"}
{$detail.vod_content}
{else /}
-
{/if}
</div>
</div>
<div class="cat">
<div class="l">更新时间</div>
<div class="r">{$detail.times}</div>
</div>
<div class="cat">
<div class="l">资源类型</div>
<div class="r">
<img src="/static/index/images/{$detail.is_type}.png" class="icon" />
{if condition="$detail.is_type==1"}
<span>阿里云盘</span>
{elseif condition="$detail.is_type==2"/}
<span>百度网盘</span>
{elseif condition="$detail.is_type==3"/}
<span>UC网盘</span>
{elseif condition="$detail.is_type==4"/}
<span>迅雷网盘</span>
{else /}
<span>夸克网盘</span>
{/if}
</div>
</div>
<div class="cat">
<div class="l">资源地址</div>
<div class="r">
<a href="{$detail.url}" target="_blank">{$detail.url}</a>
</div>
</div>
{notempty name="detail.code"}
<div class="cat">
<div class="l">提取码</div>
<div class="r" style="color: #FF3F3D;">{$detail.code}</div>
</div>
{/notempty}
<div class="btns">
<div class="btn btnCol" @click.stop="copyText($event,'{$detail.title}','{$detail.url}','{$detail.code}')"><i class="iconfont icon-fenxiang1"></i>复制分享</div>
<a href="{$detail.url}" target="_blank" class="btn"><i class="iconfont icon-yun_o"></i>立即访问</a>
</div>
</div>
</div>
<div class="right">
<block v-for="(item,index) in rankList" :key="index">
<div class="nav">
<img :src="item.image" v-if="item.image">
{{item.name}}
</div>
<div class="box" v-if="item.list && item.list.length>0">
<div class="list">
<a :href="'/s/'+vo.title+'.html'" v-for="(vo,i) in item.list" :key="i" class="item" v-show="i<5">
<p>
<span>{{i+1}}</span>
{{vo.title}}
</p>
</a>
</div>
</div>
</block>
</div>
</div>
{include file="common/foot"}
</div>
{include file="common/footer"}
<script type="text/javascript" charset="utf-8">
if(!app.is_m){
app.rankList = JSON.parse('<?php echo json_encode($rankList, JSON_UNESCAPED_UNICODE); ?>');
for (const item of app.rankList) {
axios.get('/api/tool/ranking',{
params: {
channel: item.name,
is_m: app.is_m
}
})
.then(function (res) {
item.list = res.data.data
})
}
}
</script>
</body>
</html>
+113
View File
@@ -0,0 +1,113 @@
{include file="common/header"}
</head>
<body>
<div class="headBg" style="background-image: url({$config.home_bg});"></div>
<div id="app" v-cloak>
{include file="common/head"}
<div class="homeBox searchBox">
<div class="box">
<div class="logoBox">
{notempty name="config.logo"}
<img class="logo" src="{$config.logo}"></img>
{/notempty}
{if condition="$config.app_name && $config.app_name_hide!=1"}
<span class="title">{$config.app_name}</span>
{/if}
</div>
{notempty name="config.app_subname"}
<div class="subTitle">{$config.app_subname}</div>
{/notempty}
<div class="search">
<input type="text" v-model="keyword" placeholder="输入关键字进行搜索" @keyup.enter="searchBtn" confirm-type="search" @confirm="searchBtn">
<div class="btn" @click="searchBtn">
<i class="iconfont icon-sousuo"></i>
</div>
</div>
</div>
<div class="home {if $config.ranking_type != 1}homeNO{/if}">
<div class="block" v-if="newList.length>0">
<div class="nav">
{notempty name="config.home_new_img"}
<img src="{$config.home_new_img}"></img>
{/notempty}
最新更新
</div>
<div class="content">
{if $config.ranking_type == 1 }
<div class="list">
<a :href="'/s/'+vo.title+'.html'" target="_blank" class="item" v-for="(vo,i) in newList" :key="i">
<div class="img">
<img :src="vo.src" />
<span>Loading...</span>
</div>
<p>{{vo.title}}</p>
</a>
</div>
{else /}
<div class="list">
<a :href="'/s/'+vo.title+'.html'" target="_blank" class="item" v-for="(vo,i) in newList" :key="i">
<p>
<span>{{i+1}}</span>
{{vo.title}}
</p>
</a>
</div>
{/if}
</div>
</div>
<div class="block" v-for="(item,index) in rankList" :key="index">
<div class="nav">
<img :src="item.image" v-if="item.image">
{{item.name}}
</div>
<div class="content">
{if $config.ranking_type == 1 }
<div class="list">
<a :href="'/s/'+vo.title+'.html'" target="_blank" class="item" v-for="(vo,i) in item.list" :key="i">
<div class="img">
<img :src="vo.src" />
<span>Loading...</span>
</div>
<p>{{vo.title}}</p>
</a>
</div>
{else /}
<div class="list">
<a :href="'/s/'+vo.title+'.html'" target="_blank" class="item" v-for="(vo,i) in item.list" :key="i">
<p>
<span>{{i+1}}</span>
{{vo.title}}
</p>
</a>
</div>
{/if}
</div>
</div>
</div>
</div>
{include file="common/foot"}
</div>
{include file="common/footer"}
<script type="text/javascript" charset="utf-8">
app.newList = JSON.parse('<?php echo json_encode($newList, JSON_UNESCAPED_UNICODE); ?>');
let num = '{$config.ranking_m_num}';
if(app.is_m){
app.newList = app.newList.slice(0, num);
}
app.rankList = JSON.parse('<?php echo json_encode($rankList, JSON_UNESCAPED_UNICODE); ?>');
for (const item of app.rankList) {
axios.get('/api/tool/ranking',{
params: {
channel: item.name,
is_m: app.is_m
}
})
.then(function (res) {
item.list = res.data.data
})
}
</script>
</body>
</html>
+121
View File
@@ -0,0 +1,121 @@
{include file="common/header"}
</head>
<body>
<div class="headBg" style="background-image: url({$config.home_bg});"></div>
<div id="app" v-cloak>
{include file="common/head"}
<div class="searchBox searchList">
<div class="search">
<div class="select" @click="selectBtn">
{if condition="$category_id == ''"}全部{/if}
{foreach $category as $key=>$vo }
{if condition='$category_id == $vo.id'}{$vo.name}{/if}
{/foreach}
<i class="iconfont icon-xiala" style="font-size: 3vw"></i>
</div>
<input type="text" v-model="keyword" placeholder="输入关键字进行搜索" @keyup.enter="searchBtn" confirm-type="search" @confirm="searchBtn">
<div class="btn" @click="searchBtn">
<i class="iconfont icon-sousuo"></i>
</div>
</div>
</div>
<div class="listBox">
<div class="screen">
<div class="fixed">
<h3>筛选</h3>
<div class="box">
<a href="/s/{$keyword}.html" class="{eq name="category_id" value=""}active{/eq}">全部</a>
{foreach $category as $key=>$vo }
<a href="/s/{$keyword}-1-{$vo.id}.html" class="{if condition='$category_id == $vo.id'}active{/if}">{$vo.name}</a>
{/foreach}
</div>
</div>
</div>
<div class="left">
<h3>为您找到【<span>{$keyword}</span>】相关资源<span> {$list.total_result} </span></h3>
<div class="box">
{if condition="$list.total_result>0"}
<div class="list">
{foreach $list.items as $key=>$vo }
<a class="item" target="_blank" href="{$vo.url}">
<div class="title">
{$vo.name|raw}
</div>
<div class="type time">{$vo.times}</div>
<div class="type">
{if condition="$vo.is_type==1"}
<span>来源:阿里云盘</span>
{elseif condition="$vo.is_type==2"/}
<span>来源:百度网盘</span>
{elseif condition="$vo.is_type==3"/}
<span>来源:UC网盘</span>
{elseif condition="$vo.is_type==4"/}
<span>来源:迅雷网盘</span>
{else /}
<span>来源:夸克网盘</span>
{/if}
{notempty name="vo.code"}
<span>提取码:<span>{$vo.code}</span></span>
{/notempty}
</div>
<div class="btns">
<div class="btn" @click.stop="copyText($event,'{$vo.title}','{$vo.url}','{$vo.code}')"><i class="iconfont icon-fenxiang1"></i>复制分享</div>
<div class="btn" @click.stop="goLink($event,'{$vo.id}')"><i class="iconfont icon-fangwen"></i>查看详情</div>
<div class="btn">
<img src="/static/index/images/{$vo.is_type}.png" class="icon" />
立即访问
</div>
</div>
</a>
{/foreach}
</div>
<div class="page">
{notempty name="list.total_result"}
<el-pagination background layout="prev, pager, next" :pager-count="3" :default-current-page="{$page_no}" :default-page-size="{$page_size}" :total="{$list.total_result}" @change="changeBtn"></el-pagination>
{/notempty}
</div>
{else /}
<el-empty style="margin-top: 10%;" :image-size="200" image="{$config.search_bg??''}" description="{$config.search_tips|default='未找到,可换个关键词尝试哦~'}"></el-empty>
{/if}
</div>
</div>
<div class="right">
<block v-for="(item,index) in rankList" :key="index">
<div class="nav">
<img :src="item.image" v-if="item.image">
{{item.name}}
</div>
<div class="box" v-if="item.list && item.list.length>0">
<div class="list">
<a :href="'/s/'+vo.title+'.html'" v-for="(vo,i) in item.list" :key="i" class="item" v-show="i<5">
<p>
<span>{{i+1}}</span>
{{vo.title}}
</p>
</a>
</div>
</div>
</block>
</div>
</div>
{include file="common/foot"}
</div>
{include file="common/footer"}
<script type="text/javascript" charset="utf-8">
// if(!app.is_m){
app.rankList = JSON.parse('<?php echo json_encode($rankList, JSON_UNESCAPED_UNICODE); ?>');
for (const item of app.rankList) {
axios.get('/api/tool/ranking',{
params: {
channel: item.name,
is_m: app.is_m
}
})
.then(function (res) {
item.list = res.data.data
})
}
// }
</script>
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
<?php
// 全局中间件定义文件
return [
// 跨域请求支持
\think\middleware\AllowCrossDomain::class,
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
\think\middleware\SessionInit::class
];
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace app\model;
use app\model\QfShop;
class Access extends QfShop
{
/**
* 创建一个新的授权
*
* @param [int] AdminID
* @param [plat] 授权平台
* @return 授权信息|false
*/
public function createAccess($access_admin, $access_plat)
{
//将该平台下所有授权记录标记为失效
// $this->where([
// "access_admin" => $access_admin,
// "access_plat" => $access_plat
// ])->update(['access_status' => 1]);
//生成一个新的Access_token
$access_token = sha1(time()) . rand(100000, 99999) . sha1(time());
$access_id = $this->insertGetId([
"access_admin" => $access_admin,
"access_plat" => $access_plat,
"access_token" => $access_token,
"access_ip" => request()->ip(),
"access_createtime" => time(),
"access_updatetime" => time()
]);
$access = $this->where("access_id", $access_id)->find();
return $access ?? false;
}
}
+130
View File
@@ -0,0 +1,130 @@
<?php
namespace app\model;
use app\model\QfShop;
class Admin extends QfShop
{
/**
* 用户登录
*
* @param string 帐号
* @param string 密码
* @return void
*/
public function login($admin_account, $admin_password)
{
$admin = $this->where([
"admin_account" => $admin_account,
])->find();
if ($admin) {
//判断密码是否正确
$salt = $admin['admin_salt'];
$password = $admin['admin_password'];
if ($password != encodePassword($admin_password, $salt)) {
return false;
}
return $admin->toArray() ?? false;
} else {
return false;
}
}
public function getListByPage($maps, $order = null, $field = "*")
{
$resource = $this->view('admin', $field)->view('group', '*', 'group.group_id = admin.admin_group', 'left');
foreach ($maps as $map) {
switch (count($map)) {
case 1:
$resource = $resource->where($map[0]);
break;
case 2:
$resource = $resource->where($map[0], $map[1]);
break;
case 3:
$resource = $resource->where($map[0], $map[1], $map[2]);
break;
default:
}
}
if ($order) {
$resource = $resource->order($order);
}
return $resource->paginate($this->per_page);
}
/**
* 重置密码
*
* @param string UID
* @param string 密码
* @return void
*/
public function motifyPassword($admin_id, $password)
{
$access = new Access();
//将所有授权记录标记为失效
$access->where('access_admin', $admin_id)->update(['access_status' => 1]);
$salt = getRandString(4);
$password = encodePassword($password, $salt);
return $this->where([
"admin_id" => $admin_id
])->update([
"admin_password" => $password,
"admin_salt" => $salt,
]);
}
/**
* 通过帐号获取用户信息
*
* @param string 帐号/手机号
* @return void
*/
public function getAdminByAccount($admin_account)
{
$admin = $this->where([
"admin_account" => $admin_account
])->find();
if ($admin) {
return $admin->toArray() ?? false;
} else {
return false;
}
}
/**
* AccessToken获取用户信息
*
* @param string access_token
* @return void
*/
public function getAdminByAccessToken($access_token)
{
$Access = new Access();
$access = $Access->where([
"access_token" => $access_token,
"access_status" => 0,
])->find();
if ($access) {
if (time() > $access['access_updatetime'] + 7200) {
return false;
}
if ($access['access_updatetime'] - $access['access_createtime'] > 86400) {
return false;
}
$Access->where([
"access_id" => $access['access_id'],
])->update([
'access_updatetime' => time()
]);
$this->where("admin_id", $access['access_admin'])->update([
'admin_updatetime' => time()
]);
$admin = $this->where("admin_id", $access['access_admin'])->find();
return $admin->toArray() ?? false;
} else {
return false;
}
}
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace app\model;
use app\model\QfShop;
class App extends QfShop
{
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace app\model;
use app\model\QfShop;
class Attach extends QfShop
{
}
+191
View File
@@ -0,0 +1,191 @@
<?php
namespace app\model;
use think\facade\Db;
use app\model\QfShop;
class Auth extends QfShop
{
/**
* 判断用户组是否获得某节点的授权
*
* @param int 用户组ID
* @param int 节点ID
* @return void
*/
public function auth($auth_group, $auth_node)
{
$auth = $this->where([
"auth_group" => $auth_group,
"auth_node" => $auth_node
])->find();
return $auth ? true : false;
}
/**
* 根据用户组 获取管理后台菜单
*
* @param int 用户组ID
* @return void
*/
public function getAdminMenuListByAdminId($group_id)
{
if ($group_id == 1) {
//超级管理员组
$list = Node::where([
"node_pid" => 0,
"node_show" => 1,
])
->order("node_order desc,node_id asc")
->select();
for ($i = 0; $i < count($list); $i++) {
$list[$i]['subList'] = $this->getSubAdminListByPid($list[$i]['node_id'], $group_id);
for ($j = 0; $j < count($list[$i]['subList']); $j++) {
$list[$i]['subList'][$j]['subList'] = $this->getSubAdminListByPid($list[$i]['subList'][$j]['node_id'], $group_id);
}
}
return $list;
} else {
//其他组
$list = Node::where([
"node_pid" => 0,
"node_show" => 1,
])
->order("node_order desc,node_id asc")
->select();
for ($i = 0; $i < count($list); $i++) {
$list[$i]['subList'] = $this->getSubAdminListByPid($list[$i]['node_id'], 1);
for ($j = 0; $j < count($list[$i]['subList']); $j++) {
$list[$i]['subList'][$j]['subList'] = $this->getSubAdminListByPid($list[$i]['subList'][$j]['node_id'], 1);
}
}
if($list){
$list = $list->toArray();
}
$list2 = Node::alias("node")
->view('node', '*')
->view('auth', '*', 'node.node_id=auth.auth_node', 'left')
->where([
"node_module" => "qfadmin",
"node_show" => 1,
"auth_group" => $group_id
])
->order("node_order desc,node_id asc")
->select()->toArray();
foreach ($list2 as $k => $v) {
//一级
foreach ($list as $key => $value) {
if($v['node_id'] == $value['node_id']){
$list[$key]['select'] = 1;
}
//2级
foreach ($value['subList'] as $key2 => $value2) {
if($v['node_id'] == $value2['node_id']){
$list[$key]['subList'][$key2]['select'] = 1;
}
//3级
foreach ($value2['subList'] as $key3 => $value3) {
if($v['node_id'] == $value3['node_id']){
$list[$key]['subList'][$key2]['subList'][$key3]['select'] = 1;
}
}
}
}
}
foreach ($list as $key => $value) {
//一级
if(empty($value['select'])){
if(!empty($value['subList'])){
foreach ($value['subList'] as $key2 => $value2) {
//2级
if(empty($value2['select'])){
if(!empty($value2['subList'])){
foreach ($value2['subList'] as $key3 => $value3) {
//3级
if(empty($value3['select'])){
if(empty($value3['subList'])){
unset($list[$key]['subList'][$key2]['subList'][$key3]);
if(empty($list[$key]['subList'][$key2]['subList'])){
unset($list[$key]['subList'][$key2]);
}
}
}
}
}else{
unset($list[$key]['subList'][$key2]);
if(empty($list[$key]['subList'])){
unset($list[$key]);
}
}
}
}
}else{
unset($list[$key]);
}
}
}
$list = array_values($list);
foreach ($list as $key => $value) {
if(!empty($value['subList'])){
$list[$key]['subList'] = array_values($list[$key]['subList']);
foreach ($value['subList'] as $key2 => $value2) {
if(!empty($value2['subList'])){
try {
$list[$key]['subList'][$key2]['subList'] = array_values($list[$key]['subList'][$key2]['subList']);
} catch (\Throwable $th) {
//throw $th;
}
}
}
}
}
return $list;
}
}
/**
* 根据节点ID 获取用户组的子菜单
*
* @param int 节点ID
* @param int 用户组ID
* @return void
*/
public function getSubAdminListByPid($node_id, $group_id = 1)
{
if ($group_id == 1) {
//超级管理员组
return Node::where([
"node_pid" => $node_id,
"node_show" => 1
])
->order("node_order desc,node_id asc")
->select();
} else {
//其他组
return Node::alias("node")
->view('node', '*')
->view('auth', '*', 'node.node_id=auth.auth_node', 'left')
->where([
"node_pid" => $node_id,
"node_show" => 1,
"auth_group" => $group_id
])
->order("node_order desc,node_id asc")
->select();
}
}
/**
* 删除授权记录
*
* @return void
*/
public function cleanAuth()
{
//清空auth表
Db::execute("truncate table " . config('database.connections.mysql.prefix') . "auth");
return true;
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace app\model;
use app\model\QfShop;
class Conf extends QfShop
{
/**
* 更新配置
*
* @param string 配置key
* @param string 配置值
* @param int 整形配置
* @param string 配置描述
* @return void
*/
public function updateConf($key, $value, $int = 0, $desc = null)
{
$data = [];
if ($desc) {
$data['conf_desc'] = $desc;
}
$data['conf_value'] = $value;
$this->where([
"conf_key" => $key,
"conf_readonly" => 0,
])->update($data);
}
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace app\model;
use app\model\QfShop;
class Days extends QfShop
{
}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace app\model;
use app\model\QfShop;
class Feedback extends QfShop
{
/**
* 主键
* @var string
*/
protected $pk = 'id';
/**
* 是否需要自动写入时间戳
* @var bool
*/
protected $autoWriteTimestamp = true;
/**
* 只读属性
* @var array
*/
protected $readonly = [
'id',
];
/**
* 字段类型或者格式转换
* @var array
*/
protected $type = [
'id' => 'integer',
];
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace app\model;
use app\model\QfShop;
class Group extends QfShop
{
}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace app\model;
use app\model\QfShop;
class Log extends QfShop
{
/**
* 主键
* @var string
*/
protected $pk = 'id';
/**
* 是否需要自动写入时间戳
* @var bool
*/
protected $autoWriteTimestamp = true;
/**
* 只读属性
* @var array
*/
protected $readonly = [
'id',
];
/**
* 字段类型或者格式转换
* @var array
*/
protected $type = [
'id' => 'integer',
];
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace app\model;
use app\model\QfShop;
class Node extends QfShop
{
}
+226
View File
@@ -0,0 +1,226 @@
<?php
namespace app\model;
use think\Model;
use think\helper\Str;
use app\model\Token as TokenModel;
/**
* QfShop 数据模型基类
*/
class QfShop extends Model
{
/**
* 默认分页获取条数
*
* @var int 默认分页获取条数
*/
public $page_size = 40;
public $per_page = 10;
/**
* 翻页搜索器
* @access public
* @param object $query
* @param mixed $value
* @param mixed $data
*/
public function searchPageAttr($query, $value, $data)
{
$pageNo = !empty($data['page_no']) ? $data['page_no'] : 1;
$pageSize = !empty($data['page_size']) ? $data['page_size'] : $this->page_size;
$query->page($pageNo, $pageSize);
}
/**
* 排序搜索器
* @access public
* @param object $query
* @param mixed $value
* @param mixed $data
*/
public function searchOrderAttr($query, $value, $data)
{
$order = [];
if (!empty($data['order_field']) || !empty($data['order_type'])) {
$order[$data['order_field']] = $data['order_type'];
} else {
$order = $this->defaultOrder;
}
if (!empty($this->fixedOrder)) {
// 固定排序必须在前,否则将导致自定义排序无法覆盖
$order = array_merge($this->fixedOrder, $order);
if (!empty($data['order_field']) && $this->isReverse) {
$order = array_reverse($order);
}
}
if (!empty($order)) {
$query->order($order);
}
}
/**
* 设置默认排序
* @access public
* @param array $order 默认排序
* @param array $fixed 固定排序
* @param bool $reverse 是否调整顺序
* @return $this
*/
public function setDefaultOrder(array $order, $fixed = [], $reverse = false)
{
$this->defaultOrder = $order;
$this->fixedOrder = $fixed;
$this->isReverse = $reverse;
return $this;
}
/**
* 模型验证器
* @access public
* @param array|object $data 验证数据
* @param string|null $scene 场景名
* @param bool $clean 是否清理规则键值不存在的$data
* @param string $validate 验证器规则或类
* @return bool
*/
public function validateData(array &$data, $scene = null, $clean = false, $validate = '')
{
try {
// 确定规则来源
if (empty($validate)) {
$class = '\\app\\validate\\' . $this->getName();
if ($scene) {
$v = new $class();
$v->extractScene($data, $scene, $clean, $this->getPk());
} else {
$v = validate($class);
}
} else {
$v = validate($validate);
if ($scene) {
$v->extractScene($data, $scene, $clean, $this->getPk());
}
}
if ($clean) {
$keys = $v->getRuleKey();
foreach ($data as $key => $value) {
if (!in_array($key, $keys, true)) {
unset($data[$key]);
}
}
unset($key, $value);
}
$v->failException(true)->check($data);
} catch (ValidateException $e) {
return $this->setError($e->getMessage());
}
return true;
}
/**
* 检测是否存在相同值
* @access public
* @param array $map 查询条件
* @return bool false:不存在
*/
public static function checkUnique(array $map)
{
if (empty($map)) {
return true;
}
$count = self::where($map)->count();
if (is_numeric($count) && $count <= 0) {
return false;
}
return true;
}
/**
* 后台使用分页获取数据
*
* @param array 筛选数组
* @param string 排序方式
* @param string 搜索字段
* @return void
*/
public function getListByPage($maps, $order = null, $field = "*")
{
$resource = $this->field($field);
foreach ($maps as $map) {
switch (count($map)) {
case 1:
$resource = $resource->where($map[0]);
break;
case 2:
$resource = $resource->where($map[0], $map[1]);
break;
case 3:
$resource = $resource->where($map[0], $map[1], $map[2]);
break;
default:
}
}
if ($order) {
$resource = $resource->order($order);
}
return $resource->paginate($this->per_page);
}
/**
* 替换数组中的驼峰键名为下划线
* @access public
* @param array $name 需要修改的键名
* @param array &$data 源数据
*/
public static function keyToSnake(array $name, array &$data)
{
if (!is_array($name)) {
return;
}
foreach ($name as $value) {
foreach ($data as &$item) {
if (!array_key_exists($value, $item)) {
continue;
}
$temp = $item[$value];
unset($item[$value]);
$item[Str::snake($value)] = $temp;
}
}
}
/**
* 将数组键名驼峰转下划线
* @access public
* @param array $data 数据
* @return array
*/
public static function snake(array $data)
{
if (empty($data)) {
return [];
}
foreach ($data as $itemKey => $item) {
foreach ($item as $valueKey => $value) {
$data[$itemKey][Str::snake($valueKey)] = $value;
unset($data[$itemKey][$valueKey]);
}
}
return $data;
}
}
+133
View File
@@ -0,0 +1,133 @@
<?php
namespace app\model;
class Sms
{
/**
* 发送通知短信
*
* @param string 手机号码
* @param string 内容
* @param string 签到二维码链接
* @return void
*/
public function sendSmsNotice($smsData)
{
//短连接生成
$baidu_token = config('qfshop.baidu_token');
if (!$baidu_token) {
jerr('请先在后台系统设置短链接相关参数!');
}
$urlData = [
[
'LongUrl' => $smsData['qrcodeUrl'],
'TermOfValidity' => "1-year",
]
];
$urlHeader = array(
'Content-Type: application/json; charset=UTF-8',
'Dwz-Token: '.$baidu_token,
);
$res = curlHelper("https://dwz.cn/api/v3/short-urls", "POST", json_encode($urlData,256), $urlHeader)['body'];
$res = json_decode($res, true);
if($res['Code'] != 0){
return false;
}
$smsData['qrcodeurl'] = $res['ShortUrls'][0]['ShortUrl'];
$result = $this->sendSms($smsData);
if($result){
return true;
}else{
return false;
}
}
/**
* 发送短信(百度)
*
* @param string 手机号码
* @param string 内容
* @return void
*/
private function sendSms($smsData)
{
//初始化短信相关配置
$sms_sign = config('qfshop.sms_sign');
$sms_tmpl = config('qfshop.sms_tmpl_1');
$error = null;
if (!($sms_sign && $sms_tmpl)) {
$error = jerr('请先在后台系统设置短信相关参数!');
}
require_once __DIR__ . "/../../extend/baidu/baidusmsv3.php";
$config = array(
'endPoint' => 'smsv3.bj.baidubce.com',
'accessKey' => 'b71eab07ebcc4f09b3f770e43a9d126d',
'secretAccessKey' => '3c6c8b3d85274baab4c38481996919ec',
);
$smsClient = new \Baidusmsv3($config);
$message = array(
'template' => $sms_tmpl, //短信模板ID
'signatureId' => $sms_sign, //短信签名ID
'mobile' => $smsData['mobile'],
"contentVar" => array(
'param1' => '“'.$smsData['title'].'“',
'param2' => $smsData['time'],
'param3' => $smsData['address'],
'param4' => '青峰网络',
'param5' => $smsData['qrcodeurl'],
),
);
$result = $smsClient->sendMessage($message);
if($result['code'] == 1000){
return true;
}else{
return false;
}
}
/**
* 发送短信验证码
*
* @param string 手机号码
* @return void
*/
public function sendSmsCode($mobile,$code)
{
//初始化短信相关配置
$sms_sign = config('qfshop.sms_sign');
$sms_tmpl = config('qfshop.sms_tmpl_2');
$error = null;
if (!($sms_sign && $sms_tmpl)) {
$error = jerr('请先在后台系统设置短信相关参数!');
}
require_once __DIR__ . "/../../extend/baidu/baidusmsv3.php";
$config = array(
'endPoint' => 'smsv3.bj.baidubce.com',
'accessKey' => 'b71eab07ebcc4f09b3f770e43a9d126d',
'secretAccessKey' => '3c6c8b3d85274baab4c38481996919ec',
);
$smsClient = new \Baidusmsv3($config);
$message = array(
'template' => $sms_tmpl, //短信模板ID
'signatureId' => $sms_sign, //短信签名ID
'mobile' => $mobile,
"contentVar" => array(
'code' => ''.$code,
'time' => '5',
),
);
$result = $smsClient->sendMessage($message);
if($result['code'] == 1000){
return true;
}else{
return false;
}
}
}
+318
View File
@@ -0,0 +1,318 @@
<?php
namespace app\model;
use app\model\QfShop;
use Lizhichao\Word\VicWord;
class Source extends QfShop
{
/**
* 主键
* @var string
*/
protected $pk = 'source_id';
/**
* 是否需要自动写入时间戳
* @var bool
*/
protected $autoWriteTimestamp = true;
/**
* 只读属性
* @var array
*/
protected $readonly = [
'source_id',
];
/**
* 字段类型或者格式转换
* @var array
*/
protected $type = [
'source_id' => 'integer',
'is_delete' => 'integer',
'status' => 'integer',
'time' => 'timestamp',
];
/**
* hasOne qf_source_category
* @access public
* @return mixed
*/
public function category()
{
return $this
->hasOne(SourceCategory::class, 'source_category_id', 'source_category_id')
->joinType('left')
->field('source_category_id,name');
}
/**
* @description: 获取一个信息
* @param {*} $code
* @return {*}
*/
public function getDetail(array $data)
{
$map[] = ['status', '=', 1];
$map[] = ['is_delete', '=', 0];
$map[] = ['source_id', '=', $data['id']];
$field = 'source_id as id,source_category_id,title,url,create_time as time,vod_content,vod_pic,is_type';
$result = $this->with('category')->where($map)->field($field)->find();
if(!is_null($result)){
$result->inc('page_views')->update();
$result['times'] = substr($result['time'], 0, 10);
}
unset($result['time']);
return $result;
}
/**
* 获取列表
* @access public
* @param array $data 外部数据
* @return array|false
* @throws
*/
public function getList(array $data)
{
// 搜索条件
$map = [];
//默认排序
$order = ['source_id' => 'desc'];
//需要高亮的词 仅分词搜索使用
$searchTitle = [];
$map[] = ['status', '=', 1];
$map[] = ['is_time', '=', 0];
$map[] = ['is_delete', '=', 0];
if(!empty($data['day']) && $data['day']==2){
// 获取今天的时间戳范围
$todayStart = strtotime(date('Y-m-d'));
$todayEnd = $todayStart + 86400; // 86400 秒 = 24 小时
// 获取昨天的时间戳范围
$yesterdayStart = $todayStart - 86400;
$yesterdayEnd = $todayStart;
// 添加日期范围条件
$map[] = ['create_time', 'between', [$yesterdayStart, $todayEnd]];
//记录站点更新日志
$ip = $_SERVER['REMOTE_ADDR'];
$ips = Log::where(['ip'=>$ip])->find();
if(empty($ips)){
Log::save(['name' => '访问记录','ip'=>$ip]);
}else{
Log::where('id', $ips['id'])->update(['update_time' => time()]);
}
}
if(!empty($data['is_time']) && $data['is_time']==1){
unset($map[array_search(['is_time', '=', 0], $map)]);
}
if(!empty($data['category_id'])){
// 将逗号分隔的字符串转换为数组
$categoryIds = explode(',', $data['category_id']);
// 使用 in 查询
$map[] = ['source_category_id', 'in', $categoryIds];
}
if(!empty($data['type']) && $data['type']==2){
$map[] = ['is_type', '=', 0];
}
// 如果存在 title,则进行分词
if (!empty($data['title'])) {
$search_type = config('qfshop.search_type')??1;
if($search_type == 0){
$map[] = ['title|description', 'like', '%' . trim($data['title']) . '%'];
$query = $this->where($map);
}else{
$fc = new VicWord();
$keywords = $fc->getAutoWord($data['title']);
$keywords = filterAndExtractWords($keywords);
// 如果分词后有关键词
if (count($keywords) > 1) {
if($search_type == 1){
//分词同时满足才搜索的到!
foreach ($keywords as $keyword) {
$map[] = ['title|description', 'like', '%' . $keyword . '%'];
}
$query = $this->where($map);
}else{
// 分词只要满足其一就可以搜索到!
$weightExpr = [];
foreach ($keywords as $keyword) {
$weightExpr[] = "IF(title LIKE '%{$keyword}%' OR description LIKE '%{$keyword}%', 1, 0)";
$searchTitle[] = $keyword;
}
$weightExpr = implode(' + ', $weightExpr);
// 在查询中添加权重计算和排序
$query = $this->alias('a')
->field('a.*, (' . $weightExpr . ') as weight')->where($map)
->where(function($query) use ($keywords) {
foreach ($keywords as $keyword) {
$query->whereOr('title', 'like', '%' . trim($keyword) . '%')
->whereOr('description', 'like', '%' . trim($keyword) . '%');
}
});
$order = ['weight' => 'desc', 'source_id' => 'desc'];
}
} else {
// 如果没有关键词,仍然使用原来的 title 查询
$map[] = ['title|description', 'like', '%' . trim($data['title']) . '%'];
$query = $this->where($map);
}
}
}else{
// 构建查询
$query = $this->where($map);
}
if(!empty($data['type']) && $data['type']==2){
$order = ['source_id' => 'asc'];
}
$result['total_result'] = $query->count();
if ($result['total_result'] <= 0) {
$result['items'] = [];
return $result;
}
// 获取分页数据
$result['items'] = $query->order($order)
->field('source_id as id, source_category_id, title, is_type, code, url, update_time as time, is_time')
->with('category')
->withSearch(['page', 'order'], $data)
->select()->each(function($item) use ($searchTitle) {
$item['name'] = highlightKeywords($item['title'], $searchTitle);
$item['times'] = substr($item['time'], 0, 10);
unset($item['time']);
return $item;
})
->toArray();
// 如果 $data['is_time'] == 1,则更新 update_time 字段
if (!empty($data['is_time']) && $data['is_time'] == 1) {
// 获取所有需要更新的ID
$ids = [];
foreach ($result['items'] as $item) {
if ($item['is_time'] == 1) {
$ids[] = $item['id'];
}
}
// 更新数据库中的 update_time 字段
if (!empty($ids)) {
$this->whereIn('source_id', $ids)->update(['update_time' => time()]);
}
}
return $result;
}
/**
* 获取最新
* @access public
* @param array $data 外部数据
* @return array|false
* @throws
*/
public function getNew(array $data)
{
// 搜索条件
$map = [];
$map[] = ['status', '=', 1];
$map[] = ['is_time', '=', 0];
$result['total_result'] = $this->where($map)->count();
if ($result['total_result'] <= 0) {
return $result;
}
$result['items'] = $this->setDefaultOrder(['create_time' => 'desc'])
->field('title,create_time as time')
->where($map)
->withSearch(['page', 'order'], $data)
->select()->each(function($item,$key){
$item['times'] = substr($item['time'], 5, 5);
unset($item['time']);
return $item;
})
->toArray();
return $result;
}
/**
* 获取最热
* @access public
* @param array $data 外部数据
* @return array|false
* @throws
*/
public function getHot(array $data)
{
$urlData = array(
'endDay' => date("Y-m-d", strtotime("-1 day")),
'startDay' => date("Y-m-d", strtotime("-1 day"))
);
$urlHeader = array('Content-Type: application/json');
//线路2
$res = curlHelper("https://sycsp-prd.matesec.net/api/sp/miniApp/seriesRankList", "POST", json_encode($urlData),$urlHeader)['body'];
$res = json_decode($res, true);
if($res['code'] !== 200){
return jerr($res['msg']);
}
if(empty($res['data']['seriesHeatRankList'])){
$urlData = array(
'endDay' => date("Y-m-d", strtotime("-2 day")),
'startDay' => date("Y-m-d", strtotime("-2 day"))
);
$urlHeader = array('Content-Type: application/json');
//线路2
$res = curlHelper("https://sycsp-prd.matesec.net/api/sp/miniApp/seriesRankList", "POST", json_encode($urlData),$urlHeader)['body'];
$res = json_decode($res, true);
if($res['code'] !== 200){
return jerr($res['msg']);
}
}
$ranking = 1;
$result = [];
foreach ($res['data']['seriesHeatRankList'] as $value) {
$result[] = [
'ranking' => $ranking++,
'title' => $value['seriesName']??'',
'hot' => $value['heatCount']??0,
'hots' => $value['heatCountDisplay']??'',
];
}
return $result;
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace app\model;
use app\model\QfShop;
class SourceCategory extends QfShop
{
/**
* 获取列表
* @access public
* @param array $data 外部数据
* @return array|false
* @throws
*/
public function getList(array $data)
{
// 搜索条件
$map = [];
$map[] = ['status', '=', 0];
$result = $this->where($map)->order('sort', 'desc')->select();
return $result;
}
}
+79
View File
@@ -0,0 +1,79 @@
<?php
namespace app\model;
use app\model\QfShop;
class SourceLog extends QfShop
{
/**
* 主键
* @var string
*/
protected $pk = 'source_log_id';
/**
* 是否需要自动写入时间戳
* @var bool
*/
protected $autoWriteTimestamp = true;
/**
* 只读属性
* @var array
*/
protected $readonly = [
'source_log_id',
];
/**
* 字段类型或者格式转换
* @var array
*/
protected $type = [
'source_log_id' => 'integer',
'end_time' => 'timestamp',
];
public function addLog($name="任务名称",$total_num=0)
{
try {
$Log = [
'name' => $name,
'total_num' => $total_num,
'create_time' => time(),
'update_time' => time(),
];
$logId = $this->insertGetId($Log);
return $logId;
} catch (\Throwable $th) {
//throw $th;
}
}
public function editLog($source_log_id,$total_num,$edit_name,$fail_dec='',$type=0)
{
try {
$data = [];
$data['total_num'] = $total_num;
if(!empty($fail_dec)){
$data['fail_dec'] = $fail_dec;
}
$data['update_time'] = time();
if($type==3){
$this->where('source_log_id', $source_log_id)
->update(['end_time' => time()]);
}else{
if($type==1){
$data['end_time'] = time();
}
$this->where('source_log_id', $source_log_id)
->inc($edit_name)
->update($data);
}
} catch (\Throwable $th) {
//throw $th;
}
}
}
+83
View File
@@ -0,0 +1,83 @@
<?php
namespace app\model;
use app\model\QfShop;
class Token extends QfShop
{
/**
* 创建更新一个新的授权
*
* @param [int] 用户ID
* @param [plat] 授权平台
* @return 授权信息|false
*/
public function createAccess($user_id, $platform)
{
$token = $this->where([
"user_id" => $user_id,
"platform" => $platform
])->find();
//生成一个新的Access_token
$access_token = sha1(time()) . rand(100000, 99999) . sha1(time());
$expires = time() + (30 * 24 * 60 * 60); // 30天
if($token){
//如果已有token 执行更新
$token_id = $token['token_id'];
$this->where('token_id',$token_id)->update([
"token" => $access_token,
"ip" => request()->ip(),
"token_expires" => $expires,
"create_time" => time(),
]);
}else{
//如果没有token 执行新增
$token_id = $this->insertGetId([
"user_id" => $user_id,
"platform" => $platform,
"token" => $access_token,
"ip" => request()->ip(),
"token_expires" => $expires,
"create_time" => time(),
]);
}
$access = $this->where("token_id", $token_id)->find();
return $access ?? false;
}
/**
* 授权校验
*
* @param string token
* @return void
* 校验成功 更新授权码过期时间
*/
public function getToken($access_token)
{
$token = $this->where([
"token" => $access_token
])->find();
if ($token) {
if (time() > $token['token_expires']) {
return false;
}
$expires = time() + (30 * 24 * 60 * 60); // 30天
$this->where([
"token_id" => $token['token_id'],
])->update([
'token_expires' => $expires
]);
$user = User::field("user_id,status,mobile")->where(["user_id" => $token['user_id'],"is_delete" => 0])->find();
if(!$user){
return jerr("账号不存在");
}
if ($user['status'] == 0) {
return jerr("你的账户被禁用");
}
return $user;
} else {
return false;
}
}
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace app\model;
use app\model\QfShop;
class User extends QfShop
{
}
+108
View File
@@ -0,0 +1,108 @@
<?php
namespace app\model;
//验证码类
class Validate
{
private $charset = 'abcdefghkmnprstuvwxyzABCDEFGHKMNPRSTUVWXYZ23456789'; //随机因子
private $code; //验证码
private $codelen = 4; //验证码长度
private $width = 130; //宽度
private $height = 50; //高度
private $img; //图形资源句柄
private $font; //指定的字体
private $fontsize = 20; //指定字体大小
private $fontcolor; //指定字体颜色
//构造方法初始化
public function __construct()
{
$this->font = $_SERVER['DOCUMENT_ROOT'] . '/static/admin/css/fonts/code.ttc';
}
//生成随机码
private function createCode()
{
$_len = strlen($this->charset) - 1;
for ($i = 0; $i < $this->codelen; $i++) {
$this->code .= $this->charset[mt_rand(0, $_len)];
}
}
//生成背景
private function createBg()
{
$this->img = imagecreatetruecolor($this->width, $this->height);
$color = imagecolorallocate($this->img, mt_rand(157, 255), mt_rand(157, 255), mt_rand(157, 255));
imagefilledrectangle($this->img, 0, $this->height, $this->width, 0, $color);
}
//生成文字
private function createFont()
{
$_x = $this->width / $this->codelen;
for ($i = 0; $i < $this->codelen; $i++) {
$this->fontcolor = imagecolorallocate($this->img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156));
imagettftext($this->img, $this->fontsize, mt_rand(-30, 30), $_x * $i + mt_rand(1, 5), $this->height / 1.4, $this->fontcolor, $this->font, $this->code[$i]);
}
}
//生成线条、雪花
private function createLine()
{
for ($i = 0; $i < 6; $i++) {
$color = imagecolorallocate($this->img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156));
imageline($this->img, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $color);
}
for ($i = 0; $i < 100; $i++) {
$color = imagecolorallocate($this->img, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255));
imagestring($this->img, mt_rand(1, 5), mt_rand(0, $this->width), mt_rand(0, $this->height), '*', $color);
}
}
//对外生成
public function getImg()
{
$this->createBg();
$this->createCode();
$this->createLine();
$this->createFont();
imagepng($this->img);
$image_data = ob_get_contents();
ob_end_clean();
imagedestroy($this->img);
return "data:image/png;base64," . base64_encode($image_data);
}
//获取验证码
public function getCode()
{
return strtolower($this->code);
}
/**
* 验证图形验证码
*
* @return void
*/
public function validateImgCode($token, $code)
{
if (!$token) {
return jerr("TOKEN参数丢失");
}
if (!$code) {
return jerr("请输入验证码");
}
$code = strtoupper($code);
$token = $token;
$_code = cache($token);
if (!$_code) {
return jerr("验证码已过期");
}
if ($code != $_code) {
return jerr('验证码错误');
}
// 删除设置的缓存
cache($token, null);
return null;
}
}
+310
View File
@@ -0,0 +1,310 @@
<!DOCTYPE html>
<html dir="ltr" lang="zh">
<head>
<meta charset="utf-8">
<meta name="theme-color" content="#fff">
<meta name="viewport" content="initial-scale=1, minimum-scale=1, width=device-width">
<title>系统错误</title>
<style>
a {
color: var(--link-color);
}
body {
--background-color: #fff;
--error-code-color: var(--google-gray-700);
--google-blue-100: rgb(210, 227, 252);
--google-blue-300: rgb(138, 180, 248);
--google-blue-600: rgb(26, 115, 232);
--google-blue-700: rgb(25, 103, 210);
--google-gray-100: rgb(241, 243, 244);
--google-gray-300: rgb(218, 220, 224);
--google-gray-500: rgb(154, 160, 166);
--google-gray-50: rgb(248, 249, 250);
--google-gray-600: rgb(128, 134, 139);
--google-gray-700: rgb(95, 99, 104);
--google-gray-800: rgb(60, 64, 67);
--google-gray-900: rgb(32, 33, 36);
--heading-color: var(--google-gray-900);
--primary-button-fill-color-active: var(--google-blue-700);
--primary-button-fill-color: var(--google-blue-600);
--primary-button-text-color: #fff;
--text-color: var(--google-gray-700);
background: var(--background-color);
color: var(--text-color);
word-wrap: break-word;
}
html {
-webkit-text-size-adjust: 100%;
font-size: 125%;
}
.icon {
background-repeat: no-repeat;
background-size: 100%;
}
@media (prefers-color-scheme: dark) {
body.captive-portal,
body.dark-mode-available,
body.neterror,
body.supervised-user-block,
.offline body {
--background-color: var(--google-gray-900);
--error-code-color: var(--google-gray-500);
--heading-color: var(--google-gray-500);
--link-color: var(--google-blue-300);
--primary-button-fill-color-active: rgb(129, 162, 208);
--primary-button-fill-color: var(--google-blue-300);
--primary-button-text-color: var(--google-gray-900);
--text-color: var(--google-gray-500);
}
}
</style>
<style>
button {
border: 0;
border-radius: 4px;
box-sizing: border-box;
color: var(--primary-button-text-color);
cursor: pointer;
float: right;
font-size: .875em;
margin: 0;
padding: 8px 16px;
transition: box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
}
[dir='rtl'] button {
float: left;
}
.ssl button {
background: var(--primary-button-fill-color);
}
button:active {
background: var(--primary-button-fill-color-active);
outline: 0;
}
h1 {
color: var(--heading-color);
font-size: 1.6em;
font-weight: normal;
line-height: 1.25em;
margin-bottom: 16px;
}
h2 {
font-size: 1.2em;
font-weight: normal;
}
.icon {
height: 72px;
margin: 0 0 40px;
width: 72px;
}
.interstitial-wrapper {
box-sizing: border-box;
font-size: 1em;
line-height: 1.6em;
margin: 14vh auto 0;
max-width: 600px;
width: 100%;
}
#main-message>p {
display: inline;
}
.nav-wrapper {
margin-top: 51px;
}
.nav-wrapper::after {
clear: both;
content: '';
display: table;
width: 100%;
}
@media (max-width: 700px) {
.interstitial-wrapper {
padding: 0 10%;
}
}
@media (max-width: 420px) {
button,
[dir='rtl'] button{
float: none;
font-size: .825em;
font-weight: 500;
margin: 0;
width: 100%;
}
button {
padding: 16px 24px;
}
.interstitial-wrapper {
padding: 0 5%;
}
.nav-wrapper {
margin-top: 30px;
}
}
@media (min-width: 240px) and (max-width: 420px) and (min-height: 401px),
(min-width: 421px) and (min-height: 240px) and (max-height: 560px) {
body .nav-wrapper {
background: var(--background-color);
bottom: 0;
box-shadow: 0 -22px 40px var(--background-color);
left: 0;
margin: 0 auto;
max-width: 736px;
padding-left: 24px;
padding-right: 24px;
position: fixed;
right: 0;
width: 100%;
z-index: 2;
}
.interstitial-wrapper {
max-width: 736px;
}
}
@media (max-width: 420px) and (orientation: portrait),
(max-height: 560px) {
body {
margin: 0 auto;
}
button,
[dir='rtl'] button,
button.small-link {
font-family: Roboto-Regular, Helvetica;
font-size: .933em;
margin: 6px 0;
transform: translatez(0);
}
.nav-wrapper {
box-sizing: border-box;
padding-bottom: 8px;
width: 100%;
}
h1 {
font-size: 1.5em;
margin-bottom: 8px;
}
.icon {
margin-bottom: 5.69vh;
}
.interstitial-wrapper {
box-sizing: border-box;
margin: 7vh auto 12px;
padding: 0 24px;
position: relative;
}
.interstitial-wrapper p {
font-size: .95em;
line-height: 1.61em;
margin-top: 8px;
}
}
@media (min-width: 421px) and (min-height: 500px) and (max-height: 560px) {
.interstitial-wrapper {
margin-top: 10vh;
}
}
@media (min-height: 400px) and (orientation:portrait) {
.interstitial-wrapper {
margin-bottom: 145px;
}
}
@media (min-height: 299px) {
.nav-wrapper {
padding-bottom: 16px;
}
}
@media (min-height: 500px) and (max-height: 650px) and (max-width: 414px) and (orientation: portrait) {
.interstitial-wrapper {
margin-top: 7vh;
}
}
@media (min-height: 650px) and (max-width: 414px) and (orientation: portrait) {
.interstitial-wrapper {
margin-top: 10vh;
}
}
.ssl .icon {
background-image: -webkit-image-set(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAABAlBMVEUAAADcRTfcRDfdRET/gIDcRjr/ZmbjVTncRDfcRTfcRDfdRDzgSTncRDjeSDvcRTjbRDfbRDjeRzvcRjfbRjjcRTjcRTjcRTfdRTfcRDjdRTjcRTjbRDjbRTjbRTjbRTfcRjjdRDrcRjfbRTjZQzfcRDjZRDfZRzbWQzXXRDXXQzbXQzbWQjXYSDvWQjbbRDfOQDPSQTTUQjXCPDDNPzPJPjLGPTHVQjXMPzPRQTTWQjXLPzPDPDHYQzbAOzDTQTXHPTLIPjK8Oi++Oy/FPTHEPTHPQDTQQDTUQTXBPDDKPjK/OzC9Oi/////PQDPRQDS3OS66OS7TQTTEPDHXQjbMPjMBhLaWAAAAL3RSTlMA4tgPAhYFCcL98B4x9ie1+s49WICbqXNKZY3pjuqcgVdLZnL2qKg9zmXpjfontV8LANsAAAJrSURBVHhe7ZTnduIwFAY3ARIgBAg9vW1v173ROylby/u/yso2Fx3MNaxs9h/zAHM+Sfa8+M/s2LFjx+3tdjwH+/sHWxHVAerb8KSyANnUFkRXwLiK78llgJHJxRalwSMd11OGOeV4nsM9FO0dxhJdw4LrOJ6jYy46PoohqgEHatE9JViiFNWTPIElTpIRRXcQ4C6aJ3EJAS4TkUQXsMJFFE++CCsU8xFEBSAoiHsaQNIQ7yuQCFe3DiHUhftKIlzdKoRSFe0r8sXDAkSoumkIigYaIOkIfeWi56EESFm8r1w0fFIl4epWgBA9qOMpmirCfeWijtoa9WSx6taAELFBRl/vilS3BJRIbRk9/VFTsLrifUXRuNfXLU0y/7m6p0CKxqN+v6lJU/k3eJxu7Os5LWKDHi1tYstKG1zON1X3DGiRMR80Mx3fdCbc1+bQe3o2SJrYXcV0fFMxL9xXiz0987BBtux65qaCeF8lHCR3FabBTQ3xvk4M1yN5B/Mw2+urew8hTP1BM38Qnu5evK8gMw+7IcfH9E3ZlEBfMSO//Kf35+Cm6ua+rhbSYDeEa9CUyW3qK1HIjj5DBz8dWd0bWCd6Ult/uMPEr+BmbV/JHrVG/a9MsEybV5fsK50R3frmBFXtCtVXmt73H4PhQ4t9k9rkJ55tYXwZrO4rCEUfPHfUEcuaZC/umw97TfaVpslu2tCb2lRWnBlKFtf+huwrjaa6Pxv7RfgW7nubJPtKI/X0puQO4k/Pfe/ovtLY7KbxVwve0/sE3VeaLosIbkEDvt8Hoq/hKGwQYvoq5OMnoq/hLAbgc/FVn33PX7pAfE5QHR6fAAAAAElFTkSuQmCC) 1x,
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAMAAADQmBKKAAABTVBMVEUAAADcRDf/ZmbcRjrjVTn/gIDdRETdRDzZQzbXQzXWQzbXQjbWQzXZRDbbRDnWQjXWQzXYSDvbRTjcRTjbRTfcRjfcRTjcRTjdRjncRTfdRTndRTfdRDrbRTjcRDnbRDfbRDjbRjfcRjfbRTjcRTjdRTjbRjjcRTjcRDjcRjncRTncRTndRDnbRTjcRDfZQzbcRTfgSTncRDfcRjjZQzjcRTfVRDbcRDjcRDjWQzXeRzvbRDjXRDXXQzbXQzbbRDfeSDvWQjbVQjXIPjLOQDPXQjbCPDDNPzPUQTXRQTS5OS7QQDTUQjW3OS7SQTTPQDTFPDHJPjK2OC26OS7HPjHOPzPLPjLMPjPRQDTGPDHTQTTEPTHLPzPGPTG7Oi/HPTLKPjLTQTXYQza9Oi/MPzPFPTHDPDHBPDC/OzC+Oy+8Oi/AOzDWQjX////bRDd3undHAAAAQnRSTlMA2AUWCQIPHj39wvbO8DH64ifqqYFmtrVMc1lKS5x0nY6PWKqbjYDpZXWCZ1py8Jv9McJXV+KA9qioPc5l6Y36J7VmcHe8AAAFWUlEQVR4XuzWS4rCQBSG0euz56ISgiaEjHwgGhAhDnRF3/6HDY1Ia5WPjP4a3LOKY28555xzzjnnnHPOuSyzpPR7vb6lZAUrS8hgB7uBpaMEKC0Zhz3A/mCpaPjTWCK23GwtCcMjN8ehpWDN3doS8HPi7vRjejX/1CbX8qA1sdGZB+eRaW14sjGp8YQnk7EpVQQqE7peCFyupjMnYm4yGVGZ7q1EyTZbEEche2uUbLMlL5W6t4Zkm22Ikm02561c89aQbLNTPpgq3hqSbbbmo1r41rhW8NaAaLMzvjITvDUg2WzFlyrBWwOCzc6Jkm12QQcL3Vtlmy3opFC9VbbZJR0tNW+Vbbahs0b41rhc8FbVZqdEyTb724t5/bYNA3G4e+80NYI0gGFkvaR779KKZUWuFKe7nlIsT5X//2M5VMZiZB9DQj74xW8ffrwjP90Mb/07Vf5CbXYJg0BtO4toKS9vhYHGY1vDZg28FQY6tBZls8tYBehwNLTyt1nhrTDQaDQcWAux2SJWAxpOBpWMWSvm4q0w0Gg4nFQqFTd/m72HlYBYQJV+w83bZu9jRaDJYEB4osjJ02aFt8JASUBRq+PlarMrWBGI8lQajVanXA5kopUcvBUEGrCAWhSoXs3PZtewKhA/MMbTbcpEa7l4KwwURZSHANnVnGz2CVYGmg6oZ1u1XGy2hNWBCA8BogE1m7Zl+ShNVMrdW2Wg/v+Amr2eRYCcGLBZU2+FgcSBESDfdZxdwGbNvBUGihKgnk1OjPAEwS5gsybeCgNNdTQLyAtqtRCwWQNvhYH4ndjtNnlAnlet1uIQsFl9b4WBpgNyaUCEJ45DwGa1vRUGanU6nMcmB+ZSnlosES3nvm/tUpGm1tFPd5DDAyKFBJGpzRaxSjW5J0o8/MAQ4ZEyKua/b+0Np175blMERDuaECFBZGqzBaxY9iAjIMbDK01U0OVZxcplE6BIjLzFRixgQDwflCJaXcC+1ToKyOYHFvCOljPiNmvurTBRI+oQoGTk2Z1YQyIeiWhlEftWnx8Yf8RcyiMCEkyhic2u4xOWSw9MBBQENTQFI83a+iL2rdgpJ1rms45mByYzhbDNwt6qTtTlQC7r6FT/CLRQ02ZLWKc8OmK+LzooCykhKpl4q7p+7B/d0SjNggRbqGOzm1gPqL3PX3niZakOQsenf1PDWzWAxr+JBtEDQxnnJTISNmvurfBK75t45bORBNGSobcqb9DqBCjdQOl5E370xthbYaDRiIjRDxKQwJk9a+o2u431gYZERBo/kcBIfvJ/TrSt6K1b+kDUHMkra2V3j5zRlprNbmADILbQ65S/z2ggyY82zL0VXsdQnnLdhSOKQzWbLWADIMpDgOrd3q958QiigrG3wusYzmNbXmY4sh+tangrVJ2Dgy97X9v0CmILzzIHcj3ZPTL+h6DN7mhYR5nxHI4mtKNbLCAmaX9QDDKFO6C36hDttcdJQFGLeTWRIupocGOj62cBb9WqesLTFwfm000MQgqz9lDLW+Hve35HM9Fnqw9HetBkNsF6+Yaet8Jf0+xbka0XbYspSMIg+5D8/8psnqdYv3qso1vsS9Hy6SaGQ6AYHP9ngLdqllVpiIB8RygRQjGEdOsc4K26RGzk6YTxjhbDDdzXcfwC8Fbd8glPnR4Y62gBAM/a1WybfYVNyyUBiZFPXYCAH70GvFW7nFRHH7EgyI8uAd6qXZ7NAqoilG6ZKuBH184D3qpdAQlIWp0p9dE7wFv1q8Y6+njLoPl+9P4C4K0GRKSjgTyywvoAeKtBxVWU6YhorovcvA14q0HtouwU0Fw/+jzN8w/cQ/zg6ug2/QAAAABJRU5ErkJggg==) 2x);
}
</style>
</head>
<body id="body" class="ssl extended-reporting-has-checkbox">
<div class="interstitial-wrapper">
<div id="main-content">
<div class="icon" id="icon"></div>
<div id="main-message">
<h1>系统发生错误:</h1>
<p>虽然不知道错在哪,但是确实出了点小问题...</p>
</div>
</div>
<div class="nav-wrapper">
<a href="javascript:history.go(-1);"><button id="primary-button">好的,我知道了</button></a>
</div>
</div>
<style>
html {
direction: ltr;
}
body {
font-family: system-ui, PingFang SC, STHeiti, sans-serif;
font-size: 75%;
}
button {
font-family: system-ui, PingFang SC, STHeiti, sans-serif;
}
</style>
</body>
</html>
+585
View File
@@ -0,0 +1,585 @@
<?php
/** @var array $traces */
if (!function_exists('parse_padding')) {
function parse_padding($source)
{
$length = strlen(strval(count($source['source']) + $source['first']));
return 40 + ($length - 1) * 8;
}
}
if (!function_exists('parse_class')) {
function parse_class($name)
{
$names = explode('\\', $name);
return '<abbr title="' . $name . '">' . end($names) . '</abbr>';
}
}
if (!function_exists('parse_file')) {
function parse_file($file, $line)
{
return '<a class="toggle" title="' . "{$file} line {$line}" . '">' . basename($file) . " line {$line}" . '</a>';
}
}
if (!function_exists('parse_args')) {
function parse_args($args)
{
$result = [];
foreach ($args as $key => $item) {
switch (true) {
case is_object($item):
$value = sprintf('<em>object</em>(%s)', parse_class(get_class($item)));
break;
case is_array($item):
if (count($item) > 3) {
$value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3)));
} else {
$value = sprintf('[%s]', parse_args($item));
}
break;
case is_string($item):
if (strlen($item) > 20) {
$value = sprintf(
'\'<a class="toggle" title="%s">%s...</a>\'',
htmlentities($item),
htmlentities(substr($item, 0, 20))
);
} else {
$value = sprintf("'%s'", htmlentities($item));
}
break;
case is_int($item):
case is_float($item):
$value = $item;
break;
case is_null($item):
$value = '<em>null</em>';
break;
case is_bool($item):
$value = '<em>' . ($item ? 'true' : 'false') . '</em>';
break;
case is_resource($item):
$value = '<em>resource</em>';
break;
default:
$value = htmlentities(str_replace("\n", '', var_export(strval($item), true)));
break;
}
$result[] = is_int($key) ? $value : "'{$key}' => {$value}";
}
return implode(', ', $result);
}
}
if (!function_exists('echo_value')) {
function echo_value($val)
{
if (is_array($val) || is_object($val)) {
echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));
} elseif (is_bool($val)) {
echo $val ? 'true' : 'false';
} elseif (is_scalar($val)) {
echo htmlentities($val);
} else {
echo 'Resource';
}
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>系统发生错误</title>
<meta name="robots" content="noindex,nofollow" />
<style>
/* Base */
body {
color: #333;
font: 16px Verdana, "Helvetica Neue", helvetica, Arial, 'Microsoft YaHei', sans-serif;
margin: 0;
padding: 0 20px 20px;
}
h1 {
margin: 10px 0 0;
font-size: 28px;
font-weight: 500;
line-height: 32px;
}
h2 {
color: #4288ce;
font-weight: 400;
padding: 6px 0;
margin: 6px 0 0;
font-size: 18px;
border-bottom: 1px solid #eee;
}
h3 {
margin: 12px;
font-size: 16px;
font-weight: bold;
}
abbr {
cursor: help;
text-decoration: underline;
text-decoration-style: dotted;
}
a {
color: #868686;
cursor: pointer;
}
a:hover {
text-decoration: underline;
}
.line-error {
background: #f8cbcb;
}
.echo table {
width: 100%;
}
.echo pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f7f7f7;
border: 0;
border-radius: 3px;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.echo pre>pre {
padding: 0;
margin: 0;
}
/* Exception Info */
.exception {
margin-top: 20px;
}
.exception .message {
padding: 12px;
border: 1px solid #ddd;
border-bottom: 0 none;
line-height: 18px;
font-size: 16px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .code {
float: left;
text-align: center;
color: #fff;
margin-right: 12px;
padding: 16px;
border-radius: 4px;
background: #999;
}
.exception .source-code {
padding: 6px;
border: 1px solid #ddd;
background: #f9f9f9;
overflow-x: auto;
}
.exception .source-code pre {
margin: 0;
}
.exception .source-code pre ol {
margin: 0;
color: #4288ce;
display: inline-block;
min-width: 100%;
box-sizing: border-box;
font-size: 14px;
font-family: "Century Gothic", Consolas, "Liberation Mono", Courier, Verdana, serif;
padding-left: <?php echo (isset($source) && !empty($source)) ? parse_padding($source) : 40; ?>px;
}
.exception .source-code pre li {
border-left: 1px solid #ddd;
height: 18px;
line-height: 18px;
}
.exception .source-code pre code {
color: #333;
height: 100%;
display: inline-block;
border-left: 1px solid #fff;
font-size: 14px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .trace {
padding: 6px;
border: 1px solid #ddd;
border-top: 0 none;
line-height: 16px;
font-size: 14px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .trace h2:hover {
text-decoration: underline;
cursor: pointer;
}
.exception .trace ol {
margin: 12px;
}
.exception .trace ol li {
padding: 2px 4px;
}
.exception div:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
/* Exception Variables */
.exception-var table {
width: 100%;
margin: 12px 0;
box-sizing: border-box;
table-layout: fixed;
word-wrap: break-word;
}
.exception-var table caption {
text-align: left;
font-size: 16px;
font-weight: bold;
padding: 6px 0;
}
.exception-var table caption small {
font-weight: 300;
display: inline-block;
margin-left: 10px;
color: #ccc;
}
.exception-var table tbody {
font-size: 13px;
font-family: Consolas, "Liberation Mono", Courier, "微软雅黑", serif;
}
.exception-var table td {
padding: 0 6px;
vertical-align: top;
word-break: break-all;
}
.exception-var table td:first-child {
width: 28%;
font-weight: bold;
white-space: nowrap;
}
.exception-var table td pre {
margin: 0;
}
/* Copyright Info */
.copyright {
margin-top: 24px;
padding: 12px 0;
border-top: 1px solid #eee;
}
/* SPAN elements with the classes below are added by prettyprint. */
pre.prettyprint .pln {
color: #000
}
/* plain text */
pre.prettyprint .str {
color: #080
}
/* string content */
pre.prettyprint .kwd {
color: #008
}
/* a keyword */
pre.prettyprint .com {
color: #800
}
/* a comment */
pre.prettyprint .typ {
color: #606
}
/* a type name */
pre.prettyprint .lit {
color: #066
}
/* a literal value */
/* punctuation, lisp open bracket, lisp close bracket */
pre.prettyprint .pun,
pre.prettyprint .opn,
pre.prettyprint .clo {
color: #660
}
pre.prettyprint .tag {
color: #008
}
/* a markup tag name */
pre.prettyprint .atn {
color: #606
}
/* a markup attribute name */
pre.prettyprint .atv {
color: #080
}
/* a markup attribute value */
pre.prettyprint .dec,
pre.prettyprint .var {
color: #606
}
/* a declaration; a variable name */
pre.prettyprint .fun {
color: red
}
/* a function name */
</style>
</head>
<body>
<?php if (\think\facade\App::isDebug()) { ?>
<?php foreach ($traces as $index => $trace) { ?>
<div class="exception">
<div class="message">
<div class="info">
<div>
<h2><?php echo "#{$index} [{$trace['code']}]" . sprintf('%s in %s', parse_class($trace['name']), parse_file($trace['file'], $trace['line'])); ?></h2>
</div>
<div>
<h1><?php echo nl2br(htmlentities($trace['message'])); ?></h1>
</div>
</div>
</div>
<?php if (!empty($trace['source'])) { ?>
<div class="source-code">
<pre class="prettyprint lang-php"><ol start="<?php echo $trace['source']['first']; ?>"><?php foreach ((array) $trace['source']['source'] as $key => $value) { ?><li class="line-<?php echo "{$index}-";
echo $key + $trace['source']['first'];
echo $trace['line'] === $key + $trace['source']['first'] ? ' line-error' : ''; ?>"><code><?php echo htmlentities($value); ?></code></li><?php } ?></ol></pre>
</div>
<?php } ?>
<div class="trace">
<h2 data-expand="<?php echo 0 === $index ? '1' : '0'; ?>">Call Stack</h2>
<ol>
<li><?php echo sprintf('in %s', parse_file($trace['file'], $trace['line'])); ?></li>
<?php foreach ((array) $trace['trace'] as $value) { ?>
<li>
<?php
// Show Function
if ($value['function']) {
echo sprintf(
'at %s%s%s(%s)',
isset($value['class']) ? parse_class($value['class']) : '',
isset($value['type']) ? $value['type'] : '',
$value['function'],
isset($value['args']) ? parse_args($value['args']) : ''
);
}
// Show line
if (isset($value['file']) && isset($value['line'])) {
echo sprintf(' in %s', parse_file($value['file'], $value['line']));
}
?>
</li>
<?php } ?>
</ol>
</div>
</div>
<?php } ?>
<?php } else { ?>
<div class="exception">
<div class="info">
<h1><?php echo htmlentities($message); ?></h1>
</div>
</div>
<?php } ?>
<?php if (!empty($datas)) { ?>
<div class="exception-var">
<h2>Exception Datas</h2>
<?php foreach ((array) $datas as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array) $value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
<?php } ?>
</table>
<?php } ?>
</div>
<?php } ?>
<?php if (!empty($tables)) { ?>
<div class="exception-var">
<h2>Environment Variables</h2>
<?php foreach ((array) $tables as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array) $value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
<?php } ?>
</table>
<?php } ?>
</div>
<?php } ?>
<?php if (\think\facade\App::isDebug()) { ?>
<script>
function $(selector, node) {
var elements;
node = node || document;
if (document.querySelectorAll) {
elements = node.querySelectorAll(selector);
} else {
switch (selector.substr(0, 1)) {
case '#':
elements = [node.getElementById(selector.substr(1))];
break;
case '.':
if (document.getElementsByClassName) {
elements = node.getElementsByClassName(selector.substr(1));
} else {
elements = get_elements_by_class(selector.substr(1), node);
}
break;
default:
elements = node.getElementsByTagName();
}
}
return elements;
function get_elements_by_class(search_class, node, tag) {
var elements = [],
eles,
pattern = new RegExp('(^|\\s)' + search_class + '(\\s|$)');
node = node || document;
tag = tag || '*';
eles = node.getElementsByTagName(tag);
for (var i = 0; i < eles.length; i++) {
if (pattern.test(eles[i].className)) {
elements.push(eles[i])
}
}
return elements;
}
}
$.getScript = function(src, func) {
var script = document.createElement('script');
script.async = 'async';
script.src = src;
script.onload = func || function() {};
$('head')[0].appendChild(script);
}
;
(function() {
var files = $('.toggle');
var ol = $('ol', $('.prettyprint')[0]);
var li = $('li', ol[0]);
// 短路径和长路径变换
for (var i = 0; i < files.length; i++) {
files[i].ondblclick = function() {
var title = this.title;
this.title = this.innerHTML;
this.innerHTML = title;
}
}
(function() {
var expand = function(dom, expand) {
var ol = $('ol', dom.parentNode)[0];
expand = undefined === expand ? dom.attributes['data-expand'].value === '0' : undefined;
if (expand) {
dom.attributes['data-expand'].value = '1';
ol.style.display = 'none';
dom.innerText = 'Call Stack (展开)';
} else {
dom.attributes['data-expand'].value = '0';
ol.style.display = 'block';
dom.innerText = 'Call Stack (折叠)';
}
};
var traces = $('.trace');
for (var i = 0; i < traces.length; i++) {
var h2 = $('h2', traces[i])[0];
expand(h2);
h2.onclick = function() {
expand(this);
};
}
})();
$.getScript('//cdn.bootcss.com/prettify/r298/prettify.min.js', function() {
prettyPrint();
});
})();
</script>
<?php } ?>
</body>
</html>
+309
View File
@@ -0,0 +1,309 @@
<!DOCTYPE html>
<html dir="ltr" lang="zh">
<head>
<meta charset="utf-8">
<meta name="theme-color" content="#fff">
<meta name="viewport" content="initial-scale=1, minimum-scale=1, width=device-width">
<title>系统操作成功</title>
<style>
a {
color: var(--link-color);
}
body {
--background-color: #fff;
--error-code-color: var(--google-gray-700);
--google-blue-100: rgb(210, 227, 252);
--google-blue-300: rgb(138, 180, 248);
--google-blue-600: rgb(26, 115, 232);
--google-blue-700: rgb(25, 103, 210);
--google-gray-100: rgb(241, 243, 244);
--google-gray-300: rgb(218, 220, 224);
--google-gray-500: rgb(154, 160, 166);
--google-gray-50: rgb(248, 249, 250);
--google-gray-600: rgb(128, 134, 139);
--google-gray-700: rgb(95, 99, 104);
--google-gray-800: rgb(60, 64, 67);
--google-gray-900: rgb(32, 33, 36);
--heading-color: var(--google-gray-900);
--primary-button-fill-color-active: var(--google-blue-700);
--primary-button-fill-color: var(--google-blue-600);
--primary-button-text-color: #fff;
--text-color: var(--google-gray-700);
background: var(--background-color);
color: var(--text-color);
word-wrap: break-word;
}
html {
-webkit-text-size-adjust: 100%;
font-size: 125%;
}
.icon {
background-repeat: no-repeat;
background-size: 100%;
}
@media (prefers-color-scheme: dark) {
body.captive-portal,
body.dark-mode-available,
body.neterror,
body.supervised-user-block,
.offline body {
--background-color: var(--google-gray-900);
--error-code-color: var(--google-gray-500);
--heading-color: var(--google-gray-500);
--link-color: var(--google-blue-300);
--primary-button-fill-color-active: rgb(129, 162, 208);
--primary-button-fill-color: var(--google-blue-300);
--primary-button-text-color: var(--google-gray-900);
--text-color: var(--google-gray-500);
}
}
</style>
<style>
button {
border: 0;
border-radius: 4px;
box-sizing: border-box;
color: var(--primary-button-text-color);
cursor: pointer;
float: right;
font-size: .875em;
margin: 0;
padding: 8px 16px;
transition: box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
}
[dir='rtl'] button {
float: left;
}
.ssl button {
background: var(--primary-button-fill-color);
}
button:active {
background: var(--primary-button-fill-color-active);
outline: 0;
}
h1 {
color: var(--heading-color);
font-size: 1.6em;
font-weight: normal;
line-height: 1.25em;
margin-bottom: 16px;
}
h2 {
font-size: 1.2em;
font-weight: normal;
}
.icon {
height: 72px;
margin: 0 0 40px;
width: 72px;
}
.interstitial-wrapper {
box-sizing: border-box;
font-size: 1em;
line-height: 1.6em;
margin: 14vh auto 0;
max-width: 600px;
width: 100%;
}
#main-message>p {
display: inline;
}
.nav-wrapper {
margin-top: 51px;
}
.nav-wrapper::after {
clear: both;
content: '';
display: table;
width: 100%;
}
@media (max-width: 700px) {
.interstitial-wrapper {
padding: 0 10%;
}
}
@media (max-width: 420px) {
button,
[dir='rtl'] button{
float: none;
font-size: .825em;
font-weight: 500;
margin: 0;
width: 100%;
}
button {
padding: 16px 24px;
}
.interstitial-wrapper {
padding: 0 5%;
}
.nav-wrapper {
margin-top: 30px;
}
}
@media (min-width: 240px) and (max-width: 420px) and (min-height: 401px),
(min-width: 421px) and (min-height: 240px) and (max-height: 560px) {
body .nav-wrapper {
background: var(--background-color);
bottom: 0;
box-shadow: 0 -22px 40px var(--background-color);
left: 0;
margin: 0 auto;
max-width: 736px;
padding-left: 24px;
padding-right: 24px;
position: fixed;
right: 0;
width: 100%;
z-index: 2;
}
.interstitial-wrapper {
max-width: 736px;
}
}
@media (max-width: 420px) and (orientation: portrait),
(max-height: 560px) {
body {
margin: 0 auto;
}
button,
[dir='rtl'] button,
button.small-link {
font-family: Roboto-Regular, Helvetica;
font-size: .933em;
margin: 6px 0;
transform: translatez(0);
}
.nav-wrapper {
box-sizing: border-box;
padding-bottom: 8px;
width: 100%;
}
h1 {
font-size: 1.5em;
margin-bottom: 8px;
}
.icon {
margin-bottom: 5.69vh;
}
.interstitial-wrapper {
box-sizing: border-box;
margin: 7vh auto 12px;
padding: 0 24px;
position: relative;
}
.interstitial-wrapper p {
font-size: .95em;
line-height: 1.61em;
margin-top: 8px;
}
}
@media (min-width: 421px) and (min-height: 500px) and (max-height: 560px) {
.interstitial-wrapper {
margin-top: 10vh;
}
}
@media (min-height: 400px) and (orientation:portrait) {
.interstitial-wrapper {
margin-bottom: 145px;
}
}
@media (min-height: 299px) {
.nav-wrapper {
padding-bottom: 16px;
}
}
@media (min-height: 500px) and (max-height: 650px) and (max-width: 414px) and (orientation: portrait) {
.interstitial-wrapper {
margin-top: 7vh;
}
}
@media (min-height: 650px) and (max-width: 414px) and (orientation: portrait) {
.interstitial-wrapper {
margin-top: 10vh;
}
}
.ssl .icon {
background-image: -webkit-image-set(url(data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20%20style%3d%22fill%3agreen%3bstroke%3awhite%3b%22%20d%3D%22M12%2022C6.477%2022%202%2017.523%202%2012S6.477%202%2012%202s10%204.477%2010%2010-4.477%2010-10%2010zm-1.177-7.86l-2.765-2.767L7%2012.431l3.119%203.121a1%201%200%20001.414%200l5.952-5.95-1.062-1.062-5.6%205.6z%22%2F%3E%3C%2Fsvg%3E) 2x);
}
</style>
</head>
<body id="body" class="ssl extended-reporting-has-checkbox">
<div class="interstitial-wrapper">
<div id="main-content">
<div class="icon" id="icon"></div>
<div id="main-message">
<h1>系统操作成功:</h1>
<p><?php echo $message ? $message : '虽然不知道你干啥了,但是确实操作成功了...'; ?></p>
</div>
</div>
<div class="nav-wrapper">
<a href="<?php echo $url;?>"><button id="primary-button">好的,我知道了</button></a>
</div>
</div>
<style>
html {
direction: ltr;
}
body {
font-family: system-ui, PingFang SC, STHeiti, sans-serif;
font-size: 75%;
}
button {
font-family: system-ui, PingFang SC, STHeiti, sans-serif;
}
</style>
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
<?php
use app\ExceptionHandle;
use app\Request;
// 容器Provider定义文件
return [
'think\Request' => Request::class,
'think\exception\Handle' => ExceptionHandle::class,
];
+162
View File
@@ -0,0 +1,162 @@
<?php
declare(strict_types=1);
namespace app\qfadmin;
use think\App;
use think\facade\View;
use app\model\Admin as AdminModel;
use app\model\Access as AccessModel;
use app\model\Auth as AuthModel;
use app\model\Node as NodeModel;
use app\model\Group as GroupModel;
use app\model\Conf as ConfModel;
/**
* 控制器基础类
*/
abstract class QfShop
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
protected $module;
protected $controller;
protected $action;
//模型
protected $AdminModel;
protected $accessModel;
protected $authModel;
protected $nodeModel;
protected $groupModel;
protected $confModel;
//主键key
protected $pk = '';
//表名称
protected $table = '';
//主键value
protected $pk_value = '';
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
$this->module = "qfadmin";
$this->controller = $this->request->controller() ? $this->request->controller() : "Index";
$this->action = strtolower($this->request->action()) ? strtolower($this->request->action()) : "index";
View::assign('controller', strtolower($this->controller));
View::assign('action', strtolower($this->action));
$this->table = strtolower($this->controller);
$this->pk = $this->table . "_id";
$this->pk_value = input($this->pk);
$this->adminModel = new AdminModel();
$this->accessModel = new AccessModel();
$this->authModel = new AuthModel();
$this->nodeModel = new NodeModel();
$this->groupModel = new GroupModel();
$this->confModel = new ConfModel();
$configs = $this->confModel->select()->toArray();
$c = [];
foreach ($configs as $config) {
$c[$config['conf_key']] = $config['conf_value'];
}
config($c, 'yadmin');
}
/**
* 后台简单的身份判断
*
* @return void
*/
protected function access()
{
$callback = "/qfadmin";
if (strtolower($this->controller) != "index") {
$callback .= "/" . strtolower($this->controller);
}
if ($this->action != "index") {
$callback .= "/" . $this->action;
}
$access_token = cookie('access_token');
if (!$access_token) {
return redirect('/qfadmin/admin/login/?callback=' . urlencode($callback));
}
View::assign("access_token", $access_token);
$this->admin = $this->adminModel->getAdminByAccessToken($access_token);
if (!$this->admin) {
return redirect('/qfadmin/admin/login/?callback=' . urlencode($callback));
}
if ($this->admin['admin_status'] > 0) {
return $this->error("抱歉,你的帐号已被禁用,暂时无法登录系统!");
}
cookie("access_token", $access_token);
View::assign('adminInfo', $this->admin);
$this->group = $this->groupModel->where('group_id', $this->admin['admin_group'])->find();
if ($this->group) {
if ($this->group['group_id'] != 1 && $this->group['group_status'] == 1) {
return $this->error("抱歉,你所在的用户组已被禁用,暂时无法登录系统");
} else {
$menuList = $this->authModel->getAdminMenuListByAdminId($this->group['group_id']);
View::assign('menuList', $menuList);
$node = $this->nodeModel->where(['node_module' => $this->module, 'node_controller' => strtolower($this->controller), 'node_action' => $this->action])->find();
View::assign('node', $node);
if($node['node_pid']==0){
View::assign('menu', 0);
}else{
$res = $this->nodeModel->where('node_id',$node['node_pid'])->find();
View::assign('menu', $res['node_pid']);
}
$menuLists = [];
foreach ($menuList as $key => $value) {
if($value['node_id'] == $node['node_pid']){
$menuLists = $value['subList'];
}else{
foreach ($value['subList'] as $k => $v) {
if($v['node_id'] == $node['node_pid']){
$menuLists = $value['subList'];
}
}
}
}
View::assign('menuLists', $menuLists);
View::assign('action', $this->request->action());
}
} else {
return $this->error("抱歉,没有查到你的用户组信息,暂时无法登录系统");
}
}
protected function error($message)
{
echo $message;
die;
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
namespace app\qfadmin\controller;
use app\qfadmin\QfShop;
use think\facade\View;
class Error extends QfShop
{
/**
* 监听所有请求 渲染对应控制器下方法的页面
*/
public function __call($method, $args)
{
// 判断是否是登录/注册/找回密码
// 否则进行accesss授权验证 如错误 直接返回
if (!(strtolower($this->controller) == "admin" && in_array(strtolower($this->action), ['login', 'resetpassword', 'reg']))) {
$error = $this->access();
if ($error) {
return $error;
}
}else{
cookie('access_token', null);
}
if (key_exists('callback', $args)) {
View::assign('callback', $args['callback']);
} else {
View::assign('callback', '/qfadmin');
}
View::assign('datas', $args);
return View::fetch();
}
}
+449
View File
@@ -0,0 +1,449 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-form :inline="true">
<el-form-item>
<el-button icon="el-icon-plus" size="small" @click="clickAdd" plain>添加</el-button>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-delete" size="small" @click="postMultDelete" plain>批量删除</el-button>
</el-form-item>
<div style="float:right">
<el-form-item>
<el-select placeholder="请选择状态" size="small" v-model="search.admin_status">
<el-option value="" label="全部用户">
</el-option>
<el-option value="0" label="正常用户">
</el-option>
<el-option value="1" label="禁用用户">
</el-option>
</el-select>
</el-form-item>
<el-form-item style="width:120px;">
<el-select placeholder="筛选类别" size="small" v-model="search.filter">
<el-option value="admin_id" label="用户ID">
</el-option>
<el-option value="admin_name" label="用户昵称">
</el-option>
<el-option value="admin_account" label="用户帐号">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-input placeholder="输入关键词搜索" size="small" v-model="search.keyword"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="getList_search" plain>搜索</el-button>
</el-form-item>
</div>
</el-form>
<el-table :data="dataList.data" @selection-change="changeSelection" v-loading="loading">
<el-table-column type="selection" width="50">
</el-table-column>
<el-table-column prop="admin_id" label="ID" width="100">
</el-table-column>
<el-table-column prop="admin_account" label="帐号">
</el-table-column>
<el-table-column prop="admin_name" label="昵称">
</el-table-column>
<el-table-column prop="group_name" label="用户组">
</el-table-column>
<el-table-column prop="admin_ipreg" label="注册IP" width="150">
</el-table-column>
<el-table-column label="最后活跃" width="120">
<template slot-scope="scope">
{{time2string(scope.row.admin_updatetime)}}
</template>
</el-table-column>
<el-table-column label="注册时间" width="120">
<template slot-scope="scope">
{{time2string(scope.row.admin_createtime)}}
</template>
</el-table-column>
<el-table-column label="禁用" width="80">
<template slot-scope="scope">
<el-switch v-model="scope.row.admin_status==1?true:false" active-color="#ff4949"
@change="clickStatus(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template slot-scope="scope">
<el-link type="primary" @click="clickEdit(scope.row)" :underline="false">编辑</el-link>&nbsp;
<el-link type="danger" @click="clickDelete(scope.row)" :underline="false">删除</el-link>
</template>
</el-table-column>
</el-table>
<div class="page">
<el-pagination @size-change="handleSizeChange" :page-sizes="[10, 20, 50, 100,200,500]" :page-size="10"
layout="total, sizes, prev, pager, next, jumper" background @current-change="changeCurrentPage"
:current-page="dataList.current_page" :page-count="dataList.last_page" :total="dataList.total">
</el-pagination>
</div>
<!-- 添加框 -->
<el-dialog title="添加用户" :visible.sync="dialogFormAdd" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formAdd" status-icon :rules="rules" ref="formAdd">
<el-form-item label="帐号" :label-width="formLabelWidth" prop="admin_account">
<el-input size="medium" autocomplete="off" v-model="formAdd.admin_account"></el-input>
</el-form-item>
<el-form-item label="密码" :label-width="formLabelWidth" prop="admin_password">
<el-input size="medium" show-password="true" autocomplete="off" v-model="formAdd.admin_password">
</el-input>
</el-form-item>
<el-form-item label="昵称" :label-width="formLabelWidth" prop="admin_name">
<el-input size="medium" autocomplete="off" v-model="formAdd.admin_name"></el-input>
</el-form-item>
<el-form-item label="邮箱" :label-width="formLabelWidth" prop="admin_email">
<el-input size="medium" autocomplete="off" v-model="formAdd.admin_email"></el-input>
</el-form-item>
<el-form-item label="身份证" :label-width="formLabelWidth" prop="admin_idcard">
<el-input size="medium" autocomplete="off" v-model="formAdd.admin_idcard"></el-input>
</el-form-item>
<el-form-item label="真实姓名" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formAdd.admin_truename"></el-input>
</el-form-item>
<el-form-item label="用户组" :label-width="formLabelWidth">
<el-select size="medium" placeholder="请选择用户组" v-model="formAdd.admin_group">
<el-option v-for="group_add in groupList" :value="group_add.group_id" :label="group_add.group_name">
</el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postAdd">确认添加</el-button>
</div>
</el-dialog>
<!-- 修改框 -->
<el-dialog title="修改用户" :visible.sync="dialogFormEdit" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formEdit" status-icon :rules="rules" ref="formEdit">
<el-form-item label="帐号" :label-width="formLabelWidth" prop="admin_account">
<el-input size="medium" autocomplete="off" v-model="formEdit.admin_account"></el-input>
</el-form-item>
<el-form-item label="密码" :label-width="formLabelWidth" prop="new_password">
<el-input size="medium" show-password="true" autocomplete="off" v-model="formEdit.new_password"
placeholder="不修改请留空">
</el-input>
</el-form-item>
<el-form-item label="昵称" :label-width="formLabelWidth" prop="admin_name">
<el-input size="medium" autocomplete="off" v-model="formEdit.admin_name"></el-input>
</el-form-item>
<el-form-item label="邮箱" :label-width="formLabelWidth" prop="admin_email">
<el-input size="medium" autocomplete="off" v-model="formEdit.admin_email"></el-input>
</el-form-item>
<el-form-item label="身份证" :label-width="formLabelWidth" prop="admin_idcard">
<el-input size="medium" autocomplete="off" v-model="formEdit.admin_idcard"></el-input>
</el-form-item>
<el-form-item label="真实姓名" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formEdit.admin_truename"></el-input>
</el-form-item>
<el-form-item label="用户组" :label-width="formLabelWidth">
<el-select size="medium" placeholder="请选择用户组" v-model="formEdit.admin_group">
<el-option v-for="group_edit in groupList" :value="group_edit.group_id"
:label="group_edit.group_name"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postEdit">确认修改</el-button>
</div>
</el-dialog>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
this.getList();
return {
search: {
admin_status: "",
keyword: "",
filter: "admin_id"
},
formLabelWidth: '80px',
dialogFormAdd: false,
dialogFormEdit: false,
loading: true,
dataList: [],
groupList: [],
selectList: [],
form: {
page: 1,
per_page: 10
},
formAdd: {
admin_group: 1
},
formEdit: {
admin_group: 1
},
rules: {
admin_account: [
{ required: true, message: '帐号必须填写', trigger: 'blur' },
],
admin_name: [
{ required: true, message: '昵称必须填写', trigger: 'blur' },
],
admin_password: [
{ required: true, message: '密码必须填写', trigger: 'blur' },
// { required: true, pattern: /^(?=.*[a-z])(?=.*\d).{6,16}$/, message: '密码必须包含字母和数字(6-16位)', trigger: 'blur' },
],
new_password: [
{ required: true, message: '密码必须填写', trigger: 'blur' },
// { pattern: /^(?=.*[a-z])(?=.*\d).{6,16}$/, message: '密码必须包含字母和数字(6-16位)', trigger: 'blur' },
],
admin_email: [
{ pattern: /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/, message: '邮箱格式不正确', trigger: 'blur' },
],
admin_idcard: [
{ pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '身份证格式不正确', trigger: 'blur' },
],
}
}
},
methods: {
getList_search() {
this.form.page = 1;
this.getList();
},
time2string(timestamps) {
var now = new Date(timestamps * 1000),
y = now.getFullYear(),
m = now.getMonth() + 1,
d = now.getDate();
// return y + "-" + (m < 10 ? "0" + m : m) + "-" + (d < 10 ? "0" + d : d) + " " + now.toTimeString().substr(0, 8);
return (m < 10 ? "0" + m : m) + "-" + (d < 10 ? "0" + d : d) + " " + now.toTimeString().substr(0, 5);
},
handleSizeChange(per_page) {
this.form.per_page = per_page;
this.getList();
},
postMultDelete() {
var that = this;
if (that.selectList.length == 0) {
that.$message.error('未选择任何用户!');
return;
}
this.$confirm('即将删除选中的用户, 是否确认?', '批量删除', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/admin/delete', Object.assign({}, PostBase, {
admin_id: that.selectList.join(",")
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
changeSelection(list) {
var that = this;
that.selectList = [];
for (var index in list) {
that.selectList.push(list[index].admin_id);
}
},
postEdit() {
var that = this;
that.$refs['formEdit'].validate((valid) => {
if (!valid) {
that.$message.error('仔细检查检查,是不是有个地方写得不对?');
return;
}
axios.post('/admin/admin/update', Object.assign({}, PostBase, that.formEdit))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormEdit = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
});
},
postAdd() {
var that = this;
that.$refs['formAdd'].validate((valid) => {
if (!valid) {
that.$message.error('仔细检查检查,是不是有个地方写得不对?');
return;
}
axios.post('/admin/admin/add', Object.assign({}, PostBase, that.formAdd))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormAdd = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
});
},
clickAdd() {
var that = this;
that.formAdd = {
admin_group: 1
};
axios.post('/admin/group/getList', Object.assign({}, PostBase))
.then(function (response) {
that.groupList = response.data.data;
if (response.data.code == CODE_SUCCESS) {
that.dialogFormAdd = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickDelete(row) {
var that = this;
this.$confirm('即将删除这个用户, 是否确认?', '删除提醒', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/admin/delete', Object.assign({}, PostBase, {
admin_id: row.admin_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
clickStatus(row) {
var that = this;
axios.post(row.admin_status ? '/admin/admin/enable' : '/admin/admin/disable', Object.assign({}, PostBase, {
admin_id: row.admin_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickEdit(row) {
var that = this;
that.formEdit = row;
axios.post('/admin/group/getList', Object.assign({}, PostBase))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.groupList = response.data.data;
axios.post('/admin/admin/detail', Object.assign({}, PostBase, {
admin_id: row.admin_id
}))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.formEdit = response.data.data;
that.dialogFormEdit = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
changeCurrentPage(page) {
this.form.page = page;
this.getList();
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/admin/getList', Object.assign({}, PostBase, that.form, that.search))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.dataList = response.data.data;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
console.log(error);
});
},
}
})
</script>
</html>
+263
View File
@@ -0,0 +1,263 @@
<!DOCTYPE html>
<html>
<head>
<title>后台管理系统</title>
<meta charset="UTF-8">
<!-- import CSS -->
<link rel="stylesheet" href="/static/admin/css/element.css">
<link rel="stylesheet" href="/static/admin/css/YAdmin.css">
<style>
.login-container {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
align-items: center;
justify-content: space-around;
min-width: 1280px;
min-height: 800px;
background: url(/static/admin/images/login_bg.jpg) no-repeat;
background-size: 100% 100%;
background-color: #ffffff;
}
.login-container:before{
content: " ";
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: url(/static/admin/images/login_bg_bottom.png) no-repeat;
background-size: 100% 100%;
height: 170px;
}
.login-box img{
width: 720px;
}
.login-border {
display: flex;
justify-content: center;
flex-direction: column;
position: relative;
top: -30px;
right: 100px;
}
.login-main{
background-color: #ffffff;
padding: 35px 45px 15px 45px;
border-radius: 6px;
}
.login-main .vadmin{
font-size: 16px;
font-weight: bold;
color: #6881ec;
line-height: 20px;
padding-bottom: 6px;
}
.login-logo {
margin: 0 0 20px;
}
.login-logo p {
color: #ffffff;
font-size: 25px;
font-weight: bold;
}
.login-submit {
margin-top: 10px;
width: 100%;
}
.login-form {
margin: 10px 0;
}
.login-form .el-form-item__content {
width: 270px;
}
.login-form .el-form-item {
margin-bottom: 26px;
}
.login-form .el-input input {
text-indent: 5px;
border-color: #DCDCDC;
border-radius: 3px;
border: none;
border-bottom: 1px solid #eee;
}
.login-form .el-input .el-input__prefix i {
padding: 0 5px;
font-size: 16px !important;
}
.login-code {
display: flex;
align-items: center;
justify-content: space-around;
margin-left: 10px;
cursor: pointer;
}
.login-code-img {
margin-top: 1px;
width: 100px;
height: 38px;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<div id="app" v-cloak>
<div class="login-container">
<div class="login-box">
<img src="/static/admin/images/login_bg_box.png">
</div>
<div class="login-border">
<div class="login-logo">
<p>后台登录</p>
</div>
<div class="login-main">
<p class="vadmin">管理员登录</p>
<el-form class="login-form" status-icon :rules="loginRules" ref="loginForm" :model="loginForm"
label-width="0" size="default">
<el-form-item prop="admin_account">
<el-input @keyup.enter.native="handleLogin()" v-model="loginForm.admin_account"
auto-complete="off" placeholder="请输入账号">
<i slot="prefix" class="el-icon-user"></i>
</el-input>
</el-form-item>
<el-form-item prop="admin_password">
<el-input @keyup.enter.native="handleLogin()" v-model="loginForm.admin_password" show-password
auto-complete="off" placeholder="请输入密码">
<i slot="prefix" class="el-icon-key"></i>
</el-input>
</el-form-item>
<el-form-item v-if="codeUrl" prop="admin_code">
<el-row :span="34">
<el-col :span="14">
<el-input @keyup.enter.native="handleLogin()" v-model="loginForm.admin_code"
auto-complete="off" placeholder="请输入验证码">
<i slot="prefix" class="el-icon-mobile"></i>
</el-input>
</el-col>
<el-col :span="10">
<div class="login-code">
<img :src="codeUrl" class="login-code-img" @click="getCaptcha" alt="" />
</div>
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loading" @click.native.prevent="handleLogin"
class="login-submit">登 录
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</div>
</div>
</body>
<script src="/static/admin/js/vue-2.6.10.min.js"></script>
<script src="/static/admin/js/axios.min.js"></script>
<script src="/static/admin/js/element.js"></script>
<script src="/static/admin/js/YAdmin.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
codeUrl: '',
codeToken: '',
loading: false,
loginForm: {
admin_account: '',
admin_password: '',
admin_code: '',
},
loginRules: {
admin_account: [
{ required: true, message: '请输入账号', trigger: 'blur' }
],
admin_password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码长度最少为6位', trigger: 'blur' }
],
admin_code: [
{ required: true, message: '请输入验证码', trigger: 'blur' },
{ min: 4, max: 4, message: '验证码长度为4位', trigger: 'blur' }
]
}
}
},
created() {
this.getCaptcha();
},
methods: {
/**
* @description 正式登录
*/
handleLogin() {
var that = this;
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.loginForm.token = this.codeToken
axios.post('/admin/admin/login', Object.assign({}, PostBase, this.loginForm))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: '登录成功,正在跳转中',
type: 'success'
});
setTimeout(function () {
location.replace('/qfadmin');
}, 1000)
} else {
that.$message.error(response.data.message);
that.loading = false
that.getCaptcha();
}
})
.catch(function (error) {
that.$message.error('登录失败,服务器内部错误');
that.loading = false
});
}
})
},
onSubmit() {
var that = this;
axios.post('/admin/admin/login', Object.assign({}, PostBase, this.form))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: '登录成功,正在跳转中',
type: 'success'
});
setTimeout(function () {
location.replace('{$callback}');
}, 1000)
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('登录失败,服务器内部错误');
});
},
getCaptcha() {
var that = this;
axios.post('/admin/system/getCaptcha', Object.assign({}, PostBase))
.then(function (res) {
that.codeUrl = res.data.data.img
that.codeToken = res.data.data.token
})
.catch(function (error) {
that.$message.error('获取失败');
});
},
}
})
</script>
</html>
@@ -0,0 +1,94 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<span>修改我的密码</span>
</div>
<div class="text item">
<el-form :model="form" status-icon :rules="rules" ref="form" label-width="80px">
<el-form-item label="原密码" prop="oldPassword">
<el-input show-password v-model="form.oldPassword" placeholder="请输入原密码"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input show-password password="password" v-model="form.newPassword" placeholder="请输入新密码">
</el-input>
</el-form-item>
<el-form-item label="新密码" prop="checkPassword">
<el-input show-password v-model="form.checkPassword" placeholder="请确认新密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">修改密码</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
return {
form: {
oldPassword: "",
newPassword: "",
checkPassword: "",
},
rules: {
oldPassword: [
{ required: true, message: '原密码必须输入', trigger: 'blur' },
],
newPassword: [
{ required: true, message: '必须输入', trigger: 'blur' },
],
checkPassword: [
{ required: true, message: '必须输入', trigger: 'blur' },
],
}
}
},
methods: {
onSubmit() {
var that = this;
that.$refs['form'].validate((valid) => {
if (!valid) {
that.$message.error('仔细检查检查,是不是有个地方写得不对?');
return;
}
if (that.form.newPassword != that.form.checkPassword) {
that.$message.error('两次密码输入不一致,请确认');
return;
}
axios.post('/admin/admin/motifypassword', Object.assign({}, PostBase, {
oldPassword: that.form.oldPassword,
newPassword: that.form.newPassword,
}))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
setTimeout(function () {
location.href = "/qfadmin/admin/login";
}, 2000);
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
});
},
}
});
</script>
</html>
+103
View File
@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<span>修改我的资料</span>
</div>
<div class="text item">
<el-form :model="form" status-icon :rules="rules" ref="form" label-width="80px">
<el-form-item label="昵称" prop="admin_name">
<el-input v-model="form.admin_name" placeholder="请输入你的昵称"></el-input>
</el-form-item>
<el-form-item label="姓名" prop="admin_truename">
<el-input v-model="form.admin_truename" placeholder="请输入你的真实姓名"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="admin_email">
<el-input v-model="form.admin_email" placeholder="请输入你的邮箱"></el-input>
</el-form-item>
<el-form-item label="身份证" prop="admin_idcard">
<el-input v-model="form.admin_idcard" placeholder="请输入你的身份证"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">更新资料</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
this.getData();
return {
form: {
},
rules: {
admin_name: [
{ required: true, message: '昵称必须填写', trigger: 'blur' },
],
admin_email: [
{ pattern: /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/, message: '邮箱格式不正确', trigger: 'blur' },
],
admin_idcard: [
{ pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '身份证格式不正确', trigger: 'blur' },
],
}
}
},
methods: {
getData() {
var that = this;
axios.post('/admin/admin/getmyinfo', Object.assign({}, PostBase))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.form = response.data.data;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
onSubmit() {
var that = this;
that.$refs['form'].validate((valid) => {
if (!valid) {
that.$message.error('仔细检查检查,是不是有个地方写得不对?');
return;
}
if (that.form.newPassword != that.form.checkPassword) {
that.$message.error('两次密码输入不一致,请确认');
return;
}
axios.post('/admin/admin/updateMyInfo', Object.assign({}, PostBase, that.form))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
});
},
}
});
</script>
</html>
+214
View File
@@ -0,0 +1,214 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-form :inline="true">
<el-form-item>
<el-upload class="upload-demo" action="/admin/attach/uploadImage" :on-success="handleUploadSuccess"
:file-list="fileList" :show-file-list="false" :before-upload="beforeUpload" :data="postData"
v-loading.fullscreen.lock="fullscreenLoading">
<el-button size="small" type="primary">上传图片</el-button>
</el-upload>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-delete" size="small" @click="postMultDelete" plain>批量删除</el-button>
</el-form-item>
</el-form>
<el-table :data="dataList.data" @selection-change="changeSelection" v-loading="loading">
<el-table-column type="selection" width="50">
</el-table-column>
<el-table-column prop="attach_id" label="ID" width="60">
</el-table-column>
<el-table-column label="文件预览" width="120">
<template slot-scope="scope">
<div style="display: flex;align-items: center;">
<el-link :href="scope.row.attach_path" :underline="false" target="_blank">
<el-image style="width: 80px; height: 80px;flex:none;margin-right: 10px;background-color: #f8f8f9;border-radius: 6px;"
fit="contain" :src="scope.row.attach_path">
</el-image>
</el-link>
</div>
</template>
</el-table-column>
<el-table-column prop="attach_name" label="文件名称">
</el-table-column>
<el-table-column prop="attach_size" label="附件大小" width="100">
</el-table-column>
<el-table-column label="附件类型" width="100">
<template slot-scope="scope">
<el-tag size="medium" type="warning">{{scope.row.attach_type.toUpperCase()}}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<el-link type="danger" @click="clickDelete(scope.row)" :underline="false">删除</el-link>
</template>
</el-table-column>
</el-table>
<div class="page">
<el-pagination @size-change="handleSizeChange" :page-sizes="[10, 20, 50, 100,200,500]" :page-size="10"
layout="total, sizes, prev, pager, next, jumper" background @current-change="changeCurrentPage"
:current-page="dataList.current_page" :page-count="dataList.last_page" :total="dataList.total">
</el-pagination>
</div>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
this.getList();
return {
fullscreenLoading: false,
search: {
keyword: "",
filter: "attach_phone"
},
loading: true,
dataList: [],
selectList: [],
fileList: [],
form: {
page: 1,
per_page: 10,
},
postData: PostBase,
}
},
methods: {
handleUploadSuccess(res, file) {
this.fullscreenLoading = false;
if (res.code == CODE_SUCCESS) {
this.$message({
message: res.message,
type: 'success'
});
this.getList();
} else {
this.$message.error(res.message);
}
},
beforeUpload(file) {
const isImage = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isImage) {
this.$message.error('上传图片只能是 JPG/PNG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
this.fullscreenLoading = true;
return isImage && isLt2M;
},
handleSizeChange(per_page) {
this.form.per_page = per_page;
this.getList();
},
time2string(timestamps, formatStr = 'MM-dd hh:mm') {
var now = new Date(timestamps * 1000),
y = now.getFullYear(),
m = now.getMonth() + 1,
d = now.getDate();
return y + "-" + (m < 10 ? "0" + m : m) + "-" + (d < 10 ? "0" + d : d) + " " + now.toTimeString().substr(0, 8);
},
postMultDelete() {
var that = this;
if (that.selectList.length == 0) {
that.$message.error('未选择任何附件!');
return;
}
this.$confirm('即将删除选中的附件, 是否确认?', '批量删除', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/attach/delete', Object.assign({}, PostBase, {
attach_id: that.selectList.join(",")
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => { });
},
changeSelection(list) {
var that = this;
that.selectList = [];
for (var index in list) {
that.selectList.push(list[index].attach_id);
}
},
clickAdd() {
var that = this;
that.formAdd = {};
that.dialogFormAdd = true;
},
clickDelete(row) {
var that = this;
this.$confirm('即将删除这个附件, 是否确认?', '删除提醒', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/attach/delete', Object.assign({}, PostBase, {
attach_id: row.attach_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => { });
},
changeCurrentPage(page) {
this.form.page = page;
this.getList();
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/attach/getList', Object.assign({}, PostBase, that.form, that.search))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.dataList = response.data.data;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
console.log(error);
});
}
}
})
</script>
</html>
+19
View File
@@ -0,0 +1,19 @@
</el-main>
</el-container>
</el-container>
<Uploads ref="upload"></Uploads>
<Goodslists ref="goodslist"></Goodslists>
</div>
</body>
{include file="component/view"/}
<script src="/static/admin/js/vue-2.6.10.min.js"></script>
<script src="/static/admin/js/axios.min.js"></script>
<script src="/static/admin/js/element.js"></script>
<script src="/static/admin/js/YAdmin.js"></script>
<script src="/static/admin/js/SkuForm.umd.js"></script>
<script src="/static/admin/UEditor/vue-ueditor-wrap.min.js"></script>
<script src="/static/admin/UEditor/ueditor.config.js"></script>
<script src="/static/admin/UEditor/ueditor.all.js"></script>
<script src="/static/admin/js/component.js"></script>
<script src="/static/admin/js/Sortable.min.js"></script>
<script src="/static/admin/js/vuedraggable.umd.min.js"></script>
+67
View File
@@ -0,0 +1,67 @@
<meta charset="UTF-8">
<!-- import CSS -->
<link rel="stylesheet" href="/static/admin/css/element.css">
<link rel="stylesheet" href="/static/admin/css/YAdmin.css">
</head>
<body>
<div id="app" v-cloak>
<el-container>
<el-header>
<el-col style="width: auto;">
<el-menu class="el-menu-vertical" text-color="#333333" :default-active="'{if condition="$node.node_pid"}{$node.node_pid}{else}{$node.node_id}{/if}'" unique-opened
style="border:none;" mode="horizontal" active-text-color="#333333">
{volist name="menuList" id="item"}
{if condition="count($item.subList)>0"}
{if condition="count($item.subList[0]['subList'])>0"}
<el-menu-item index="{$item.node_id}"
onclick="location.href='/{$item['subList'][0]['subList'][0]['node_module']}/{$item['subList'][0]['subList'][0]['node_controller']}/{$item['subList'][0]['subList'][0]['node_action']}';"
{if
condition="$menu==$item.node_id"
}class="is-active" {/if}>
<i class="{$item.node_icon}"></i> {$item.node_title}
</el-menu-item>
{else}
<el-menu-item index="{$item.node_id}"
onclick="location.href='/{$item['subList'][0]['node_module']}/{$item['subList'][0]['node_controller']}/{$item['subList'][0]['node_action']}';" {if
condition="$menu==$item.node_id"
}class="is-active" {/if}>
<i class="{$item.node_icon}"></i> {$item.node_title}
</el-menu-item>
{/if}
{else}
{if condition="count($item.subList)>0 || $item.node_controller=='index'"}
<el-menu-item index="{$item.node_id}"
onclick="location.href='/{$item.node_module}/{$item.node_controller}/{$item.node_action}';" {if
condition="$menu==$item.node_id"
}class="is-active" {/if}>
<i class="{$item.node_icon}"></i> {$item.node_title}
</el-menu-item>
{/if}
{/if}
{/volist}
</el-menu>
</el-col>
<el-col style="width: 240px;float: right;">
<span class="topArea">
<el-link :underline="false" class="el-icon-full-screen menuicon" onclick="requestFullScreen()"></el-link>
<!-- <el-link :underline="false" class="el-icon-brush menuicon"></el-link> -->
<el-dropdown>
<el-link :underline="false">&nbsp;{$adminInfo['admin_name']}<i class="el-icon-arrow-down"></i></el-link>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item onclick="location.href='/qfadmin/admin/updatemyinfo';">修改资料
</el-dropdown-item>
<el-dropdown-item onclick="location.href='/qfadmin/admin/motifypassword';">修改密码
</el-dropdown-item>
<el-dropdown-item onclick="location.href='/qfadmin/system/clean';">清除缓存
</el-dropdown-item>
<el-dropdown-item onclick="logout()">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</span>
</el-col>
</el-header>
<el-container class="body">
{include file="common/menu"/}
<el-main>
@@ -0,0 +1,47 @@
<meta charset="UTF-8">
<!-- import CSS -->
<link rel="stylesheet" href="/static/admin/css/element.css">
<link rel="stylesheet" href="/static/admin/css/YAdmin.css">
</head>
<body>
<div id="app" v-cloak>
<el-container>
<el-header>
<el-col style="width: auto;">
<el-menu class="el-menu-vertical" text-color="#333333" unique-opened
style="border:none;" mode="horizontal" active-text-color="#333333">
<el-menu-item onclick="location.href='./index.html?meeting_id={$datas.meeting_id??''}'" {if
condition="$action=='index'"
}class="is-active" {/if}>
<i class="el-icon-user-solid"></i> 客户管理
</el-menu-item>
<el-menu-item onclick="location.href='./team.html?meeting_id={$datas.meeting_id??''}'" {if
condition="$action=='team'"
}class="is-active" {/if}>
<i class="el-icon-s-custom"></i> 团队管理
</el-menu-item>
<el-menu-item onclick="location.href='./valetor.html?meeting_id={$datas.meeting_id??''}'" {if
condition="$action=='valetor'"
}class="is-active" {/if}>
<i class="el-icon-s-help"></i> 会务人员管理
</el-menu-item>
</el-menu>
</el-col>
<el-col style="width: 240px;float: right;">
<span class="topArea">
<el-link :underline="false" class="el-icon-full-screen menuicon" onclick="requestFullScreen()"></el-link>
<!-- <el-link :underline="false" class="el-icon-brush menuicon"></el-link> -->
<el-dropdown>
<el-link :underline="false">&nbsp;{$adminInfo['admin_name']}<i class="el-icon-arrow-down"></i></el-link>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item onclick="logout()">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</span>
</el-col>
</el-header>
<el-container class="body">
{include file="common/menu"/}
<el-main>
+44
View File
@@ -0,0 +1,44 @@
{if condition="$menuLists"}
<el-aside width="160px">
<a class="titlehome" href="/qfadmin" style="display: block;height: 62px;line-height: 62px;text-align: center;"><img src="/static/admin/images/logo.png" width="40px" style="vertical-align: middle;" /></a>
<el-menu class="el-menu-vertical-demo" text-color="#333333" default-active="'{$node.node_pid}-{$node.node_id}'" :collapse="false" :default-openeds="['{$node.node_pid}']">
{volist name="menuLists" id="item"}
{if condition="count($item.subList)>0"}
<el-submenu index="{$item.node_id}">
<template slot="title">
<i {if condition='$item.node_icon'}class="{$item.node_icon}"{else}class="el-icon-menu"{/if}></i> {$item.node_title}
</template>
{volist name="$item.subList" id="subItem"}
<el-menu-item onclick="location.href='/{$subItem.node_module}/{$subItem.node_controller}/{$subItem.node_action}';"
index="{$item.node_id}-{$subItem.node_id}" {if
condition="$subItem.node_controller==strtolower($controller) && $subItem.node_action==strtolower($action)"
}class="is-active" {/if}>{$subItem.node_title}</el-menu-item>
{/volist}
</el-submenu>
{else}
{if condition="$item.node_controller=='' && $item.node_action==''"}
<el-menu-item index="{$item.node_id}" onclick="testalert('暂无该功能')">
<i {if condition='$item.node_icon' }class="{$item.node_icon}" {else}class="el-icon-menu" {/if}></i>
{$item.node_title}
</el-menu-item>
{else}
<el-menu-item index="{$item.node_id}"
onclick="location.href='/{$item.node_module}/{$item.node_controller}/{$item.node_action}';" {if
condition="$item.node_controller==strtolower($controller) && $item.node_action==strtolower($action)"
}class="is-active" {/if}>
<i {if condition='$item.node_icon' }class="{$item.node_icon}" {else}class="el-icon-menu" {/if}></i>
{$item.node_title}
</el-menu-item>
{/if}
{/if}
{/volist}
<div style="height: 120px;"></div>
</el-menu>
<div class="version">资源管理系统<br> Version 1.0.0</div>
</el-aside>
{else}
<div style="position: absolute;top: -72px;left: 0;width: 160px;background-color: #ffffff;box-shadow: 0 0 12px 0 rgb(47 75 168 / 6%);border-radius: 12px;">
<a class="title" href="/admin" style="display: block;height: 62px;line-height: 62px;text-align: center;"><img
src="/static/admin/images/logo.png" width="40px" style="vertical-align: middle;" /></a>
</div>
{/if}
+152
View File
@@ -0,0 +1,152 @@
<template id="Upload">
<el-dialog title="图片库" :visible.sync="visible" :modal-append-to-body='false' append-to-body :close-on-click-modal="false"
width="725px">
<div class="upload-boxs">
<el-upload class="upload-right" action="/admin/attach/uploadImage" :on-success="handleUploadSuccess"
:file-list="fileList" :show-file-list="false" :before-upload="beforeUpload" :data="postData"
v-loading.fullscreen.lock="fullscreenLoading">
<el-button size="small" type="primary" icon="el-icon-upload">上传图片</el-button>
</el-upload>
</div>
<ul class="storage-list">
<li :class="item.select?'active':''" v-for="(item, index) in dataList.data" :key="index" @click="select(index)">
<el-image fit="contain" :src="item.attach_path"></el-image>
<p>{{item.attach_name}}</p>
</li>
</ul>
<p v-if="dataList.data&&dataList.data.length==0" style="text-align: center;">暂无资源</p>
<el-pagination @current-change="changeCurrentPage" layout="prev, pager, next" :current-page="dataList.current_page"
:page-count="dataList.last_page" hide-on-single-page background>
</el-pagination>
<div slot="footer" class="dialog-footer">
<div style="float: left; font-size: 13px;">
<span v-if="multiple">
当前已选 <span style="color: #F56C6C;">{{selectList.length+selected_num}}</span> 个,最多允许选择 <span
style="color: #F56C6C;">{{total_num}}</span> 个资源
</span>
<span v-else>当前已选 <span style="color: #F56C6C;">{{selectList.length}}</span> 个资源</span>
</div>
<el-button @click="visible = false" size="small">取消</el-button>
<el-button type="primary" @click="save" size="small">确定</el-button>
</div>
</el-dialog>
</template>
<template id="Single">
<div class="slectimg" v-if="multiple">
<block v-if="value.length>0">
<draggable v-model="value" chosenClass="chosen" forceFallback="true" animation="600" @start="onStart"
@end="onEnd">
<transition-group>
<div class="imgs" v-for="(v, s) in value" :key="s" style="cursor: all-scroll;">
<el-image fit="contain" :src="v" :preview-src-list="value" :z-index="s"></el-image>
<!-- <el-image fit="contain" :src="v" ></el-image> -->
<i class="close el-icon-error" @click="deles(s)"></i>
</div>
</transition-group>
</draggable>
</block>
<div class="noimg" @click="selectimg()">
<i class="el-icon-plus"></i>
</div>
</div>
<div class="slectimg" v-else>
<div class="imgs" v-if="value.length>0">
<el-image fit="contain" :src="value" :preview-src-list="[value]"></el-image>
<i class="close el-icon-error" @click="deles()"></i>
</div>
<div class="noimg" v-else @click="selectimg()">
<i class="el-icon-plus"></i>
</div>
</div>
</template>
<template id="Ueditor">
<Ueditors v-model="value" ref="Ueditor" :config="config"></Ueditors>
</template>
<template id="skuforms">
<div>
<div style="padding-bottom: 10px;">
<el-input style="width: 120px;" v-if="inputVisible" v-model="inputValue" ref="saveTagInput" size="small"
@keyup.enter.native="handleInputConfirm" placeholder="回车确定">
</el-input>
<el-button v-else class="button-new-tag" size="small" @click="showInput" style="width: 120px;">+添加规格组</el-button>
</div>
<sku-form :source-attribute="sourceAttribute" :attribute.sync="attribute" :structure="structure" :sku.sync="sku"
ref="skuForm"></sku-form>
</div>
</template>
<template id="Goodslist">
<el-dialog title="商品库" :before-close="handleClose" :visible.sync="visible" :modal-append-to-body='false' append-to-body
:close-on-click-modal="false" width="900px">
<el-form :inline="true">
<div style="float:right">
<el-form-item style="width:100px; margin-bottom: 0;">
<el-cascader v-model="search.classify" placeholder="商品分类" :options="categoryList" :props="cascaderProps"
style="width: 100%;" filterable clearable size="small" :show-all-levels="false">
</el-cascader>
</el-form-item>
<el-form-item style="margin-bottom: 0;">
<el-input placeholder="输入商品名称搜索" size="small" v-model="search.keyword" @keyup.enter.native="getList_search"
clearable @clear="getList_search"></el-input>
</el-form-item>
<el-form-item style="margin-bottom: 0;">
<el-button type="primary" icon="el-icon-search" size="small" @click="getList_search" plain>搜索
</el-button>
<el-button icon="el-icon-refresh-left" size="small" @click="getList_search(0)" plain>重置</el-button>
</el-form-item>
</div>
</el-form>
<el-table :data="dataList.data" ref="multipleTable" @selection-change="changeSelection" row-key="goods_id" reserve-selection="true" style="min-height: 425px;" v-loading="loading">
<el-table-column align="center" type="selection" reserve-selection="true" width="55"></el-table-column>
<el-table-column label="商品" prop="goods_id" min-width="380">
<template slot-scope="scope">
<el-image class="goods-image" style="width: 50px;height: 50px;" :src="scope.row.picture[0]" :preview-src-list="[scope.row.picture[0]]"
fit="contain" lazy></el-image>
<div class="goods-info cs-ml">
<p class="action" style="overflow:hidden;text-overflow:ellipsis;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;">
<span :title="scope.row.goods_name" class="link">{{scope.row.goods_name}}</span>
</p>
</div>
</template>
</el-table-column>
<el-table-column label="本店价" prop="goods_price">
<template slot-scope="scope">
<div class="action">
<span class="goods-shop-price">{{scope.row.goods_price}}</span>
</div>
</template>
</el-table-column>
<el-table-column label="库存" prop="stock_total">
<template slot-scope="scope">
<div class="action">
<span>{{scope.row.stock_total}}</span>
</div>
</template>
</el-table-column>
</el-table>
<div slot="footer" class="dialog-footer">
<p style="padding-bottom: 10px;">
<el-pagination hide-on-single-page="true" layout="prev, pager, next" background :current-page="form.page" @current-change="changeCurrentPage" :page-size="5" :total="dataList.total">
</el-pagination>
</p>
<p>
<el-button @click="cancels" size="small">取消</el-button>
<el-button type="primary" @click="save" size="small">确定</el-button>
</p>
</div>
</el-dialog>
</template>
+194
View File
@@ -0,0 +1,194 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-card class="box-card" shadow="never">
<el-tabs v-model="activeName">
<el-tab-pane :label="item.name" :name="item.val" v-for="(item, index) in tabname" :key="index" v-if="item.show">
<div class="base_form" style="padding-right: 220px;">
<el-form ref="form" label-width="220px">
<block v-for="(items, indexs) in form" :key="indexs">
<el-form-item :label="items.conf_title?items.conf_title:items.conf_key" v-if="items.conf_type==item.val">
<block v-if="items.conf_spec==1">
<el-input type="textarea" :rows="4" v-model="items.conf_value"></el-input>
</block>
<block v-else-if="items.conf_spec==2">
<el-radio v-model="items.conf_value" v-for="(val, key) in items.conf_content" :key="key" :label="val.value">{{val.name}}</el-radio>
</block>
<block v-else-if="items.conf_spec==3">
<el-checkbox-group v-model="items.conf_value">
<el-checkbox v-for="(val, key) in items.conf_content" :key="key" :label="val.value">{{val.name}}</el-checkbox>
</el-checkbox-group>
</block>
<block v-else-if="items.conf_spec==4">
<Single v-model="items.conf_value"/>
</block>
<block v-else-if="items.conf_spec==5">
<Single v-model="items.conf_value" multiple="true" :selected_num="items.conf_value.length"/>
</block>
<block v-else-if="items.conf_spec==6">
<Ueditor v-model="items.conf_value"></Ueditor>
</block>
<block v-else-if="items.conf_spec==7">
<el-color-picker v-model="items.conf_value"></el-color-picker>
</block>
<block v-else>
<el-input v-model="items.conf_value"></el-input>
</block>
<span class="f_tips">{{items.conf_desc}}<span v-if="items.conf_spec==5"> 最多上传10张</span></span>
</el-form-item>
</block>
<el-form-item>
<el-button type="primary" @click="onSubmit(item.val)">保存配置</el-button>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
</el-tabs>
</el-card>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
this.getData();
return {
form: [],
activeName: "0",
tabname: [
{
name: '基础设置',
val: '0',
show: false,
},
{
name: 'SEO设置',
val: '9',
show: false,
},
{
name: '前端模版',
val: '3',
show: false,
},
{
name: '搜索设置',
val: '1',
show: false,
},
{
name: '微信设置',
val: '8',
show: false,
},
{
name: '交易设置',
val: '10',
show: false,
},
{
name: '售后设置',
val: '11',
show: false,
},
{
name: '上传配置',
val: '2',
show: false,
},
{
name: '其他配置',
val: '4',
show: false,
},
],
}
},
methods: {
getData() {
var that = this;
axios.post('/admin/conf/getBaseConfig', Object.assign({}, PostBase))
.then(function (res) {
if (res.data.code == 200) {
for (let item of res.data.data) {
if (item.conf_spec == 2) {
for (let i = 0; i < item.conf_content.length; i++) {
let d = item.conf_content[i].split("=>");
item.conf_content[i] = {
name: d[0].toString(),
value: d[1].toString()
}
}
}else if(item.conf_spec==3){
for (let i = 0; i < item.conf_content.length; i++) {
let d = item.conf_content[i].split("=>");
item.conf_content[i] = {
name: d[0].toString(),
value: d[1].toString()
}
}
if(item.conf_value){
item.conf_value = item.conf_value.split(",");
}else{
item.conf_value = []
}
}else if (item.conf_spec == 5) {
if(item.conf_value){
item.conf_value = item.conf_value.split(",");
for (let i = 0; i < item.conf_value.length; i++) {
if (!item.conf_value[i]) {
item.conf_value.splice(i, 1);
}
}
} else {
item.conf_value = []
}
}
for (let i = 0; i < that.tabname.length; i++) {
if(that.tabname[i].val == item.conf_type){
that.tabname[i].show = true
}
}
}
that.form = res.data.data;
} else {
that.$message.error(res.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
onSubmit(index) {
var that = this;
var postData = {};
for (var i = 0; i < that.form.length; i++) {
if(that.form[i].conf_type == index){
postData[that.form[i].conf_key] = that.form[i].conf_value;
}
}
axios.post('/admin/conf/updateBaseConfig', Object.assign({}, PostBase, postData))
.then(function (res) {
if (res.data.code == 200) {
that.$message({
message: res.data.message,
type: 'success'
});
} else {
that.$message.error(res.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
}
})
</script>
</html>
+468
View File
@@ -0,0 +1,468 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-form :inline="true">
<el-form-item>
<el-button icon="el-icon-plus" size="small" @click="clickAdd" plain>添加</el-button>
</el-form-item>
<div style="float:right">
<el-form-item style="width:120px;">
<el-select placeholder="筛选类别" size="small" v-model="search.filter">
<el-option value="conf_id" label="参数ID">
</el-option>
<el-option value="conf_title" label="参数名称">
</el-option>
<el-option value="conf_key" label="参数字段">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-input placeholder="输入关键词搜索" size="small" v-model="search.keyword"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="getList_search" plain>搜索</el-button>
</el-form-item>
</div>
</el-form>
<el-table :data="dataList.data" @selection-change="changeSelection" v-loading="loading">
<el-table-column prop="conf_id" label="ID" width="60">
</el-table-column>
<el-table-column prop="conf_type" label="所属分类" width="150">
<template slot-scope="scope">
<el-tag size="small" type="success" v-if="scope.row.conf_type==1">搜索设置</el-tag>
<el-tag size="small" type="warning" v-else-if="scope.row.conf_type==2">上传配置</el-tag>
<el-tag size="small" type="info" v-else-if="scope.row.conf_type==3">前端模版</el-tag>
<el-tag size="small" type="danger" v-else-if="scope.row.conf_type==4">其他配置</el-tag>
<el-tag size="small" type="success" v-else-if="scope.row.conf_type==5">微信支付配置</el-tag>
<el-tag size="small" type="warning" v-else-if="scope.row.conf_type==6">支付宝支付配置</el-tag>
<el-tag size="small" type="success" v-else-if="scope.row.conf_type==7">微信小程序配置</el-tag>
<el-tag size="small" type="danger" v-else-if="scope.row.conf_type==8">微信公众号配置</el-tag>
<el-tag size="small" type="danger" v-else-if="scope.row.conf_type==9">SEO设置</el-tag>
<el-tag size="small" type="danger" v-else-if="scope.row.conf_type==10">交易设置</el-tag>
<el-tag size="small" type="danger" v-else-if="scope.row.conf_type==11">售后设置</el-tag>
<el-tag size="small" v-else>基础设置</el-tag>
</template>
</el-table-column>
<el-table-column prop="conf_title" label="参数名称">
</el-table-column>
<el-table-column prop="conf_desc" label="参数描述">
</el-table-column>
<el-table-column prop="conf_key" label="参数字段">
<template slot-scope="scope">
<el-tooltip class="item" effect="dark" :content="scope.row.conf_title" placement="top">
<el-link>{{scope.row.conf_key}}</el-link>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="conf_sort" label="排序" width="90">
</el-table-column>
<el-table-column label="操作" width="180">
<template slot-scope="scope">
<el-link type="primary" @click="clickEdit(scope.row)" :underline="false">编辑</el-link>&nbsp;
<el-link type="danger" @click="clickDelete(scope.row)" :underline="false" v-if="scope.row.conf_system==0">删除</el-link>
</template>
</el-table-column>
</el-table>
<div class="page">
<el-pagination @size-change="handleSizeChange" :page-sizes="[10, 20, 50, 100,200,500]" :page-size="10"
layout="total, sizes, prev, pager, next, jumper" background @current-change="changeCurrentPage"
:current-page="dataList.current_page" :page-count="dataList.last_page" :total="dataList.total">
</el-pagination>
</div>
<!-- 添加框 -->
<el-dialog title="添加配置" :visible.sync="dialogFormAdd" width="800px" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formAdd" status-icon :rules="rules" ref="formAdd">
<el-form-item label="所属分类" :label-width="formLabelWidth" prop="conf_type">
<el-select v-model="formAdd.conf_type" placeholder="请选择所属分类" size="medium">
<el-option label="基础设置" value="0"></el-option>
<el-option label="SEO设置" value="9"></el-option>
<el-option label="搜索设置" value="1"></el-option>
<el-option label="上传配置" value="2"></el-option>
<el-option label="前端模版" value="3"></el-option>
<el-option label="其他配置" value="4"></el-option>
<el-option label="微信支付配置" value="5"></el-option>
<el-option label="支付宝支付配置" value="6"></el-option>
<el-option label="微信小程序配置" value="7"></el-option>
<el-option label="微信公众号配置" value="8"></el-option>
<el-option label="交易设置" value="10"></el-option>
<el-option label="售后设置" value="11"></el-option>
</el-select>
</el-form-item>
<el-form-item label="参数名称" :label-width="formLabelWidth" prop="conf_title">
<el-input size="medium" autocomplete="off" v-model="formAdd.conf_title"></el-input>
<span style="color: #999;">参数名称,如:网站LOGO</span>
</el-form-item>
<el-form-item label="参数字段" :label-width="formLabelWidth" prop="conf_key">
<el-input size="medium" autocomplete="off" v-model="formAdd.conf_key"></el-input>
<span style="color: #999;">参数字段,如:logo</span>
</el-form-item>
<el-form-item label="参数描述" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formAdd.conf_desc"></el-input>
<span style="color: #999;">参数描述,如:建议尺寸: 300*300</span>
</el-form-item>
<el-form-item label="字段类型" :label-width="formLabelWidth">
<el-radio-group v-model="formAdd.conf_spec" size="small">
<el-radio-button label="0">文本框</el-radio-button>
<el-radio-button label="1">多行文本框</el-radio-button>
<el-radio-button label="2">单选框</el-radio-button>
<el-radio-button label="3">多选框</el-radio-button>
<el-radio-button label="4">单图</el-radio-button>
<el-radio-button label="5">多图</el-radio-button>
<el-radio-button label="6">富文本</el-radio-button>
</el-radio-group>
<el-input v-if="formAdd.conf_spec==2 || formAdd.conf_spec==3" type="textarea" v-model="formAdd.conf_content"
:rows="4" placeholder="参数方式例如:&#10;开启=>1&#10;关闭=>0" style="margin-top: 10px;"></el-input>
</el-form-item>
<el-form-item label="显示隐藏" :label-width="formLabelWidth">
<el-switch size="medium" v-model="formAdd.conf_status"></el-switch>
</el-form-item>
<el-form-item label="排序" :label-width="formLabelWidth">
<el-input-number v-model="formAdd.conf_sort" :min="0" :max="999" size="medium" style="width: 120px;" controls-position="right" />
</el-form-item>
<el-form-item label="系统参数" :label-width="formLabelWidth">
<el-switch size="medium" v-model="formAdd.conf_system"></el-switch>
<div style="color: #999;">开启后,添加的参数将无法删除</div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postAdd">确认添加</el-button>
</div>
</el-dialog>
<!-- 修改框 -->
<el-dialog title="修改配置" :visible.sync="dialogFormEdit" width="800px" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formEdit" status-icon :rules="rules" ref="formEdit">
<el-form-item label="所属分类" :label-width="formLabelWidth" prop="conf_type">
<el-select v-model="formEdit.conf_type" placeholder="请选择所属分类" size="medium">
<el-option label="基础设置" value="0"></el-option>
<el-option label="SEO设置" value="9"></el-option>
<el-option label="搜索设置" value="1"></el-option>
<el-option label="上传配置" value="2"></el-option>
<el-option label="前端模版" value="3"></el-option>
<el-option label="其他配置" value="4"></el-option>
<el-option label="微信支付配置" value="5"></el-option>
<el-option label="支付宝支付配置" value="6"></el-option>
<el-option label="微信小程序配置" value="7"></el-option>
<el-option label="微信公众号配置" value="8"></el-option>
<el-option label="交易设置" value="10"></el-option>
<el-option label="售后设置" value="11"></el-option>
</el-select>
</el-form-item>
<el-form-item label="参数名称" :label-width="formLabelWidth" prop="conf_title">
<el-input size="medium" autocomplete="off" v-model="formEdit.conf_title"></el-input>
<span style="color: #999;">参数名称,如:网站LOGO</span>
</el-form-item>
<el-form-item label="参数字段" :label-width="formLabelWidth" prop="conf_key">
<el-input size="medium" autocomplete="off" v-model="formEdit.conf_key"></el-input>
<span style="color: #6881ec;">参数字段,切勿随意修改</span>
</el-form-item>
<el-form-item label="参数描述" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formEdit.conf_desc"></el-input>
<span style="color: #999;">参数描述,如:建议尺寸: 300*300</span>
</el-form-item>
<el-form-item label="字段类型" :label-width="formLabelWidth">
<el-radio-group v-model="formEdit.conf_spec" size="small">
<el-radio-button label="0">文本框</el-radio-button>
<el-radio-button label="1">多行文本框</el-radio-button>
<el-radio-button label="2">单选框</el-radio-button>
<el-radio-button label="3">多选框</el-radio-button>
<el-radio-button label="4">单图</el-radio-button>
<el-radio-button label="5">多图</el-radio-button>
<el-radio-button label="6">富文本</el-radio-button>
<el-radio-button label="7">颜色选择</el-radio-button>
</el-radio-group>
<el-input v-if="formEdit.conf_spec==2 || formEdit.conf_spec==3" type="textarea" v-model="formEdit.conf_content" :rows="4" placeholder="参数方式例如:&#10;开启=>1&#10;关闭=>0" style="margin-top: 10px;"></el-input>
</el-form-item>
<el-form-item label="显示隐藏" :label-width="formLabelWidth">
<el-switch size="medium" v-model="formEdit.conf_status"></el-switch>
</el-form-item>
<el-form-item label="排序" :label-width="formLabelWidth">
<el-input-number v-model="formEdit.conf_sort" :min="0" :max="999" size="medium" style="width: 120px;"
controls-position="right" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postEdit">确认修改</el-button>
</div>
</el-dialog>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
this.getList();
return {
search: {
keyword: "",
filter: "conf_id"
},
formLabelWidth: '80px',
dialogFormAdd: false,
dialogFormEdit: false,
loading: true,
dataList: [],
selectList: [],
form: {
page: 1,
per_page: 10
},
formAdd: {
conf_status: true,
conf_spec: 0,
conf_sort: 0,
},
formEdit: {},
rules: {
conf_title: [
{ required: true, message: '参数名称必须填写', trigger: 'blur' },
],
conf_key: [
{ required: true, message: '参数字段必须填写', trigger: 'blur' },
],
conf_type: [
{ required: true, message: '所属分类必须填写', trigger: 'blur' },
],
}
}
},
methods: {
getList_search() {
this.form.page = 1;
this.getList();
},
handleSizeChange(per_page) {
this.form.per_page = per_page;
this.getList();
},
postMultDelete() {
var that = this;
if (that.selectList.length == 0) {
that.$message.error('未选择任何配置!');
return;
}
this.$confirm('即将删除选中的配置, 是否确认?', '批量删除', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/conf/delete', Object.assign({}, PostBase, {
conf_id: that.selectList.join(",")
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
changeSelection(list) {
var that = this;
that.selectList = [];
for (var index in list) {
that.selectList.push(list[index].conf_id);
}
},
postEdit() {
var that = this;
that.$refs['formEdit'].validate((valid) => {
if (!valid) {
that.$message.error('仔细检查检查,是不是有个地方写得不对?');
return;
}
axios.post('/admin/conf/update', Object.assign({}, PostBase, that.formEdit))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormEdit = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
});
},
postAdd() {
var that = this;
that.$refs['formAdd'].validate((valid) => {
if (!valid) {
that.$message.error('仔细检查检查,是不是有个地方写得不对?');
return;
}
axios.post('/admin/conf/add', Object.assign({}, PostBase, that.formAdd))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormAdd = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
});
},
clickAdd() {
var that = this;
that.formAdd = {
conf_status: true,
conf_spec: 0,
conf_sort: 0,
};
axios.post('/admin/conf/getList', Object.assign({}, PostBase))
.then(function (response) {
that.groupList = response.data.data;
if (response.data.code == CODE_SUCCESS) {
that.dialogFormAdd = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickDelete(row) {
var that = this;
this.$confirm('即将删除这个配置, 是否确认?', '删除提醒', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/conf/delete', Object.assign({}, PostBase, {
conf_id: row.conf_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
clickStatus(row) {
var that = this;
axios.post(row.conf_status ? '/admin/conf/enable' : '/admin/conf/disable', Object.assign({}, PostBase, {
conf_id: row.conf_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickEdit(row) {
var that = this;
that.formEdit = row;
axios.post('/admin/conf/getList', Object.assign({}, PostBase))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.groupList = response.data.data;
axios.post('/admin/conf/detail', Object.assign({}, PostBase, {
conf_id: row.conf_id
}))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
response.data.data.conf_status = response.data.data.conf_status?true:false;
response.data.data.conf_type = response.data.data.conf_type.toString();
that.formEdit = response.data.data;
that.dialogFormEdit = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
changeCurrentPage(page) {
this.form.page = page;
this.getList();
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/conf/getList', Object.assign({}, PostBase, that.form, that.search))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.dataList = response.data.data;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
console.log(error);
});
}
}
})
</script>
</html>
+408
View File
@@ -0,0 +1,408 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-form :inline="true">
<el-form-item>
<el-button icon="el-icon-plus" size="small" @click="clickAdd" plain>添加</el-button>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-delete" size="small" @click="postMultDelete" plain>批量删除</el-button>
</el-form-item>
</el-form>
<el-table :data="dataList" @selection-change="changeSelection" v-loading="loading">
<el-table-column type="selection" width="50">
</el-table-column>
<el-table-column prop="group_id" label="组ID" width="100">
</el-table-column>
<el-table-column prop="group_name" label="组名称" width="200">
</el-table-column>
<el-table-column prop="group_desc" label="组描述">
</el-table-column>
</el-table-column>
<el-table-column label="禁用" width="80">
<template slot-scope="scope">
<el-switch v-model="scope.row.group_status==1?true:false" active-color="#ff4949"
@change="clickStatus(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-link type="primary" @click="clickEdit(scope.row)" :underline="false">编辑</el-link>&nbsp;
<el-link type="primary" @click="clickAuth(scope.row)" :underline="false">授权</el-link>&nbsp;
<el-link type="danger" @click="clickDelete(scope.row)" :underline="false">删除</el-link>
</template>
</el-table-column>
</el-table>
<!-- 添加框 -->
<el-dialog title="添加用户组" :visible.sync="dialogFormAdd" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formAdd" status-icon :rules="rules" ref="formAdd">
<el-form-item label="组名称" :label-width="formLabelWidth" prop="group_name">
<el-input size="medium" autocomplete="off" v-model="formAdd.group_name"></el-input>
</el-form-item>
<el-form-item label="组描述" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formAdd.group_desc"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postAdd">确认添加</el-button>
</div>
</el-dialog>
<!-- 修改框 -->
<el-dialog title="修改用户组" :visible.sync="dialogFormEdit" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formEdit" status-icon :rules="rules" ref="formEdit">
<el-form-item label="组名称" :label-width="formLabelWidth" prop="group_name">
<el-input size="medium" autocomplete="off" v-model="formEdit.group_name"></el-input>
</el-form-item>
<el-form-item label="组描述" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formEdit.group_desc"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postEdit">确认修改</el-button>
</div>
</el-dialog>
<!-- 授权框 -->
<el-dialog class="pub_dialog" title="用户组授权" :visible.sync="dialogFormAuth" :modal-append-to-body='false' append-to-body
width="60%" :close-on-click-modal='false'>
<div style="padding: 10px 30px;">
<el-tree :data="nodeList" @check="currentChecked" show-checkbox node-key="node_id" :props="defaultProps" :default-checked-keys="defaultkeys"></el-tree>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postAuth">确认授权</el-button>
</div>
</el-dialog>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
this.getList();
return {
checkAll: false,
search: {
group_status: "",
keyword: "",
filter: "group_id"
},
formLabelWidth: '80px',
dialogFormAdd: false,
dialogFormEdit: false,
dialogFormAuth: false,
loading: true,
dataList: [],
groupList: [],
selectList: [],
selectNodeList: [],
selectedGroupId: 0,
nodeList: [],
defaultProps: {
children: 'sub',
label: 'node_title'
},
defaultkeys: [],
form: {
page: 1
},
formAdd: {},
formEdit: {},
rules: {
group_name: [
{ required: true, message: '组名称必须填写', trigger: 'blur' },
],
}
}
},
methods: {
postMultDelete() {
var that = this;
if (that.selectList.length == 0) {
that.$message.error('未选择任何用户!');
return;
}
this.$confirm('即将删除选中的用户, 是否确认?', '批量删除', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/group/delete', Object.assign({}, PostBase, {
group_id: that.selectList.join(",")
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
changeSelection(list) {
var that = this;
that.selectList = [];
for (var index in list) {
that.selectList.push(list[index].group_id);
}
},
postAuth() {
var that = this;
axios.post('/admin/group/authorize', Object.assign({}, PostBase, {
node_ids: that.selectNodeList.join(','),
group_id: that.selectedGroupId
}))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormAuth = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
postEdit() {
var that = this;
that.$refs['formEdit'].validate((valid) => {
if (!valid) {
that.$message.error('仔细检查检查,是不是有个地方写得不对?');
return;
}
axios.post('/admin/group/update', Object.assign({}, PostBase, that.formEdit))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormEdit = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
});
},
postAdd() {
var that = this;
that.$refs['formAdd'].validate((valid) => {
if (!valid) {
that.$message.error('仔细检查检查,是不是有个地方写得不对?');
return;
}
axios.post('/admin/group/add', Object.assign({}, PostBase, that.formAdd))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormAdd = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
});
},
clickAdd() {
var that = this;
that.formAdd = {};
axios.post('/admin/group/getList', Object.assign({}, PostBase))
.then(function (response) {
that.groupList = response.data.data;
if (response.data.code == CODE_SUCCESS) {
that.dialogFormAdd = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickDelete(row) {
var that = this;
this.$confirm('即将删除这个用户, 是否确认?', '删除提醒', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/group/delete', Object.assign({}, PostBase, {
group_id: row.group_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
clickStatus(row) {
var that = this;
axios.post(row.group_status ? '/admin/group/enable' : '/admin/group/disable', Object.assign({}, PostBase, {
group_id: row.group_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickAuth(row) {
var that = this;
that.selectNodeList = [];
that.selectedGroupId = row.group_id;
axios.post('/admin/node/getList', Object.assign({}, PostBase))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.nodeList = response.data.data.data;
that.dialogFormAuth = true;
that.getAuthList(row);
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
getAuthList(row) {
var that = this;
that.defaultkeys = [];
axios.post('/admin/group/getAuthorize', Object.assign({}, PostBase, {
group_id: row.group_id
}))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.defaultkeys = [];
for (var i in response.data.data) {
that.defaultkeys.push(response.data.data[i].auth_node);
}
that.dialogFormAuth = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('设置选中状态失败');
});
},
currentChecked(nodeObj, SelectedObj) {
this.selectNodeList = SelectedObj.checkedKeys
},
clickEdit(row) {
var that = this;
that.formEdit = row;
axios.post('/admin/group/getList', Object.assign({}, PostBase))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.groupList = response.data.data;
axios.post('/admin/group/detail', Object.assign({}, PostBase, {
group_id: row.group_id
}))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.formEdit = response.data.data;
that.dialogFormEdit = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
changeCurrentPage(page) {
this.form.page = page;
this.getList();
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/group/getList', Object.assign({}, PostBase, that.form, that.search))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.dataList = response.data.data;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
console.log(error);
});
}
}
})
</script>
</html>
+28
View File
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>后台管理系统</title>
{include file="common/header"/}
<div class="homecontainer" style="height: 100%;display: flex;align-items: center;justify-content: center;">
<div>
<img src="/static/admin/images/logo@2x.png" alt="">
<p style="color: #999999;">@资源管理系统</p>
</div>
</div>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
return {
data: {}
}
},
methods: {
}
});
</script>
</html>
+103
View File
@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-table :data="dataList.data" v-loading="loading">
<el-table-column prop="id" label="ID" align="center" width="100">
</el-table-column>
<el-table-column prop="name" label="name">
</el-table-column>
<el-table-column prop="ip" label="IP">
</el-table-column>
<el-table-column prop="domain" label="address">
</el-table-column>
<el-table-column prop="create_time" label="创建时间" align="center" width="200">
</el-table-column>
<el-table-column prop="update_time" label="最新时间" align="center" width="200">
</el-table-column>
</el-table>
<div class="page">
<el-pagination @size-change="handleSizeChange" :page-sizes="[10, 20, 50, 100,200,500]" :page-size="10"
layout="total, sizes, prev, pager, next, jumper" background @current-change="changeCurrentPage"
:current-page="dataList.current_page" :page-count="dataList.last_page" :total="dataList.total">
</el-pagination>
</div>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
return {
loading: true,
dataList: [],
form: {
page: 1,
per_page: 10,
order: 'id desc'
},
}
},
created() {
this.getList();
},
methods: {
handleSizeChange(per_page) {
this.form.per_page = per_page;
this.getList();
},
changeCurrentPage(page) {
this.form.page = page;
this.getList();
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/log/getList', Object.assign({}, PostBase, that.form))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.dataList = response.data.data;
for (let i = 0; i < that.dataList.data.length; i++) {
if(!that.dataList.data[i].domain){
that.getAdd(i)
}
}
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
});
},
getAdd(index){
var that = this;
axios.get('https://api.suyanw.cn/api/ipcha.php?ip='+that.dataList.data[index].ip)
.then(function (res) {
that.dataList.data[index].domain = res.data.text
axios.post('/admin/log/setDomain', Object.assign({}, PostBase, {
id: that.dataList.data[index].id,
domain: that.dataList.data[index].domain,
}))
.then(function (response) {
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
});
})
},
}
})
</script>
</html>
+462
View File
@@ -0,0 +1,462 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-form :inline="true">
<el-form-item>
<el-button icon="el-icon-plus" size="small" @click="clickAdd" plain>添加</el-button>
</el-form-item>
<div style="float:right">
<el-form-item style="width:120px;">
<el-select placeholder="显示状态" size="small" v-model="search.node_show">
<el-option value="" label="全部状态">
</el-option>
<el-option v-for="show in showList" :value="show.show_id" :label="show.show_title">
</el-option>
</el-select>
</el-form-item>
<el-form-item style="width:120px;">
<el-select placeholder="筛选类别" size="small" v-model="search.filter">
<el-option value="node_id" label="节点ID">
</el-option>
<el-option value="node_title" label="节点名称">
</el-option>
<el-option value="node_desc" label="节点描述">
</el-option>
<el-option value="node_module" label="模块">
</el-option>
<el-option value="node_controller" label="控制器">
</el-option>
<el-option value="node_action" label="方法">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-input placeholder="输入关键词搜索" size="small" v-model="search.keyword"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="getList_search" plain>搜索</el-button>
</el-form-item>
</div>
</el-form>
<el-table :data="dataList" default-expand-all @selection-change="changeSelection" v-loading="loading" row-key="node_id" :tree-props="{children: 'sub', hasChildren: 'hasChildren'}">
<el-table-column prop="node_id" label="ID" width="120">
</el-table-column>
<el-table-column prop="node_title" label="节点名称">
<template slot-scope="scope">
<i :class="scope.row.node_icon" style="font-size: 16px;"></i>&nbsp;{{scope.row.node_title}}
</template>
</el-table-column>
<el-table-column label="节点地址">
<template slot-scope="scope">
{{scope.row.node_module+"/"+scope.row.node_controller+"/"+scope.row.node_action}}
</template>
</el-table-column>
<el-table-column prop="node_order" label="排序" width="">
</el-table-column>
<el-table-column label="隐藏" width="80">
<template slot-scope="scope">
<el-switch v-model="scope.row.node_show==0?true:false" active-color="#ff4949"
@change="clickShow(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template slot-scope="scope">
<el-link type="primary" @click="clickEdit(scope.row)" :underline="false">编辑</el-link>&nbsp;
<el-link type="danger" @click="clickDelete(scope.row)" :underline="false">删除</el-link>
</template>
</el-table-column>
</el-table>
<!-- 添加框 -->
<el-dialog title="添加节点" :visible.sync="dialogFormAdd" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formAdd" status-icon :rules="rules" ref="formAdd">
<el-form-item label="节点名称" :label-width="formLabelWidth" prop="node_title">
<el-input size="medium" autocomplete="off" v-model="formAdd.node_title"></el-input>
</el-form-item>
<el-form-item label="节点描述" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formAdd.node_desc"></el-input>
</el-form-item>
<el-form-item label="节点图标" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formAdd.node_icon"></el-input>
</el-form-item>
<el-form-item label="所属模块" :label-width="formLabelWidth" prop="node_module">
<el-input size="medium" autocomplete="off" v-model="formAdd.node_module"></el-input>
</el-form-item>
<el-form-item label="控制器" :label-width="formLabelWidth" prop="node_controller">
<el-input size="medium" autocomplete="off" v-model="formAdd.node_controller"></el-input>
</el-form-item>
<el-form-item label="方法" :label-width="formLabelWidth" prop="node_action">
<el-input size="medium" autocomplete="off" v-model="formAdd.node_action"></el-input>
</el-form-item>
<el-form-item label="是否显示" :label-width="formLabelWidth">
<el-select placeholder="请选择是否显示到菜单" size="small" v-model="formAdd.node_show">
<el-option v-for="show in showList" :value="show.show_id" :label="show.show_title">
</el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="父级菜单" :label-width="formLabelWidth">
<el-select placeholder="请选择菜单" size="small" v-model="formAdd.node_pid">
<el-option v-for="parent in parentList" :value="parent.node_id" :label="parent.node_title">
</el-option>
</el-select>
</el-form-item> -->
<el-form-item label="父级菜单" :label-width="formLabelWidth">
<el-cascader :options="parentList" v-model="formAdd.node_pid" :props="props" :show-all-levels="false">
</el-cascader>
</el-form-item>
<el-form-item label="显示顺序" :label-width="formLabelWidth" prop="node_order">
<el-input size="medium" autocomplete="off" v-model="formAdd.node_order"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postAdd">确认添加</el-button>
</div>
</el-dialog>
<!-- 修改框 -->
<el-dialog title="修改节点" :visible.sync="dialogFormEdit" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formEdit" status-icon :rules="rules" ref="formEdit">
<el-form-item label="节点名称" :label-width="formLabelWidth" prop="node_title">
<el-input size="medium" autocomplete="off" v-model="formEdit.node_title"></el-input>
</el-form-item>
<el-form-item label="节点描述" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formEdit.node_desc"></el-input>
</el-form-item>
<el-form-item label="节点图标" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formEdit.node_icon"></el-input>
</el-form-item>
<el-form-item label="所属模块" :label-width="formLabelWidth" prop="node_module">
<el-input size="medium" autocomplete="off" v-model="formEdit.node_module"></el-input>
</el-form-item>
<el-form-item label="控制器" :label-width="formLabelWidth" prop="node_controller">
<el-input size="medium" autocomplete="off" v-model="formEdit.node_controller"></el-input>
</el-form-item>
<el-form-item label="方法" :label-width="formLabelWidth" prop="node_action">
<el-input size="medium" autocomplete="off" v-model="formEdit.node_action"></el-input>
</el-form-item>
<el-form-item label="是否显示" :label-width="formLabelWidth">
<el-select placeholder="请选择是否显示到菜单" size="small" v-model="formEdit.node_show">
<el-option v-for="show in showList" :value="show.show_id" :label="show.show_title">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="父级菜单" :label-width="formLabelWidth">
<el-cascader :options="parentList" v-model="formEdit.node_pid" :props="props" :show-all-levels="false"></el-cascader>
</el-form-item>
<el-form-item label="显示顺序" :label-width="formLabelWidth" prop="node_order">
<el-input size="medium" autocomplete="off" v-model="formEdit.node_order"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postEdit">确认修改</el-button>
</div>
</el-dialog>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
this.getList();
return {
search: {
node_show: "",
keyword: "",
filter: "node_id"
},
formLabelWidth: '80px',
dialogFormAdd: false,
dialogFormEdit: false,
loading: true,
dataList: [],
parentList: [],
props: {
checkStrictly: true,
emitPath: false,
value: 'node_id',
label: 'node_title',
children: 'sub',
},
showList: [
{
show_id: 0,
show_title: "隐藏"
},
{
show_id: 1,
show_title: "显示"
}
],
selectList: [],
formAdd: {
node_readonly: 0,
node_pid: 0,
node_order: 1,
node_show: 1,
},
formEdit: {
node_readonly: 0,
node_pid: 0,
},
rules: {
node_title: [
{ required: true, message: '节点名称必须填写', trigger: 'blur' },
],
node_controller: [
// { required: true, pattern: /^[a-z]+$/, message: '控制器为有效小写字母', trigger: 'blur' },
],
node_module: [
{ required: true, pattern: /^[a-z]+$/, message: '模块名为有效小写字母', trigger: 'blur' },
],
node_action: [
{ required: true, pattern: /^[a-z]+$/, message: '方法名为有效小写字母', trigger: 'blur' },
],
node_order: [
{ required: true, pattern: /^\d$/, message: '顺序为有效自然数', trigger: 'blur' },
],
}
}
},
methods: {
getList_search() {
this.form.page = 1;
this.getList();
},
postMultDelete() {
var that = this;
if (that.selectList.length == 0) {
that.$message.error('未选择任何节点!');
return;
}
this.$confirm('即将删除选中的节点, 是否确认?', '批量删除', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/node/delete', Object.assign({}, PostBase, {
node_id: that.selectList.join(",")
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
changeSelection(list) {
var that = this;
that.selectList = [];
for (var index in list) {
that.selectList.push(list[index].node_id);
}
},
postEdit() {
var that = this;
axios.post('/admin/node/update', Object.assign({}, PostBase, that.formEdit))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormEdit = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
postAdd() {
var that = this;
axios.post('/admin/node/add', Object.assign({}, PostBase, that.formAdd))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormAdd = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickAdd() {
var that = this;
that.formAdd = {
node_readonly: 0,
node_pid: 0,
node_order: 1,
node_show: 1,
};
axios.post('/admin/node/getList', Object.assign({}, PostBase))
.then(function (response) {
that.groupList = response.data.data;
if (response.data.code == CODE_SUCCESS) {
that.dialogFormAdd = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickDelete(row) {
var that = this;
this.$confirm('即将删除这个节点, 是否确认?', '删除提醒', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/node/delete', Object.assign({}, PostBase, {
node_id: row.node_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
clickShow(row) {
var that = this;
axios.post(row.node_show ? '/admin/node/hide_menu' : '/admin/node/show_menu', Object.assign({}, PostBase, {
node_id: row.node_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickEdit(row) {
var that = this;
that.formEdit = row;
axios.post('/admin/node/getList', Object.assign({}, PostBase))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.groupList = response.data.data;
axios.post('/admin/node/detail', Object.assign({}, PostBase, {
node_id: row.node_id
}))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
response.data.data.node_pid = response.data.data.node_pid==0?'0':response.data.data.node_pid
that.formEdit = response.data.data;
that.dialogFormEdit = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
changeCurrentPage(page) {
this.form.page = page;
this.getList();
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/node/getList', Object.assign({}, PostBase, that.form, that.search))
.then(function (res) {
that.loading = false;
if (res.data.code == 200) {
that.dataList = JSON.parse(JSON.stringify(res.data.data.data));
that.parentList = [];
that.parentList.push({
node_id: "0",
node_title: "顶级菜单",
sub: [],
});
for (var i in res.data.data.data) {
res.data.data.data[i].node_id = res.data.data.data[i].node_id
that.parentList.push(res.data.data.data[i]);
}
for (let item of that.parentList) {
if(item.sub.length>0){
for (let items of item.sub) {
items.sub = undefined
}
}else{
item.sub = undefined
}
}
} else {
that.$message.error(res.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
console.log(error);
});
}
}
})
</script>
</html>
+324
View File
@@ -0,0 +1,324 @@
<!DOCTYPE html>
<html>
<head>
<title>资源分类</title>
{include file="common/header"/}
<el-form :inline="true">
<el-form-item>
<el-button icon="el-icon-plus" size="small" @click="clickAdd" plain>添加</el-button>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-warning-outline" size="small" @click="dayShow=true" plain>如何每日更新?</el-button>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-warning-outline" size="small" @click="allShow=true" plain>如何全部转存?</el-button>
</el-form-item>
</el-form>
<el-table :data="dataList" @selection-change="changeSelection" v-loading="loading">
<el-table-column type="selection" width="50">
</el-table-column>
<el-table-column prop="source_category_id" label="ID" width="60">
</el-table-column>
<el-table-column label="分类名称">
<template slot-scope="scope">
<img :src="scope.row.image" style="width: 30px;height:30px;vertical-align: middle;" v-if="scope.row.image" />
<span style="vertical-align: middle;margin-left: 5px">{{scope.row.name}}</span>
</template>
</el-table-column>
<el-table-column label="是否每日更新" width="150" align="center">
<template slot-scope="scope">
<el-switch v-model="scope.row.is_update==1?true:false"
@change="clickStatus(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column label="是否前台展示" width="150" align="center">
<template slot-scope="scope">
<el-switch v-model="scope.row.status==1?false:true"
@change="clickStatus(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column prop="sort" label="排序" width="150" align="center">
</el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-link type="primary" @click="s2Btn(scope.row)" :underline="false">一键转存</el-link>&nbsp;&nbsp;&nbsp;&nbsp;
<el-link type="primary" @click="clickEdit(scope.row)" :underline="false">编辑</el-link>&nbsp;&nbsp;&nbsp;&nbsp;
<el-link type="danger" @click="clickDelete(scope.row)" :underline="false">删除</el-link>
</template>
</el-table-column>
</el-table>
<!-- 添加框 -->
<el-dialog title="添加资源分类名称" :visible.sync="dialogFormAdd" width="500px" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formAdd" :rules="rules" ref="formAdd">
<el-form-item prop="name" label="分类名称" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formAdd.name"></el-input>
</el-form-item>
<el-form-item prop="image" label="图标" :label-width="formLabelWidth">
<Single v-model="formAdd.image"></Single>
</el-form-item>
<el-form-item prop="sort" label="排序" :label-width="formLabelWidth">
<el-input-number v-model="formAdd.sort" :min="0" :max="999" size="medium" style="width: 120px;"
controls-position="right" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postAdd()">确认添加</el-button>
</div>
</el-dialog>
<!-- 修改框 -->
<el-dialog title="修改资源分类信息" :visible.sync="dialogFormEdit" width="500px" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<el-form :model="formEdit" :rules="rules" ref="formEdit">
<el-form-item prop="name" label="分类名称" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" v-model="formEdit.name" disabled ></el-input>
</el-form-item>
<el-form-item prop="image" label="图标" :label-width="formLabelWidth">
<Single v-model="formEdit.image"></Single>
</el-form-item>
<el-form-item prop="sort" label="排序" :label-width="formLabelWidth">
<el-input-number v-model="formEdit.sort" :min="0" :max="999" size="medium" style="width: 120px;"
controls-position="right" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postEdit()">确认修改</el-button>
</div>
</el-dialog>
<!-- 每日更新 -->
<el-dialog title="每日更新" :visible.sync="dayShow" width="500px" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<div style="margin-bottom: 20px;font-size:14px;color:#666;line-height: 2">
<p>自动更新:<font color=orangered>转存当日及昨天的资源数据;</font></p>
<font color=orangered>将此接口添加到计划任务中,计划任务每日执行一次即可;</font>
<p>接口地址:{{domain}}/api/source/day</p>
<p>Tips:添加计划任务后方可生效;名称重复的资源会跳过转存;</p>
<p>宝塔任务类型:访问URL-GET</p>
</div>
</el-dialog>
<!-- 全部更新 -->
<el-dialog title="全部转存" :visible.sync="allShow" width="500px" :modal-append-to-body='false' append-to-body :close-on-click-modal='false'>
<div style="margin-bottom: 20px;font-size:14px;color:#666;line-height: 2">
<p>全部转存:<font color=orangered>一键转存心悦搜索所有资源到自己的网盘及系统中</font></p>
<font color=orangered>全部转存速度比较慢,提交后请耐心等待;名称重复的资源会跳过转存;</font>
<p>全部转存需要按类别转存:见下方列表一键转存按钮</p>
<p>Tips:心悦搜索:https://pan.xinyuedh.com</p>
</div>
</el-dialog>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
this.getList();
return {
formLabelWidth: '80px',
dialogFormAdd: false,
dialogFormEdit: false,
loading: true,
dataList: [],
selectList: [],
formAdd: {
image: '',
sort: 0
},
formEdit: {
},
rules: {
name: [ { required: true, message: '请输入分类名称', trigger: 'blur' }],
},
allShow: false,
dayShow: false,
domain: window.location.protocol+'//'+window.location.host
}
},
methods: {
changeSelection(list) {
var that = this;
that.selectList = [];
for (var index in list) {
that.selectList.push(list[index].source_category_id);
}
},
postEdit() {
var that = this;
that.$refs["formEdit"].validate((valid) => {
if (valid) {
axios.post('/admin/source_category/update', Object.assign({}, PostBase, that.formEdit))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormEdit = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}
});
},
postAdd() {
var that = this;
that.$refs['formAdd'].validate((valid) => {
if (valid) {
axios.post('/admin/source_category/add', Object.assign({}, PostBase, that.formAdd))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormAdd = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}
});
},
clickAdd() {
var that = this;
that.formAdd = { sort: 0,image: '' };
that.dialogFormAdd = true;
},
clickDelete(row) {
var that = this;
this.$confirm('即将删除这个分类, 是否确认?', '删除提醒', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/source_category/delete', Object.assign({}, PostBase, {
source_category_id: row.source_category_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
clickStatus(row) {
var that = this;
axios.post(row.status ? '/admin/source_category/enable' : '/admin/source_category/disable', Object.assign({}, PostBase, {
source_category_id: row.source_category_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
clickEdit(row) {
var that = this;
that.formEdit = row;
axios.post('/admin/source_category/detail', Object.assign({}, PostBase, {
source_category_id: row.source_category_id
}))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.formEdit = response.data.data;
that.formEdit.image = that.formEdit.image||''
that.dialogFormEdit = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/source_category/getList', Object.assign({}, PostBase))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.dataList = response.data.data;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
console.log(error);
});
},
s2Btn(row){
let that = this
if(row.source_category_id!=1) return that.$message.error('当前版本仅支持短剧');
this.$confirm('全部转存速度比较慢,提交后请耐心等待,该操作不可暂停, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/source/transferAll', Object.assign({}, PostBase,{
source_category_id: row.source_category_id
}))
.then(function (res) {
if (res.data.code == 200) {
} else {
that.$message.error(res.data.message);
}
})
.catch(function (error) {
});
that.$message({
message: "已提交任务,稍后查看结果",
type: 'success'
});
}).catch(() => {});
},
}
})
</script>
</html>
+116
View File
@@ -0,0 +1,116 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
<style>
textarea{
height: 300px;
}
</style>
{include file="common/header"/}
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<span>目前仅支持夸克</span>
</div>
<div class="text item">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>设置夸克cookie</span>
</div>
<div style="font-size:14px;color:#666;">
<el-form :model="form">
<el-form-item>
<el-input style="width: 100%;" v-model="form.cookie" placeholder="夸克云盘网页版的cookie"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">保存</el-button>
</el-form-item>
</el-form>
<p>Tips:夸克云盘网页版的cookie,不懂如何获取请百度;填写并保存后才能使用下面功能</p>
</div>
</el-card>
</div>
</el-card>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
return {
form: {
cookie: '',
},
file: '',
files: [],
};
},
created() {
this.getData();
// this.getFile()
},
methods: {
getData(){
let that = this
axios.post('/admin/conf/getBaseConfig', Object.assign({}, PostBase))
.then(function (response) {
if (response.data.code == 200) {
for (let item of response.data.data) {
if(item.conf_key === 'quark_cookie'){
that.form.cookie = item.conf_value
}
if(item.conf_key === 'quark_file'){
that.file = item.conf_value
}
}
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
});
},
onSubmit(){
let that = this
axios.post('/admin/conf/updateBaseConfig', Object.assign({}, PostBase, {
quark_cookie: that.form.cookie
}))
.then(function (response) {
if (response.data.code == 200) {
that.$message({
message: response.data.message,
type: 'success'
});
that.getFile()
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
getFile(){
let that = this
axios.post('/admin/source/getFiles', Object.assign({}, PostBase))
.then(function (res) {
if (res.data.code == 200) {
that.files = res.data || []
} else {
that.$message.error(res.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
},
}
})
</script>
</html>
+74
View File
@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-table :data="dataList.data" v-loading="loading">
<el-table-column prop="id" label="ID" align="center" width="100">
</el-table-column>
<el-table-column prop="content" label="用户想要的资源描述">
</el-table-column>
<el-table-column prop="create_time" label="提交时间" align="center" width="200">
</el-table-column>
</el-table>
<div class="page">
<el-pagination @size-change="handleSizeChange" :page-sizes="[10, 20, 50, 100,200,500]" :page-size="10"
layout="total, sizes, prev, pager, next, jumper" background @current-change="changeCurrentPage"
:current-page="dataList.current_page" :page-count="dataList.last_page" :total="dataList.total">
</el-pagination>
</div>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
return {
loading: true,
dataList: [],
form: {
page: 1,
per_page: 10,
order: 'id desc'
},
}
},
created() {
this.getList();
},
methods: {
handleSizeChange(per_page) {
this.form.per_page = per_page;
this.getList();
},
changeCurrentPage(page) {
this.form.page = page;
this.getList();
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/feedback/getList', Object.assign({}, PostBase, that.form))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.dataList = response.data.data;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
});
},
}
})
</script>
</html>
+476
View File
@@ -0,0 +1,476 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-form :inline="true" @submit.native.prevent>
<el-form-item>
<el-button icon="el-icon-plus" size="small" @click="clickAdd" plain>添加资源</el-button>
<el-button icon="el-icon-document-copy" size="small" @click="getExport" plain>导出资源</el-button>
<el-button icon="el-icon-plus" size="small" @click="ImportShow" plain>夸克导入专用</el-button>
<el-button icon="el-icon-plus" size="small" @click="ImportBatch" plain>批量导入</el-button>
</el-form-item>
<div style="float:right">
<el-form-item style="width:120px;">
<el-select size="small" v-model="search.source_category_id" placeholder="筛选分类">
<el-option v-for="item in category" :key="item.source_category_id" :label="item.name" :value="item.source_category_id">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-input placeholder="输入关键词搜索" size="small" v-model="search.keyword" @keyup.enter.native="getList_search"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="getList_search" plain>搜索
</el-button>
<el-button icon="el-icon-refresh-left" size="small" @click="getList_search(0)" plain>重置</el-button>
</el-form-item>
</div>
</el-form>
<el-table :data="dataList.data" v-loading="loading">
<el-table-column prop="source_id" label="ID" width="80">
</el-table-column>
<el-table-column prop="title" label="资源名称">
</el-table-column>
<el-table-column prop="source_category_id_name" label="资源分类">
</el-table-column>
<el-table-column prop="url" label="资源地址" align="center">
</el-table-column>
<el-table-column prop="create_time" label="入库时间" align="center" width="200">
</el-table-column>
<el-table-column prop="update_time" label="更新时间" align="center" width="200">
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<div class="order-text">
<p>
<el-link type="success" @click="clickEdit(scope.row)" :underline="false">编辑</el-link>
</p>
<p>
<el-link type="danger" @click="clickDelete(scope.row)" :underline="false">删除</el-link>
</p>
</div>
</template>
</el-table-column>
</el-table>
<div class="page">
<el-pagination @size-change="handleSizeChange" :page-sizes="[10, 20, 50, 100,200,500]" :page-size="10"
layout="total, sizes, prev, pager, next, jumper" background @current-change="changeCurrentPage"
:current-page="dataList.current_page" :page-count="dataList.last_page" :total="dataList.total">
</el-pagination>
</div>
<!-- 添加框 -->
<el-dialog title="添加资源" :visible.sync="dialogFormAdd" :modal-append-to-body='false' append-to-body
:close-on-click-modal='false' width="680px">
<el-form :model="formAdd" :rules="rules" ref="formAdd">
<el-form-item prop="source_category_id" label="资源分类" :label-width="formLabelWidth">
<el-select size="medium" v-model="formAdd.source_category_id" placeholder="请选择分类">
<el-option v-for="item in category" :key="item.source_category_id" :label="item.name" :value="item.source_category_id">
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="title" label="资源名称" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" placeholder="请输入资源名称" v-model="formAdd.title"></el-input>
</el-form-item>
<el-form-item prop="url" label="资源地址" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" placeholder="请输入资源地址" v-model="formAdd.url"></el-input>
</el-form-item>
<el-form-item label="关键词搜索" :label-width="formLabelWidth">
<el-input type="textarea" :rows="5" size="medium" autocomplete="off" placeholder="一行一个名称" v-model="formAdd.description"></el-input>
</el-form-item>
<el-form-item label="资源介绍" :label-width="formLabelWidth">
<el-input type="textarea" :rows="5" size="medium" autocomplete="off" placeholder="" v-model="formAdd.vod_content"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postAdd()">确认添加</el-button>
</div>
</el-dialog>
<!-- 修改框 -->
<el-dialog title="修改资源" :visible.sync="dialogFormEdit" :modal-append-to-body='false' append-to-body
:close-on-click-modal='false' width="680px">
<el-form :model="formEdit" :rules="rules" ref="formEdit">
<el-form-item prop="source_category_id" label="资源分类" :label-width="formLabelWidth">
<el-select size="medium" v-model="formEdit.source_category_id" placeholder="请选择分类" clearable>
<el-option v-for="item in category" :key="item.source_category_id" :label="item.name"
:value="item.source_category_id">
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="title" label="资源名称" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" placeholder="请输入资源名称" v-model="formEdit.title"></el-input>
</el-form-item>
<el-form-item prop="url" label="资源地址" :label-width="formLabelWidth">
<el-input size="medium" autocomplete="off" placeholder="请输入资源地址" v-model="formEdit.url"></el-input>
</el-form-item>
<el-form-item label="关键词搜索" :label-width="formLabelWidth">
<el-input type="textarea" :rows="5" size="medium" autocomplete="off" placeholder="一行一个名称" v-model="formEdit.description"></el-input>
</el-form-item>
<el-form-item label="资源介绍" :label-width="formLabelWidth">
<el-input type="textarea" :rows="5" size="medium" autocomplete="off" placeholder="" v-model="formEdit.vod_content"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="postEdit()">确认修改</el-button>
</div>
</el-dialog>
<!-- 夸克导入数据 -->
<el-dialog title="导入资源" :visible.sync="dialogImport" :modal-append-to-body='false' append-to-body
:close-on-click-modal='false' width="600px">
<el-form :model="Importform">
<el-form-item prop="source_category_id" label="资源分类" label-width="90px">
<el-select size="medium" v-model="Importform.source_category_id" placeholder="请选择分类" clearable>
<el-option v-for="item in category" :key="item.source_category_id" :label="item.name"
:value="item.source_category_id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="" label-width="90px">
<el-upload class="upload-demo" :data="Importform" name="file"
ref="ImportUpload"
drag
:auto-upload="false"
limit="1"
:on-exceed="handleExceed"
:on-success="handleAvatarSuccess"
action="/admin/source/imports"
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>
<span style="color: #999;">请导入夸克官方导出的csv文件</span>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="ImportPost()">提交</el-button>
</div>
</el-dialog>
<!-- 批量导入数据 -->
<el-dialog title="导入资源" :visible.sync="dialogBatch" :modal-append-to-body='false' append-to-body
:close-on-click-modal='false' width="790px">
<el-form :model="Batchform">
<el-form-item prop="type" label="选择方式" label-width="70px">
<el-radio-group v-model="Batchform.type">
<el-radio-button :label="1">直接导入</el-radio-button>
<el-radio-button :label="2">转存分享导入</el-radio-button>
</el-radio-group>
<p style="color: #999;" v-if='Batchform.type==1'>直接导入:链接校验有效后直接入库;Tips:该功能不会检测是否重复;</p>
<p style="color: #999;" v-else-if='Batchform.type==2'>将资源转存到自己网盘后分享入库(<font color=orangered>此功能仅支持夸克</font>Tips:该功能不会检测是否重复;</p>
<span style="color: #999;" v-if='Batchform.type==1'>支持<font color=orangered>夸克、阿里、UC</font>的网盘资源(一次最多可以上传500条资源)</span>
<span style="color: #999;" v-else-if='Batchform.type==2'>目前仅支持<font color=orangered>夸克</font>的网盘资源(一次最多可以上传500条资源)</span>
</el-form-item>
<el-form-item prop="source_category_id" label="资源分类" label-width="70px" v-if="Batchform.type">
<el-select size="medium" v-model="Batchform.source_category_id" placeholder="请选择分类" clearable>
<el-option v-for="item in category" :key="item.source_category_id" :label="item.name"
:value="item.source_category_id">
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="urls" label="资源分类" label-width="70px" v-if="Batchform.type">
<el-input
type="textarea"
placeholder="资源示例:
一条资源一行
https://pan.quark.cn/s/xxxxxxxx
https://www.alipan.com/s/xxxxxxxxx
https://drive.uc.cn/s/xxxxxxxxxxx"
v-model="Batchform.urls"
rows="20"
show-word-limit
>
</el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="BatchPost()">提交</el-button>
</div>
</el-dialog>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
return {
search: {
keyword: "",
filter: "title",
source_category_id: ''
},
formLabelWidth: '120px',
dialogFormAdd: false,
dialogFormEdit: false,
loading: true,
dataList: [],
form: {
page: 1,
per_page: 10,
order: 'create_time desc'
},
formAdd: {
},
formEdit: {
},
rules: {
title: [{ required: true, message: '请输入资源名称', trigger: 'blur' }],
url: [{ required: true, message: '请输入资源地址', trigger: 'blur' }],
},
dialogImport: false,
Importform: {
},
category: [],
dialogBatch: false,
Batchform: {},
}
},
created() {
this.getcategory();
},
methods: {
getList_search(val) {
if (val == 0) {
this.search = {
keyword: "",
filter: "title",
source_category_id: ''
}
}
this.form.page = 1;
this.getList();
},
handleSizeChange(per_page) {
this.form.per_page = per_page;
this.getList();
},
postEdit() {
var that = this;
that.$refs["formEdit"].validate((valid) => {
if (valid) {
axios.post('/admin/source/update', Object.assign({}, PostBase, that.formEdit))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormEdit = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}
});
},
postAdd() {
var that = this;
that.$refs['formAdd'].validate((valid) => {
if (valid) {
axios.post('/admin/source/add', Object.assign({}, PostBase, that.formAdd))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
that.dialogFormAdd = false;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
});
}
});
},
clickAdd() {
var that = this;
that.formAdd = { status: 1, share_image: '' };
that.dialogFormAdd = true;
},
clickDelete(row) {
var that = this;
this.$confirm('删除后,资源将无法查看,是否继续删除?', '删除提醒', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/source/delete', Object.assign({}, PostBase, {
source_id: row.source_id
}))
.then(function (response) {
that.getList();
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
});
}).catch(() => {
});
},
clickEdit(row) {
var that = this;
that.formEdit = row;
axios.post('/admin/source/detail', Object.assign({}, PostBase, {
source_id: row.source_id
}))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
response.data.data.source_category_id = response.data.data.source_category_id || undefined
that.formEdit = response.data.data;
that.dialogFormEdit = true;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
});
},
changeCurrentPage(page) {
this.form.page = page;
this.getList();
},
getcategory(){
var that = this;
axios.post('/admin/source_category/getList', Object.assign({}, PostBase))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.category = response.data.data;
that.getList();
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
console.log(error);
});
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/source/getList', Object.assign({}, PostBase, that.form, that.search))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.dataList = response.data.data;
that.setcategory()
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
});
},
setcategory(){
for (let item of this.dataList.data) {
for (let items of this.category) {
if(item.source_category_id == items.source_category_id){
item.source_category_id_name = items.name
}
}
}
},
//导入数据
ImportShow() {
this.Importform = {
}
this.dialogImport = true
},
handleExceed(files, fileList) {
this.$message.warning(`只能选择一个文件`);
},
handleAvatarSuccess(res, file) {
if (res.code == 200) {
this.getList();
this.$message({
message: res.message,
type: 'success'
});
this.dialogImport = false;
} else {
this.$message.error(res.message);
}
this.$refs.ImportUpload.clearFiles();
},
ImportPost(){
this.Importform = Object.assign(this.Importform, PostBase)
this.$nextTick(() => {
this.$refs.ImportUpload.submit();
})
},
//批量导入数据
ImportBatch() {
this.Batchform = {}
this.dialogBatch = true
},
BatchPost(){
var that = this;
if(!that.Batchform.type) return that.$message.error('请选择导入方式');
if(!that.Batchform.urls) return that.$message.error('请输入资源地址');
axios.post('/admin/source/transfer', Object.assign({}, PostBase, that.Batchform))
.then(function (res) {
})
.catch(function (error) {
that.$message.error('服务器内部错误');
});
that.$message({
message: "已提交任务,稍后查看结果",
type: 'success'
});
},
//数据导出
getExport(){
var that = this;
var filters = Object.assign({}, PostBase, that.search);
var url = '/admin/source/excel?';
for (let key in filters) {
url += key + "=" + filters[key] + "&";
}
window.open(url);
that.$message.success('数据导出成功');
},
}
})
</script>
</html>
+92
View File
@@ -0,0 +1,92 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-table :data="dataList.data" v-loading="loading">
<el-table-column prop="name" label="任务名称">
</el-table-column>
<el-table-column prop="total_num" label="转存/导入总数" align="center">
</el-table-column>
<el-table-column prop="new_num" label="新增数" align="center">
</el-table-column>
<el-table-column prop="skip_num" label="重复跳过" align="center">
</el-table-column>
<el-table-column prop="fail_num" label="失败数" align="center">
</el-table-column>
<el-table-column prop="fail_dec" label="最新错误信息" align="center">
</el-table-column>
<el-table-column label="状态" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.end_time">已完成</el-tag>
<el-tag type="danger" v-else>转存中</el-tag>
</template>
</el-table-column>
<el-table-column prop="create_time" label="时间" align="center" width="240">
<template slot-scope="scope">
<p>任务开始:{{scope.row.create_time}}</p>
<p v-if="scope.row.end_time">任务结束:{{scope.row.end_time}}</p>
</template>
</el-table-column>
</el-table>
<div class="page">
<el-pagination @size-change="handleSizeChange" :page-sizes="[10, 20, 50, 100,200,500]" :page-size="10"
layout="total, sizes, prev, pager, next, jumper" background @current-change="changeCurrentPage"
:current-page="dataList.current_page" :page-count="dataList.last_page" :total="dataList.total">
</el-pagination>
</div>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
return {
loading: true,
dataList: [],
form: {
page: 1,
per_page: 10,
order: 'source_log_id desc'
},
}
},
created() {
this.getList();
},
methods: {
handleSizeChange(per_page) {
this.form.per_page = per_page;
this.getList();
},
changeCurrentPage(page) {
this.form.page = page;
this.getList();
},
getList() {
var that = this;
that.loading = true;
axios.post('/admin/source_log/getList', Object.assign({}, PostBase, that.form))
.then(function (response) {
that.loading = false;
if (response.data.code == CODE_SUCCESS) {
that.dataList = response.data.data;
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.loading = false;
that.$message.error('服务器内部错误');
});
},
}
})
</script>
</html>
+100
View File
@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html>
<head>
<title>{$node.node_title}</title>
{include file="common/header"/}
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<span>系统数据清理</span>
</div>
<div class="text item">
<!-- <el-card class="box-card">
<div slot="header" class="clearfix">
<span>清理授权记录</span>
</div>
<div style="margin-bottom: 20px;font-size:14px;color:#666;">
用户组授权信息清理为
<font color=orangered>不可逆操作</font>,请谨慎操作!<br> 清理完毕后,除超级管理用户组外,其他任何用户组将无法访问系统任何功能!
<br> 建议仅在用户组权限混乱或出现其他账号安全问题时进行清理操作。
<br> 清理成功后可重新对用户组进行权限授权,即可恢复正常使用。
</div>
<el-button type="danger" @click="clearAuth">清理授权</el-button>
</el-card>
<br> -->
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>清除缓存</span>
</div>
<div style="margin-bottom: 20px;font-size:14px;color:#666;">
清除缓存
<font color=orangered>不可逆操作</font>
</div>
<el-button type="danger" @click="clearLog">清除缓存</el-button>
</el-card>
</div>
</el-card>
{include file="common/footer"/}
<script>
var app = new Vue({
el: '#app',
data() {
return {};
},
methods: {
clearLog() {
var that = this;
this.$confirm('即将清除缓存, 是否确认?', '删除日志', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/admin/system/clean', Object.assign({}, PostBase))
.then(function (response) {
if (response.data.code == CODE_SUCCESS) {
that.$message({
message: response.data.message,
type: 'success'
});
} else {
that.$message.error(response.data.message);
}
})
.catch(function (error) {
that.$message.error('服务器内部错误');
console.log(error);
});
}).catch(() => {
});
},
// clearAuth() {
// var that = this;
// this.$confirm('即将删除授权信息, 是否确认?', '清空授权', {
// confirmButtonText: '删除',
// cancelButtonText: '取消',
// type: 'warning'
// }).then(() => {
// axios.post('/admin/auth/clean', Object.assign({}, PostBase))
// .then(function (response) {
// if (response.data.code == CODE_SUCCESS) {
// that.$message({
// message: response.data.message,
// type: 'success'
// });
// } else {
// that.$message.error(response.data.message);
// }
// })
// .catch(function (error) {
// that.$message.error('服务器内部错误');
// console.log(error);
// });
// }).catch(() => {
// });
// },
}
})
</script>
</html>
+9
View File
@@ -0,0 +1,9 @@
<?php
use app\AppService;
// 系统服务定义文件
// 服务在完成全局初始化之后执行
return [
AppService::class,
];

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