Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71c2338086 | ||
|
|
3d652114a9 | ||
|
|
a1044c5287 | ||
|
|
32dcc9e277 | ||
|
|
d360dc8ee9 | ||
|
|
bfa96c13d4 | ||
|
|
e12dead6c8 | ||
|
|
2d6e5aabbd | ||
|
|
b8194994f0 | ||
|
|
a74ad2dda2 | ||
|
|
183760f1af | ||
|
|
e4ae29fed2 | ||
|
|
c82e1c8ea3 | ||
|
|
3f718beacb | ||
|
|
af44a9e7b8 | ||
|
|
4ed8237a00 | ||
|
|
216ca6e697 | ||
|
|
969a7a5ce5 | ||
|
|
5593a20009 | ||
|
|
8a33a4fed3 | ||
|
|
a4e8a86045 | ||
|
|
61e622d2ad | ||
|
|
1b3265aeb5 | ||
|
|
e1c0f6c881 | ||
|
|
3891cf8898 | ||
|
|
4ade618657 | ||
|
|
e7253e7de0 | ||
|
|
063108a846 | ||
|
|
f41943320b | ||
|
|
1f0064743e | ||
|
|
115573a88c | ||
|
|
253379f0c6 | ||
|
|
9a0ff912b5 | ||
|
|
517fd191d3 | ||
|
|
d1dfa8b49b | ||
|
|
c819751a66 | ||
|
|
3a2ee69d0f | ||
|
|
d513177c74 | ||
|
|
0705b9a38d | ||
|
|
feb26660e8 | ||
|
|
b8ccf1542b | ||
|
|
74122885f1 | ||
|
|
f5813dec99 | ||
|
|
db0ac015f0 | ||
|
|
bdabac7cff | ||
|
|
bd9cb6a3af | ||
|
|
3aaf030b89 | ||
|
|
16975c4ee8 | ||
|
|
666598cd30 | ||
|
|
b9f764e4d0 | ||
|
|
bc03616e43 | ||
|
|
8aba56c8c2 | ||
|
|
150e0ecd23 | ||
|
|
e9ed0cd8f6 | ||
|
|
187d4343b3 | ||
|
|
9bc0185b6b | ||
|
|
652b17d6a6 | ||
|
|
ed8c3d545b | ||
|
|
12b38c7bf5 | ||
|
|
fc202be987 | ||
|
|
71e069712a | ||
|
|
ca4080d5e6 | ||
|
|
4bbe287626 | ||
|
|
e316cd40e0 | ||
|
|
a7a3ddef8b | ||
|
|
51f2cbc0f4 | ||
|
|
8acf9f3f6c | ||
|
|
d7b23f305d | ||
|
|
fdfe2a542a | ||
|
|
3d412d9ec6 | ||
|
|
f75ebffa5d | ||
|
|
77881a27ed | ||
|
|
07e11a1c45 | ||
|
|
8531ec89ad | ||
|
|
ff2e842c24 | ||
|
|
3d767643c8 | ||
|
|
08fb6ef4d0 | ||
|
|
32d94bb3e0 | ||
|
|
d93483d9bf | ||
|
|
973e9cb24c | ||
|
|
b510042323 | ||
|
|
b55dd8f67a | ||
|
|
8e488fb46c | ||
|
|
d99e168583 | ||
|
|
d6bb1456fa | ||
|
|
91eac36371 | ||
|
|
1e4486989a |
10
.example.env
10
.example.env
@@ -14,6 +14,16 @@ DB_PORT=3306
|
|||||||
DB_CHARSET=utf8mb4
|
DB_CHARSET=utf8mb4
|
||||||
DB_PREFIX=ea8_
|
DB_PREFIX=ea8_
|
||||||
|
|
||||||
|
# 限流器开关 若启动需要配置 Redis 服务
|
||||||
|
RATE_LIMITING_STATUS=false
|
||||||
|
|
||||||
|
# Redis配置
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PORT=6379
|
||||||
|
REDIS_PASSWORD=
|
||||||
|
REDIS_PREFIX=
|
||||||
|
REDIS_DATABASE=0
|
||||||
|
|
||||||
# 后台配置项组
|
# 后台配置项组
|
||||||
[EASYADMIN]
|
[EASYADMIN]
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div align="center" dir="auto">
|
<div align="center" dir="auto">
|
||||||
<img alt="log" src="/public/static/common/images/logo-8.png" />
|
<img alt="log" src="public/static/common/images/logo-8.png" />
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<img src="https://img.shields.io/badge/php-%3E=8.1.0-brightgreen.svg?style=for-the-badge&logo=php&colorB=ff69b4" alt="php">
|
<img src="https://img.shields.io/badge/php-%3E=8.1.0-brightgreen.svg?style=for-the-badge&logo=php&colorB=ff69b4" alt="php">
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
|
|
||||||
## 项目介绍
|
## 项目介绍
|
||||||
|
|
||||||
> `EasyAdmin8` 在 [`EasyAdmin`](https://gitee.com/zhongshaofa/easyadmin) 的基础上更新 ThinkPHP 框架到 8.0+ ,PHP 最低版本要求不低于 8.1
|
> `EasyAdmin8` 在 [`EasyAdmin`](https://gitee.com/zhongshaofa/easyadmin) 的基础上更新 ThinkPHP 框架到 8.1+ ,PHP 最低版本要求不低于 8.1
|
||||||
>
|
>
|
||||||
> 2025年起 `PHP` 版本要求提升到 `8.1+`, 如果需要 `8.0` 到分支 `v8.0` 中下载
|
> 2025年起 `PHP` 版本要求提升到 `8.1+`, 如果需要 `8.0` 到分支 `v8.0` 中下载
|
||||||
>
|
>
|
||||||
> ThinkPHP v8.0+ 和 Layui v2.9.x 的快速开发的后台管理系统。
|
> ThinkPHP v8.1+ 和 Layui v2.9.x 的快速开发的后台管理系统。
|
||||||
>
|
>
|
||||||
> 项目地址:[http://easyadmin8.top](http://easyadmin8.top)
|
> 项目地址:[http://easyadmin8.top](http://easyadmin8.top)
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use app\admin\middleware\CheckInstall;
|
|||||||
use app\admin\middleware\CheckLogin;
|
use app\admin\middleware\CheckLogin;
|
||||||
use app\admin\middleware\CheckAuth;
|
use app\admin\middleware\CheckAuth;
|
||||||
use app\admin\middleware\SystemLog;
|
use app\admin\middleware\SystemLog;
|
||||||
|
use app\admin\middleware\RateLimiting;
|
||||||
|
|
||||||
// 你可以在这里继续写你需要的路由
|
// 你可以在这里继续写你需要的路由
|
||||||
|
|
||||||
@@ -16,6 +17,8 @@ use app\admin\middleware\SystemLog;
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'middleware' => [
|
'middleware' => [
|
||||||
|
// 限流中间件
|
||||||
|
RateLimiting::class,
|
||||||
// 判断是否已经安装后台系统
|
// 判断是否已经安装后台系统
|
||||||
CheckInstall::class,
|
CheckInstall::class,
|
||||||
// 检测是否登录
|
// 检测是否登录
|
||||||
|
|||||||
@@ -109,24 +109,21 @@ class Ajax extends AdminController
|
|||||||
*/
|
*/
|
||||||
public function getUploadFiles(Request $request): Json
|
public function getUploadFiles(Request $request): Json
|
||||||
{
|
{
|
||||||
$get = $request->get();
|
$get = $request->get();
|
||||||
$page = !empty($get['page']) ? $get['page'] : 1;
|
$page = !empty($get['page']) ? $get['page'] : 1;
|
||||||
$limit = !empty($get['limit']) ? $get['limit'] : 10;
|
$limit = !empty($get['limit']) ? $get['limit'] : 10;
|
||||||
$title = !empty($get['title']) ? $get['title'] : null;
|
$title = !empty($get['title']) ? $get['title'] : null;
|
||||||
$this->model = new SystemUploadfile();
|
$count = SystemUploadfile::where(function(Query $query) use ($title) {
|
||||||
$count = $this->model
|
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
|
||||||
->where(function (Query $query) use ($title) {
|
})
|
||||||
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
|
|
||||||
})
|
|
||||||
->count();
|
->count();
|
||||||
$list = $this->model
|
$list = SystemUploadfile::where(function(Query $query) use ($title) {
|
||||||
->where(function (Query $query) use ($title) {
|
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
|
||||||
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
|
})
|
||||||
})
|
|
||||||
->page($page, $limit)
|
->page($page, $limit)
|
||||||
->order($this->sort)
|
->order($this->sort)
|
||||||
->select()->toArray();
|
->select()->toArray();
|
||||||
$data = [
|
$data = [
|
||||||
'code' => 0,
|
'code' => 0,
|
||||||
'msg' => '',
|
'msg' => '',
|
||||||
'count' => $count,
|
'count' => $count,
|
||||||
@@ -149,7 +146,7 @@ class Ajax extends AdminController
|
|||||||
$upload_allow_size = $uploadConfig['upload_allow_size'];
|
$upload_allow_size = $uploadConfig['upload_allow_size'];
|
||||||
$_upload_allow_ext = explode(',', $uploadConfig['upload_allow_ext']);
|
$_upload_allow_ext = explode(',', $uploadConfig['upload_allow_ext']);
|
||||||
$upload_allow_ext = [];
|
$upload_allow_ext = [];
|
||||||
array_map(function ($value) use (&$upload_allow_ext) {
|
array_map(function($value) use (&$upload_allow_ext) {
|
||||||
$upload_allow_ext[] = '.' . $value;
|
$upload_allow_ext[] = '.' . $value;
|
||||||
}, $_upload_allow_ext);
|
}, $_upload_allow_ext);
|
||||||
$config = [
|
$config = [
|
||||||
@@ -213,4 +210,23 @@ class Ajax extends AdminController
|
|||||||
return json($config);
|
return json($config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function composerInfo(): Json
|
||||||
|
{
|
||||||
|
$lockFilePath = root_path() . '/composer.lock';
|
||||||
|
$list = [];
|
||||||
|
if (file_exists($lockFilePath)) {
|
||||||
|
$lockFileContent = file_get_contents($lockFilePath);
|
||||||
|
if ($lockFileContent !== false) {
|
||||||
|
$lockData = json_decode($lockFileContent, true);
|
||||||
|
if (!empty($lockData['packages'])) {
|
||||||
|
foreach ($lockData['packages'] as $package) {
|
||||||
|
$list[] = ['name' => $package['name'], 'version' => $package['version']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->success('success', $list);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ class Index extends AdminController
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$save = $row->save([
|
$save = $row->save([
|
||||||
'password' => password($post['password']),
|
'password' => password_hash($post['password'], PASSWORD_DEFAULT),
|
||||||
]);
|
]);
|
||||||
}catch (Exception $e) {
|
}catch (Exception $e) {
|
||||||
$this->error('保存失败');
|
$this->error('保存失败');
|
||||||
|
|||||||
@@ -4,17 +4,19 @@ namespace app\admin\controller;
|
|||||||
|
|
||||||
use app\admin\model\SystemAdmin;
|
use app\admin\model\SystemAdmin;
|
||||||
use app\common\controller\AdminController;
|
use app\common\controller\AdminController;
|
||||||
|
use app\common\utils\Helper;
|
||||||
use think\captcha\facade\Captcha;
|
use think\captcha\facade\Captcha;
|
||||||
use think\db\exception\DataNotFoundException;
|
use think\db\exception\DataNotFoundException;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use think\db\exception\ModelNotFoundException;
|
use think\db\exception\ModelNotFoundException;
|
||||||
use app\Request;
|
use app\Request;
|
||||||
use think\Response;
|
use think\Response;
|
||||||
|
use Wolfcode\RateLimiting\Attributes\RateLimitingMiddleware;
|
||||||
|
|
||||||
class Login extends AdminController
|
class Login extends AdminController
|
||||||
{
|
{
|
||||||
|
|
||||||
protected bool $ignoreAuth = true;
|
protected bool $ignoreLogin = true;
|
||||||
|
|
||||||
public function initialize(): void
|
public function initialize(): void
|
||||||
{
|
{
|
||||||
@@ -34,6 +36,7 @@ class Login extends AdminController
|
|||||||
* @throws DbException
|
* @throws DbException
|
||||||
* @throws ModelNotFoundException
|
* @throws ModelNotFoundException
|
||||||
*/
|
*/
|
||||||
|
#[RateLimitingMiddleware(key: [Helper::class, 'getIp'], seconds: 1, limit: 1, message: '请求过于频繁')]
|
||||||
public function index(Request $request): string
|
public function index(Request $request): string
|
||||||
{
|
{
|
||||||
$captcha = env('EASYADMIN.CAPTCHA', 1);
|
$captcha = env('EASYADMIN.CAPTCHA', 1);
|
||||||
@@ -50,7 +53,7 @@ class Login extends AdminController
|
|||||||
if (empty($admin)) {
|
if (empty($admin)) {
|
||||||
$this->error('用户不存在');
|
$this->error('用户不存在');
|
||||||
}
|
}
|
||||||
if (password($post['password']) != $admin->password) {
|
if (!password_verify($post['password'], $admin->password)) {
|
||||||
$this->error('密码输入有误');
|
$this->error('密码输入有误');
|
||||||
}
|
}
|
||||||
if ($admin->status == 0) {
|
if ($admin->status == 0) {
|
||||||
@@ -65,7 +68,7 @@ class Login extends AdminController
|
|||||||
$admin->save();
|
$admin->save();
|
||||||
$admin = $admin->toArray();
|
$admin = $admin->toArray();
|
||||||
unset($admin['password']);
|
unset($admin['password']);
|
||||||
$admin['expire_time'] = $post['keep_login'] == 1 ? true : time() + 7200;
|
$admin['expire_time'] = $post['keep_login'] == 1 ? 0 : time() + 7200;
|
||||||
session('admin', $admin);
|
session('admin', $admin);
|
||||||
$this->success('登录成功');
|
$this->success('登录成功');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Cate extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new MallCate();
|
self::$model = MallCate::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,8 @@ use app\admin\service\annotation\NodeAnnotation;
|
|||||||
use app\Request;
|
use app\Request;
|
||||||
use think\App;
|
use think\App;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
|
use Wolfcode\Ai\Enum\AiType;
|
||||||
|
use Wolfcode\Ai\Service\AiChatService;
|
||||||
|
|
||||||
#[ControllerAnnotation(title: '商城商品管理')]
|
#[ControllerAnnotation(title: '商城商品管理')]
|
||||||
class Goods extends AdminController
|
class Goods extends AdminController
|
||||||
@@ -22,8 +24,8 @@ class Goods extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new MallGoods();
|
self::$model = new MallGoods();
|
||||||
$this->assign('cate', (new MallCate())->column('title', 'id'));
|
$this->assign('cate', MallCate::column('title', 'id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[NodeAnnotation(title: '列表', auth: true)]
|
#[NodeAnnotation(title: '列表', auth: true)]
|
||||||
@@ -32,8 +34,8 @@ class Goods extends AdminController
|
|||||||
if ($request->isAjax()) {
|
if ($request->isAjax()) {
|
||||||
if (input('selectFields')) return $this->selectList();
|
if (input('selectFields')) return $this->selectList();
|
||||||
list($page, $limit, $where) = $this->buildTableParams();
|
list($page, $limit, $where) = $this->buildTableParams();
|
||||||
$count = $this->model->where($where)->count();
|
$count = self::$model::where($where)->count();
|
||||||
$list = $this->model->with(['cate'])->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
|
$list = self::$model::with(['cate'])->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
|
||||||
$data = [
|
$data = [
|
||||||
'code' => 0,
|
'code' => 0,
|
||||||
'msg' => '',
|
'msg' => '',
|
||||||
@@ -48,7 +50,7 @@ class Goods extends AdminController
|
|||||||
#[NodeAnnotation(title: '入库', auth: true)]
|
#[NodeAnnotation(title: '入库', auth: true)]
|
||||||
public function stock(Request $request, $id): string
|
public function stock(Request $request, $id): string
|
||||||
{
|
{
|
||||||
$row = $this->model->find($id);
|
$row = self::$model::find($id);
|
||||||
empty($row) && $this->error('数据不存在');
|
empty($row) && $this->error('数据不存在');
|
||||||
if ($request->isPost()) {
|
if ($request->isPost()) {
|
||||||
$post = $request->post();
|
$post = $request->post();
|
||||||
@@ -72,4 +74,62 @@ class Goods extends AdminController
|
|||||||
{
|
{
|
||||||
return '这里演示方法不需要经过登录验证';
|
return '这里演示方法不需要经过登录验证';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[NodeAnnotation(title: 'AI优化', auth: true)]
|
||||||
|
public function aiOptimization(Request $request): void
|
||||||
|
{
|
||||||
|
$message = $request->post('message');
|
||||||
|
if (empty($message)) $this->error('请输入内容');
|
||||||
|
|
||||||
|
// 演示环境下 默认返回的内容
|
||||||
|
if ($this->isDemo) {
|
||||||
|
$content = <<<EOF
|
||||||
|
演示环境中 默认返回的内容
|
||||||
|
|
||||||
|
我来帮你优化这个标题,让它更有吸引力且更符合电商平台的搜索逻辑:
|
||||||
|
|
||||||
|
"商务男士高端定制马克杯 | 办公室精英必备 | 优质陶瓷防烫手柄"
|
||||||
|
|
||||||
|
这个优化后的标题:
|
||||||
|
1. 突出了目标用户群体(商务男士)
|
||||||
|
2. 强调了产品定位(高端定制)
|
||||||
|
3. 点明了使用场景(办公室)
|
||||||
|
4. 添加了材质和功能特点(优质陶瓷、防烫手柄)
|
||||||
|
5. 使用了吸引人的关键词(精英必备)
|
||||||
|
|
||||||
|
这样的标题不仅更具体,也更容易被搜索引擎识别,同时能精准触达目标客户群。您觉得这个版本如何?
|
||||||
|
EOF;
|
||||||
|
$choices = [['message' => [
|
||||||
|
'role' => 'assistant',
|
||||||
|
'content' => $content,
|
||||||
|
]]];
|
||||||
|
$this->success('success', compact('choices'));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = AiChatService::instance()
|
||||||
|
// 当使用推理模型时,可能存在超时的情况,所以需要设置超时时间为 0
|
||||||
|
// ->setTimeLimit(0)
|
||||||
|
// 请替换为您需要的模型类型
|
||||||
|
->setAiType(AiType::QWEN)
|
||||||
|
// 如果需要指定模型的 API 地址,可自行设置
|
||||||
|
// ->setAiUrl('https://xxx.com')
|
||||||
|
// 请替换为您的模型
|
||||||
|
->setAiModel('qwen-plus')
|
||||||
|
// 请替换为您的 API KEY
|
||||||
|
->setAiKey('sk-1234567890')
|
||||||
|
// 此内容会作为系统提示,会影响到回答的内容 当前仅作为测试使用
|
||||||
|
->setSystemContent('你现在是一位资深的海外电商产品经理')
|
||||||
|
->chat($message);
|
||||||
|
$choices = $result['choices'];
|
||||||
|
}catch (\Throwable $exception) {
|
||||||
|
$choices = [['message' => [
|
||||||
|
'role' => 'assistant',
|
||||||
|
'content' => $exception->getMessage(),
|
||||||
|
]]];
|
||||||
|
}
|
||||||
|
$this->success('success', compact('choices'));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -24,8 +24,8 @@ class Admin extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new SystemAdmin();
|
self::$model = SystemAdmin::class;
|
||||||
$this->assign('auth_list', $this->model->getAuthList());
|
$this->assign('auth_list', self::$model::getAuthList());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[NodeAnnotation(title: '列表', auth: true)]
|
#[NodeAnnotation(title: '列表', auth: true)]
|
||||||
@@ -36,11 +36,8 @@ class Admin extends AdminController
|
|||||||
return $this->selectList();
|
return $this->selectList();
|
||||||
}
|
}
|
||||||
list($page, $limit, $where) = $this->buildTableParams();
|
list($page, $limit, $where) = $this->buildTableParams();
|
||||||
$count = $this->model
|
$count = self::$model::where($where)->count();
|
||||||
->where($where)
|
$list = self::$model::withoutField('password')
|
||||||
->count();
|
|
||||||
$list = $this->model
|
|
||||||
->withoutField('password')
|
|
||||||
->where($where)
|
->where($where)
|
||||||
->page($page, $limit)
|
->page($page, $limit)
|
||||||
->order($this->sort)
|
->order($this->sort)
|
||||||
@@ -66,11 +63,11 @@ class Admin extends AdminController
|
|||||||
$rule = [];
|
$rule = [];
|
||||||
$this->validate($post, $rule);
|
$this->validate($post, $rule);
|
||||||
if (empty($post['password'])) $post['password'] = '123456';
|
if (empty($post['password'])) $post['password'] = '123456';
|
||||||
$post['password'] = password($post['password']);
|
$post['password'] = password_hash($post['password'],PASSWORD_DEFAULT);
|
||||||
try {
|
try {
|
||||||
$save = $this->model->save($post);
|
$save = self::$model::create($post);
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
$this->error('保存失败');
|
$this->error('保存失败' . $e->getMessage());
|
||||||
}
|
}
|
||||||
$save ? $this->success('保存成功') : $this->error('保存失败');
|
$save ? $this->success('保存成功') : $this->error('保存失败');
|
||||||
}
|
}
|
||||||
@@ -80,7 +77,7 @@ class Admin extends AdminController
|
|||||||
#[NodeAnnotation(title: '编辑', auth: true)]
|
#[NodeAnnotation(title: '编辑', auth: true)]
|
||||||
public function edit(Request $request, $id = 0): string
|
public function edit(Request $request, $id = 0): string
|
||||||
{
|
{
|
||||||
$row = $this->model->find($id);
|
$row = self::$model::find($id);
|
||||||
empty($row) && $this->error('数据不存在');
|
empty($row) && $this->error('数据不存在');
|
||||||
if ($request->isPost()) {
|
if ($request->isPost()) {
|
||||||
$post = $request->post();
|
$post = $request->post();
|
||||||
@@ -88,18 +85,14 @@ class Admin extends AdminController
|
|||||||
$post['auth_ids'] = implode(',', array_keys($authIds));
|
$post['auth_ids'] = implode(',', array_keys($authIds));
|
||||||
$rule = [];
|
$rule = [];
|
||||||
$this->validate($post, $rule);
|
$this->validate($post, $rule);
|
||||||
if (isset($row['password'])) {
|
|
||||||
unset($row['password']);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
$save = $row->save($post);
|
$save = $row->save($post);
|
||||||
TriggerService::updateMenu($id);
|
TriggerService::updateMenu($id);
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
$this->error('保存失败');
|
$this->error('保存失败' . $e->getMessage());
|
||||||
}
|
}
|
||||||
$save ? $this->success('保存成功') : $this->error('保存失败');
|
$save ? $this->success('保存成功') : $this->error('保存失败');
|
||||||
}
|
}
|
||||||
$row->auth_ids = explode(',', $row->auth_ids ?: '');
|
|
||||||
$this->assign('row', $row);
|
$this->assign('row', $row);
|
||||||
return $this->fetch();
|
return $this->fetch();
|
||||||
}
|
}
|
||||||
@@ -107,7 +100,7 @@ class Admin extends AdminController
|
|||||||
#[NodeAnnotation(title: '设置密码', auth: true)]
|
#[NodeAnnotation(title: '设置密码', auth: true)]
|
||||||
public function password(Request $request, $id): string
|
public function password(Request $request, $id): string
|
||||||
{
|
{
|
||||||
$row = $this->model->find($id);
|
$row = self::$model::find($id);
|
||||||
empty($row) && $this->error('数据不存在');
|
empty($row) && $this->error('数据不存在');
|
||||||
if ($request->isAjax()) {
|
if ($request->isAjax()) {
|
||||||
$post = $request->post();
|
$post = $request->post();
|
||||||
@@ -121,14 +114,13 @@ class Admin extends AdminController
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$save = $row->save([
|
$save = $row->save([
|
||||||
'password' => password($post['password']),
|
'password' => password_hash($post['password'], PASSWORD_DEFAULT),
|
||||||
]);
|
]);
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
$this->error('保存失败');
|
$this->error('保存失败');
|
||||||
}
|
}
|
||||||
$save ? $this->success('保存成功') : $this->error('保存失败');
|
$save ? $this->success('保存成功') : $this->error('保存失败');
|
||||||
}
|
}
|
||||||
$row->auth_ids = explode(',', $row->auth_ids ?: '');
|
|
||||||
$this->assign('row', $row);
|
$this->assign('row', $row);
|
||||||
return $this->fetch();
|
return $this->fetch();
|
||||||
}
|
}
|
||||||
@@ -138,7 +130,7 @@ class Admin extends AdminController
|
|||||||
{
|
{
|
||||||
$this->checkPostRequest();
|
$this->checkPostRequest();
|
||||||
$id = $request->param('id');
|
$id = $request->param('id');
|
||||||
$row = $this->model->whereIn('id', $id)->select();
|
$row = self::$model::whereIn('id', $id)->select();
|
||||||
$row->isEmpty() && $this->error('数据不存在');
|
$row->isEmpty() && $this->error('数据不存在');
|
||||||
$id == AdminConstant::SUPER_ADMIN_ID && $this->error('超级管理员不允许修改');
|
$id == AdminConstant::SUPER_ADMIN_ID && $this->error('超级管理员不允许修改');
|
||||||
if (is_array($id)) {
|
if (is_array($id)) {
|
||||||
@@ -171,7 +163,7 @@ class Admin extends AdminController
|
|||||||
if ($post['id'] == AdminConstant::SUPER_ADMIN_ID && $post['field'] == 'status') {
|
if ($post['id'] == AdminConstant::SUPER_ADMIN_ID && $post['field'] == 'status') {
|
||||||
$this->error('超级管理员状态不允许修改');
|
$this->error('超级管理员状态不允许修改');
|
||||||
}
|
}
|
||||||
$row = $this->model->find($post['id']);
|
$row = self::$model::find($post['id']);
|
||||||
empty($row) && $this->error('数据不存在');
|
empty($row) && $this->error('数据不存在');
|
||||||
try {
|
try {
|
||||||
$row->save([
|
$row->save([
|
||||||
|
|||||||
@@ -23,16 +23,16 @@ class Auth extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new SystemAuth();
|
self::$model = SystemAuth::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[NodeAnnotation(title: '授权', auth: true)]
|
#[NodeAnnotation(title: '授权', auth: true)]
|
||||||
public function authorize(Request $request, $id): string
|
public function authorize(Request $request, $id): string
|
||||||
{
|
{
|
||||||
$row = $this->model->find($id);
|
$row = self::$model::find($id);
|
||||||
empty($row) && $this->error('数据不存在');
|
empty($row) && $this->error('数据不存在');
|
||||||
if ($request->isAjax()) {
|
if ($request->isAjax()) {
|
||||||
$list = $this->model->getAuthorizeNodeListByAdminId($id);
|
$list = self::$model::getAuthorizeNodeListByAdminId($id);
|
||||||
$this->success('获取成功', $list);
|
$this->success('获取成功', $list);
|
||||||
}
|
}
|
||||||
$this->assign('row', $row);
|
$this->assign('row', $row);
|
||||||
@@ -46,7 +46,7 @@ class Auth extends AdminController
|
|||||||
$id = $request->post('id');
|
$id = $request->post('id');
|
||||||
$node = $request->post('node', "[]");
|
$node = $request->post('node', "[]");
|
||||||
$node = json_decode($node, true);
|
$node = json_decode($node, true);
|
||||||
$row = $this->model->find($id);
|
$row = self::$model::find($id);
|
||||||
empty($row) && $this->error('数据不存在');
|
empty($row) && $this->error('数据不存在');
|
||||||
try {
|
try {
|
||||||
$authNode = new SystemAuthNode();
|
$authNode = new SystemAuthNode();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use app\admin\service\annotation\ControllerAnnotation;
|
|||||||
use app\admin\service\annotation\NodeAnnotation;
|
use app\admin\service\annotation\NodeAnnotation;
|
||||||
use app\Request;
|
use app\Request;
|
||||||
use think\App;
|
use think\App;
|
||||||
|
use think\facade\Cache;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
|
|
||||||
#[ControllerAnnotation(title: '系统配置管理')]
|
#[ControllerAnnotation(title: '系统配置管理')]
|
||||||
@@ -18,7 +19,7 @@ class Config extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new SystemConfig();
|
self::$model = SystemConfig::class;
|
||||||
$this->assign('upload_types', config('admin.upload_types'));
|
$this->assign('upload_types', config('admin.upload_types'));
|
||||||
$this->assign('editor_types', config('admin.editor_types'));
|
$this->assign('editor_types', config('admin.editor_types'));
|
||||||
}
|
}
|
||||||
@@ -41,25 +42,26 @@ class Config extends AdminController
|
|||||||
if ($group == 'upload') {
|
if ($group == 'upload') {
|
||||||
$upload_types = config('admin.upload_types');
|
$upload_types = config('admin.upload_types');
|
||||||
// 兼容旧版本
|
// 兼容旧版本
|
||||||
$this->model->where('name', 'upload_allow_type')->update(['value' => implode(',', array_keys($upload_types))]);
|
self::$model::where('name', 'upload_allow_type')->update(['value' => implode(',', array_keys($upload_types))]);
|
||||||
}
|
}
|
||||||
foreach ($post as $key => $val) {
|
foreach ($post as $key => $val) {
|
||||||
if (in_array($key, $notAddFields)) continue;
|
if (in_array($key, $notAddFields)) continue;
|
||||||
if ($this->model->where('name', $key)->count()) {
|
if (self::$model::where('name', $key)->count()) {
|
||||||
$this->model->where('name', $key)->update(['value' => $val,]);
|
self::$model::where('name', $key)->update(['value' => $val,]);
|
||||||
}else {
|
}else {
|
||||||
$this->model->create(
|
self::$model::create(
|
||||||
[
|
[
|
||||||
'name' => $key,
|
'name' => $key,
|
||||||
'value' => $val,
|
'value' => $val,
|
||||||
'group' => $group,
|
'group' => $group,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
if (Cache::has($key)) Cache::set($key, $val);
|
||||||
}
|
}
|
||||||
TriggerService::updateMenu();
|
TriggerService::updateMenu();
|
||||||
TriggerService::updateSysConfig();
|
TriggerService::updateSysConfig();
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
$this->error('保存失败');
|
$this->error('保存失败' . $e->getMessage());
|
||||||
}
|
}
|
||||||
$this->success('保存成功');
|
$this->success('保存成功');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ class CurdGenerate extends AdminController
|
|||||||
$command = $request->post('command', '');
|
$command = $request->post('command', '');
|
||||||
if (empty($command)) $this->error('请输入命令');
|
if (empty($command)) $this->error('请输入命令');
|
||||||
$commandExp = explode(' ', $command);
|
$commandExp = explode(' ', $command);
|
||||||
|
$commandExp = array_values(array_filter($commandExp));
|
||||||
try {
|
try {
|
||||||
|
|
||||||
$output = Console::call('curd', [...$commandExp]);
|
$output = Console::call('curd', [...$commandExp]);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class Log extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new SystemLog();
|
self::$model = SystemLog::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[NodeAnnotation(title: '列表', auth: true)]
|
#[NodeAnnotation(title: '列表', auth: true)]
|
||||||
@@ -34,7 +34,7 @@ class Log extends AdminController
|
|||||||
}
|
}
|
||||||
[$page, $limit, $where, $excludeFields] = $this->buildTableParams(['month']);
|
[$page, $limit, $where, $excludeFields] = $this->buildTableParams(['month']);
|
||||||
$month = !empty($excludeFields['month']) ? date('Ym', strtotime($excludeFields['month'])) : date('Ym');
|
$month = !empty($excludeFields['month']) ? date('Ym', strtotime($excludeFields['month'])) : date('Ym');
|
||||||
$model = $this->model->setMonth($month)->with('admin')->where($where);
|
$model = (new self::$model)->setSuffix("_$month")->with('admin')->where($where);
|
||||||
try {
|
try {
|
||||||
$count = $model->count();
|
$count = $model->count();
|
||||||
$list = $model->page($page, $limit)->order($this->sort)->select();
|
$list = $model->page($page, $limit)->order($this->sort)->select();
|
||||||
@@ -54,13 +54,14 @@ class Log extends AdminController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[NodeAnnotation(title: '导出', auth: true)]
|
#[NodeAnnotation(title: '导出', auth: true)]
|
||||||
public function export(): bool
|
public function export()
|
||||||
{
|
{
|
||||||
if (env('EASYADMIN.IS_DEMO', false)) {
|
if (env('EASYADMIN.IS_DEMO', false)) {
|
||||||
$this->error('演示环境下不允许操作');
|
$this->error('演示环境下不允许操作');
|
||||||
}
|
}
|
||||||
[$page, $limit, $where, $excludeFields] = $this->buildTableParams(['month']);
|
[$page, $limit, $where, $excludeFields] = $this->buildTableParams(['month']);
|
||||||
$tableName = $this->model->getName();
|
$month = !empty($excludeFields['month']) ? date('Ym', strtotime($excludeFields['month'])) : date('Ym');
|
||||||
|
$tableName = (new self::$model)->setSuffix("_$month")->getName();
|
||||||
$tableName = CommonTool::humpToLine(lcfirst($tableName));
|
$tableName = CommonTool::humpToLine(lcfirst($tableName));
|
||||||
$prefix = config('database.connections.mysql.prefix');
|
$prefix = config('database.connections.mysql.prefix');
|
||||||
$dbList = Db::query("show full columns from {$prefix}{$tableName}");
|
$dbList = Db::query("show full columns from {$prefix}{$tableName}");
|
||||||
@@ -71,20 +72,60 @@ class Log extends AdminController
|
|||||||
$header[] = [$comment, $vo['Field']];
|
$header[] = [$comment, $vo['Field']];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$month = !empty($excludeFields['month']) ? date('Ym', strtotime($excludeFields['month'])) : date('Ym');
|
$model = (new self::$model)->setSuffix("_$month")->with('admin')->where($where);
|
||||||
$model = $this->model->setMonth($month)->with('admin')->where($where);
|
|
||||||
try {
|
try {
|
||||||
$list = $model
|
$list = $model
|
||||||
->where($where)
|
->limit(10000)
|
||||||
->limit(100000)
|
|
||||||
->order('id', 'desc')
|
->order('id', 'desc')
|
||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
}catch (PDOException|DbException $exception) {
|
foreach ($list as &$vo) {
|
||||||
|
$vo['content'] = json_encode($vo['content'], JSON_UNESCAPED_UNICODE);
|
||||||
|
$vo['response'] = json_encode($vo['response'], JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
exportExcel($header, $list, '操作日志');
|
||||||
|
}catch (\Throwable $exception) {
|
||||||
$this->error($exception->getMessage());
|
$this->error($exception->getMessage());
|
||||||
}
|
}
|
||||||
$fileName = time();
|
}
|
||||||
return Excel::exportData($list, $header, $fileName, 'xlsx');
|
|
||||||
|
|
||||||
|
#[NodeAnnotation(title: '删除指定日志', auth: true)]
|
||||||
|
public function deleteMonthLog(Request $request)
|
||||||
|
{
|
||||||
|
if (!$request->isAjax()) {
|
||||||
|
return $this->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isDemo) $this->error('演示环境下不允许操作');
|
||||||
|
|
||||||
|
$monthsAgo = $request->param('month/d', 0);
|
||||||
|
if ($monthsAgo < 1) $this->error('月份错误');
|
||||||
|
|
||||||
|
$currentDate = new \DateTime();
|
||||||
|
$currentDate->modify("-$monthsAgo months");
|
||||||
|
|
||||||
|
$dbPrefix = env('DB_PREFIX');
|
||||||
|
$dbLike = "{$dbPrefix}system_log_";
|
||||||
|
$tables = Db::query("SHOW TABLES LIKE '$dbLike%'");
|
||||||
|
$threshold = date('Ym', strtotime("-$monthsAgo month"));
|
||||||
|
$tableNames = [];
|
||||||
|
try {
|
||||||
|
foreach ($tables as $table) {
|
||||||
|
$tableName = current($table);
|
||||||
|
if (!preg_match("/^$dbLike\d{6}$/", $tableName)) continue;
|
||||||
|
$datePart = substr($tableName, -6);
|
||||||
|
$issetTable = Db::query("SHOW TABLES LIKE '$tableName'");
|
||||||
|
if (!$issetTable) continue;
|
||||||
|
if ($datePart - $threshold <= 0) {
|
||||||
|
Db::execute("DROP TABLE `$tableName`");
|
||||||
|
$tableNames[] = $tableName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (PDOException) {
|
||||||
|
}
|
||||||
|
if (empty($tableNames)) $this->error('没有需要删除的表');
|
||||||
|
$this->success('操作成功 - 共删除 ' . count($tableNames) . ' 张表<br/>' . implode('<br>', $tableNames));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOG)]
|
#[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOG)]
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class Menu extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new SystemMenu();
|
self::$model = SystemMenu::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[NodeAnnotation(title: '列表', auth: true)]
|
#[NodeAnnotation(title: '列表', auth: true)]
|
||||||
@@ -35,8 +35,8 @@ class Menu extends AdminController
|
|||||||
if (input('selectFields')) {
|
if (input('selectFields')) {
|
||||||
return $this->selectList();
|
return $this->selectList();
|
||||||
}
|
}
|
||||||
$count = $this->model->count();
|
$count = self::$model::count();
|
||||||
$list = $this->model->order($this->sort)->select()->toArray();
|
$list = self::$model::order($this->sort)->select()->toArray();
|
||||||
$data = [
|
$data = [
|
||||||
'code' => 0,
|
'code' => 0,
|
||||||
'msg' => '',
|
'msg' => '',
|
||||||
@@ -52,7 +52,7 @@ class Menu extends AdminController
|
|||||||
public function add(Request $request): string
|
public function add(Request $request): string
|
||||||
{
|
{
|
||||||
$id = $request->param('id');
|
$id = $request->param('id');
|
||||||
$homeId = $this->model->where(['pid' => MenuConstant::HOME_PID,])->value('id');
|
$homeId = self::$model::where(['pid' => MenuConstant::HOME_PID,])->value('id');
|
||||||
if ($id == $homeId) {
|
if ($id == $homeId) {
|
||||||
$this->error('首页不能添加子菜单');
|
$this->error('首页不能添加子菜单');
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ class Menu extends AdminController
|
|||||||
];
|
];
|
||||||
$this->validate($post, $rule);
|
$this->validate($post, $rule);
|
||||||
try {
|
try {
|
||||||
$save = $this->model->save($post);
|
$save = self::$model::create($post);
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
$this->error('保存失败');
|
$this->error('保存失败');
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ class Menu extends AdminController
|
|||||||
$this->error('保存失败');
|
$this->error('保存失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$pidMenuList = $this->model->getPidMenuList();
|
$pidMenuList = self::$model::getPidMenuList();
|
||||||
$this->assign('id', $id);
|
$this->assign('id', $id);
|
||||||
$this->assign('pidMenuList', $pidMenuList);
|
$this->assign('pidMenuList', $pidMenuList);
|
||||||
return $this->fetch();
|
return $this->fetch();
|
||||||
@@ -85,7 +85,7 @@ class Menu extends AdminController
|
|||||||
#[NodeAnnotation(title: '编辑', auth: true)]
|
#[NodeAnnotation(title: '编辑', auth: true)]
|
||||||
public function edit(Request $request, $id = 0): string
|
public function edit(Request $request, $id = 0): string
|
||||||
{
|
{
|
||||||
$row = $this->model->find($id);
|
$row = self::$model::find($id);
|
||||||
empty($row) && $this->error('数据不存在');
|
empty($row) && $this->error('数据不存在');
|
||||||
if ($request->isPost()) {
|
if ($request->isPost()) {
|
||||||
$post = $request->post();
|
$post = $request->post();
|
||||||
@@ -108,7 +108,7 @@ class Menu extends AdminController
|
|||||||
$this->error('保存失败');
|
$this->error('保存失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$pidMenuList = $this->model->getPidMenuList();
|
$pidMenuList = self::$model::getPidMenuList();
|
||||||
$this->assign([
|
$this->assign([
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'pidMenuList' => $pidMenuList,
|
'pidMenuList' => $pidMenuList,
|
||||||
@@ -122,7 +122,7 @@ class Menu extends AdminController
|
|||||||
{
|
{
|
||||||
$this->checkPostRequest();
|
$this->checkPostRequest();
|
||||||
$id = $request->param('id');
|
$id = $request->param('id');
|
||||||
$row = $this->model->whereIn('id', $id)->select();
|
$row = self::$model::whereIn('id', $id)->select();
|
||||||
empty($row) && $this->error('数据不存在');
|
empty($row) && $this->error('数据不存在');
|
||||||
try {
|
try {
|
||||||
$save = $row->delete();
|
$save = $row->delete();
|
||||||
@@ -148,17 +148,16 @@ class Menu extends AdminController
|
|||||||
'value|值' => 'require',
|
'value|值' => 'require',
|
||||||
];
|
];
|
||||||
$this->validate($post, $rule);
|
$this->validate($post, $rule);
|
||||||
$row = $this->model->find($post['id']);
|
$row = self::$model::find($post['id']);
|
||||||
if (!$row) {
|
if (!$row) {
|
||||||
$this->error('数据不存在');
|
$this->error('数据不存在');
|
||||||
}
|
}
|
||||||
if (!in_array($post['field'], $this->allowModifyFields)) {
|
if (!in_array($post['field'], $this->allowModifyFields)) {
|
||||||
$this->error('该字段不允许修改:' . $post['field']);
|
$this->error('该字段不允许修改:' . $post['field']);
|
||||||
}
|
}
|
||||||
$homeId = $this->model
|
$homeId = self::$model::where([
|
||||||
->where([
|
'pid' => MenuConstant::HOME_PID,
|
||||||
'pid' => MenuConstant::HOME_PID,
|
])
|
||||||
])
|
|
||||||
->value('id');
|
->value('id');
|
||||||
if ($post['id'] == $homeId && $post['field'] == 'status') {
|
if ($post['id'] == $homeId && $post['field'] == 'status') {
|
||||||
$this->error('首页状态不允许关闭');
|
$this->error('首页状态不允许关闭');
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ use app\admin\service\annotation\NodeAnnotation;
|
|||||||
use app\admin\service\NodeService;
|
use app\admin\service\NodeService;
|
||||||
use app\Request;
|
use app\Request;
|
||||||
use think\App;
|
use think\App;
|
||||||
|
use think\db\exception\DataNotFoundException;
|
||||||
|
use think\db\exception\DbException;
|
||||||
|
use think\db\exception\ModelNotFoundException;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
|
|
||||||
#[ControllerAnnotation(title: '系统节点管理')]
|
#[ControllerAnnotation(title: '系统节点管理')]
|
||||||
@@ -19,7 +22,7 @@ class Node extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new SystemNode();
|
self::$model = SystemNode::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[NodeAnnotation(title: '列表', auth: true)]
|
#[NodeAnnotation(title: '列表', auth: true)]
|
||||||
@@ -29,10 +32,8 @@ class Node extends AdminController
|
|||||||
if (input('selectFields')) {
|
if (input('selectFields')) {
|
||||||
return $this->selectList();
|
return $this->selectList();
|
||||||
}
|
}
|
||||||
$count = $this->model
|
$count = self::$model::count();
|
||||||
->count();
|
$list = self::$model::getNodeTreeList();
|
||||||
$list = $this->model
|
|
||||||
->getNodeTreeList();
|
|
||||||
$data = [
|
$data = [
|
||||||
'code' => 0,
|
'code' => 0,
|
||||||
'msg' => '',
|
'msg' => '',
|
||||||
@@ -51,15 +52,14 @@ class Node extends AdminController
|
|||||||
$this->checkPostRequest();
|
$this->checkPostRequest();
|
||||||
$nodeList = (new NodeService())->getNodeList();
|
$nodeList = (new NodeService())->getNodeList();
|
||||||
empty($nodeList) && $this->error('暂无需要更新的系统节点');
|
empty($nodeList) && $this->error('暂无需要更新的系统节点');
|
||||||
$model = new SystemNode();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($force == 1) {
|
if ($force == 1) {
|
||||||
$updateNodeList = $model->whereIn('node', array_column($nodeList, 'node'))->select();
|
$updateNodeList = self::$model::whereIn('node', array_column($nodeList, 'node'))->select();
|
||||||
$formatNodeList = array_format_key($nodeList, 'node');
|
$formatNodeList = array_format_key($nodeList, 'node');
|
||||||
foreach ($updateNodeList as $vo) {
|
foreach ($updateNodeList as $vo) {
|
||||||
isset($formatNodeList[$vo['node']])
|
isset($formatNodeList[$vo['node']])
|
||||||
&& $model->where('id', $vo['id'])->update(
|
&& self::$model::where('id', $vo['id'])->update(
|
||||||
[
|
[
|
||||||
'title' => $formatNodeList[$vo['node']]['title'],
|
'title' => $formatNodeList[$vo['node']]['title'],
|
||||||
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
|
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
|
||||||
@@ -67,7 +67,7 @@ class Node extends AdminController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$existNodeList = $model->field('node,title,type,is_auth')->select();
|
$existNodeList = self::$model::field('node,title,type,is_auth')->select();
|
||||||
foreach ($nodeList as $key => $vo) {
|
foreach ($nodeList as $key => $vo) {
|
||||||
foreach ($existNodeList as $v) {
|
foreach ($existNodeList as $v) {
|
||||||
if ($vo['node'] == $v->node) {
|
if ($vo['node'] == $v->node) {
|
||||||
@@ -76,8 +76,10 @@ class Node extends AdminController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$model->saveAll($nodeList);
|
if (!empty($nodeList)) {
|
||||||
TriggerService::updateNode();
|
(new self::$model)->saveAll($nodeList);
|
||||||
|
TriggerService::updateNode();
|
||||||
|
}
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
$this->error('节点更新失败');
|
$this->error('节点更新失败');
|
||||||
}
|
}
|
||||||
@@ -89,12 +91,11 @@ class Node extends AdminController
|
|||||||
{
|
{
|
||||||
$this->checkPostRequest();
|
$this->checkPostRequest();
|
||||||
$nodeList = (new NodeService())->getNodeList();
|
$nodeList = (new NodeService())->getNodeList();
|
||||||
$model = new SystemNode();
|
|
||||||
try {
|
try {
|
||||||
$existNodeList = $model->field('id,node,title,type,is_auth')->select()->toArray();
|
$existNodeList = self::$model::field('id,node,title,type,is_auth')->select()->toArray();
|
||||||
$formatNodeList = array_format_key($nodeList, 'node');
|
$formatNodeList = array_format_key($nodeList, 'node');
|
||||||
foreach ($existNodeList as $vo) {
|
foreach ($existNodeList as $vo) {
|
||||||
!isset($formatNodeList[$vo['node']]) && $model->where('id', $vo['id'])->delete();
|
!isset($formatNodeList[$vo['node']]) && self::$model::where('id', $vo['id'])->delete();
|
||||||
}
|
}
|
||||||
TriggerService::updateNode();
|
TriggerService::updateNode();
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class Quick extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new SystemQuick();
|
self::$model = SystemQuick::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ class Uploadfile extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new SystemUploadfile();
|
self::$model = SystemUploadfile::class;
|
||||||
$this->assign('upload_types', config('admin.upload_types'));
|
$this->assign('upload_types', config('admin.upload_types'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
0
app/admin/entity/.keep
Normal file
0
app/admin/entity/.keep
Normal file
12
app/admin/entity/Test.php
Normal file
12
app/admin/entity/Test.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\admin\entity;
|
||||||
|
|
||||||
|
use app\common\entity\BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ThinkORM 4.0 实体模型案例
|
||||||
|
* 可与 Model 并存 或者 单独使用
|
||||||
|
* @package app\admin\entity
|
||||||
|
*/
|
||||||
|
class Test extends BaseEntity {}
|
||||||
@@ -35,7 +35,7 @@ class CheckAuth
|
|||||||
!$check && $this->error('无权限访问');
|
!$check && $this->error('无权限访问');
|
||||||
// 判断是否为演示环境
|
// 判断是否为演示环境
|
||||||
if (env('EASYADMIN.IS_DEMO', false) && $request->isPost()) {
|
if (env('EASYADMIN.IS_DEMO', false) && $request->isPost()) {
|
||||||
if (!in_array($currentNode, ['system.log/record', ''])) $this->error('演示环境下不允许修改');
|
if (!in_array($currentNode, ['system.log/record', 'mall.goods/aiOptimization'])) $this->error('演示环境下不允许修改');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
|||||||
@@ -25,26 +25,31 @@ class CheckLogin
|
|||||||
$controllerClass = 'app\\admin\\controller\\' . $controller;
|
$controllerClass = 'app\\admin\\controller\\' . $controller;
|
||||||
$classObj = new ReflectionClass($controllerClass);
|
$classObj = new ReflectionClass($controllerClass);
|
||||||
$properties = $classObj->getDefaultProperties();
|
$properties = $classObj->getDefaultProperties();
|
||||||
$ignoreAuth = $properties['ignoreAuth'] ?? false;
|
// 整个控制器是否忽略登录
|
||||||
$adminUserInfo = session('admin');
|
$ignoreLogin = $properties['ignoreLogin'] ?? false;
|
||||||
if (!$ignoreAuth) {
|
$adminUserInfo = session('admin');
|
||||||
|
if (!$ignoreLogin) {
|
||||||
$noNeedCheck = $properties['noNeedCheck'] ?? [];
|
$noNeedCheck = $properties['noNeedCheck'] ?? [];
|
||||||
if (in_array($action, $noNeedCheck)) {
|
if (in_array($action, $noNeedCheck)) {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
$reflectionMethod = new \ReflectionMethod($controllerClass, $action);
|
try {
|
||||||
$attributes = $reflectionMethod->getAttributes(MiddlewareAnnotation::class);
|
$reflectionMethod = new \ReflectionMethod($controllerClass, $action);
|
||||||
foreach ($attributes as $attribute) {
|
$attributes = $reflectionMethod->getAttributes(MiddlewareAnnotation::class);
|
||||||
$annotation = $attribute->newInstance();
|
foreach ($attributes as $attribute) {
|
||||||
$_ignore = (array)$annotation->ignore;
|
$annotation = $attribute->newInstance();
|
||||||
if (in_array('LOGIN', (array)$_ignore)) return $next($request);
|
$_ignore = (array)$annotation->ignore;
|
||||||
|
// 控制器中的某个方法忽略登录
|
||||||
|
if (in_array('LOGIN', $_ignore)) return $next($request);
|
||||||
|
}
|
||||||
|
}catch (\Throwable) {
|
||||||
}
|
}
|
||||||
if (empty($adminUserInfo)) {
|
if (empty($adminUserInfo)) {
|
||||||
return redirect(__url('login/index'));
|
return redirect(__url('login/index'));
|
||||||
}
|
}
|
||||||
// 判断是否登录过期
|
// 判断是否登录过期
|
||||||
$expireTime = $adminUserInfo['expire_time'];
|
$expireTime = $adminUserInfo['expire_time'];
|
||||||
if ($expireTime !== true && time() > $expireTime) {
|
if ($expireTime !== 0 && time() > $expireTime) {
|
||||||
session('admin', null);
|
session('admin', null);
|
||||||
$this->error('登录已过期,请重新登录', [], __url(env('EASYADMIN.ADMIN') . '/login/index'));
|
$this->error('登录已过期,请重新登录', [], __url(env('EASYADMIN.ADMIN') . '/login/index'));
|
||||||
}
|
}
|
||||||
|
|||||||
45
app/admin/middleware/RateLimiting.php
Normal file
45
app/admin/middleware/RateLimiting.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\admin\middleware;
|
||||||
|
|
||||||
|
use app\common\traits\JumpTrait;
|
||||||
|
use app\Request;
|
||||||
|
use Closure;
|
||||||
|
use Wolfcode\RateLimiting\Bootstrap;
|
||||||
|
|
||||||
|
class RateLimiting
|
||||||
|
{
|
||||||
|
use JumpTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用限流器需要开启Redis
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): mixed
|
||||||
|
{
|
||||||
|
// 是否启用限流器
|
||||||
|
if (!env('RATE_LIMITING_STATUS', false)) return $next($request);
|
||||||
|
if ($request->method() == 'GET') return $next($request);
|
||||||
|
$controller = $request->controller();
|
||||||
|
$module = app('http')->getName();
|
||||||
|
$appNamespace = config('app.app_namespace');
|
||||||
|
$controllerClass = "app\\{$module}\\controller\\{$controller}{$appNamespace}";
|
||||||
|
$controllerClass = str_replace('.', '\\', $controllerClass);
|
||||||
|
$action = $request->action();
|
||||||
|
try {
|
||||||
|
Bootstrap::init($controllerClass, $action, [
|
||||||
|
# Redis 相关配置
|
||||||
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
|
'port' => (int)env('REDIS_PORT', 6379),
|
||||||
|
'password' => env('REDIS_PASSWORD', ''),
|
||||||
|
'prefix' => env('REDIS_PREFIX', ''),
|
||||||
|
'database' => (int)env('REDIS_DATABASE', 0),
|
||||||
|
]);
|
||||||
|
}catch (\Throwable $exception) {
|
||||||
|
$this->error($exception->getMessage());
|
||||||
|
}
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,11 @@ use app\common\model\TimeModel;
|
|||||||
class MallCate extends TimeModel
|
class MallCate extends TimeModel
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $deleteTime = 'delete_time';
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'deleteTime' => 'delete_time',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,10 +8,12 @@ use think\model\relation\HasOne;
|
|||||||
|
|
||||||
class MallGoods extends TimeModel
|
class MallGoods extends TimeModel
|
||||||
{
|
{
|
||||||
|
protected function getOptions(): array
|
||||||
protected $table = "";
|
{
|
||||||
|
return [
|
||||||
protected $deleteTime = 'delete_time';
|
'deleteTime' => 'delete_time',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
// * +++++++++++++++++++++++++++
|
// * +++++++++++++++++++++++++++
|
||||||
// | 以下两种写法适用于 with 关联
|
// | 以下两种写法适用于 with 关联
|
||||||
|
|||||||
@@ -8,7 +8,12 @@ use app\common\model\TimeModel;
|
|||||||
class SystemAdmin extends TimeModel
|
class SystemAdmin extends TimeModel
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $deleteTime = 'delete_time';
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'deleteTime' => 'delete_time',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public array $notes = [
|
public array $notes = [
|
||||||
'login_type' => [
|
'login_type' => [
|
||||||
@@ -17,12 +22,15 @@ class SystemAdmin extends TimeModel
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
public function getAuthList()
|
public static function getAuthIdsAttr($value): array
|
||||||
{
|
{
|
||||||
$list = (new SystemAuth())
|
if (!$value) return [];
|
||||||
->where('status', 1)
|
return explode(',', $value);
|
||||||
->column('title', 'id');
|
}
|
||||||
return $list;
|
|
||||||
|
public static function getAuthList(): array
|
||||||
|
{
|
||||||
|
return SystemAuth::where('status', 1)->column('title', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,44 +3,52 @@
|
|||||||
namespace app\admin\model;
|
namespace app\admin\model;
|
||||||
|
|
||||||
use app\common\model\TimeModel;
|
use app\common\model\TimeModel;
|
||||||
|
use think\db\exception\DataNotFoundException;
|
||||||
|
use think\db\exception\DbException;
|
||||||
|
use think\db\exception\ModelNotFoundException;
|
||||||
|
|
||||||
class SystemAuth extends TimeModel
|
class SystemAuth extends TimeModel
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $deleteTime = 'delete_time';
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'deleteTime' => 'delete_time',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据角色ID获取授权节点
|
* 根据角色ID获取授权节点
|
||||||
* @param $authId
|
* @param $authId
|
||||||
* @return array
|
* @return array
|
||||||
* @throws \think\db\exception\DataNotFoundException
|
* @throws DataNotFoundException
|
||||||
* @throws \think\db\exception\DbException
|
* @throws DbException
|
||||||
* @throws \think\db\exception\ModelNotFoundException
|
* @throws ModelNotFoundException
|
||||||
*/
|
*/
|
||||||
public function getAuthorizeNodeListByAdminId($authId)
|
public static function getAuthorizeNodeListByAdminId($authId): array
|
||||||
{
|
{
|
||||||
$checkNodeList = (new SystemAuthNode())
|
$checkNodeList = (new SystemAuthNode())
|
||||||
->where('auth_id', $authId)
|
->where('auth_id', $authId)
|
||||||
->column('node_id');
|
->column('node_id');
|
||||||
$systemNode = new SystemNode();
|
$systemNode = new SystemNode();
|
||||||
$nodelList = $systemNode
|
$nodeList = $systemNode
|
||||||
->where('is_auth', 1)
|
->where('is_auth', 1)
|
||||||
->field('id,node,title,type,is_auth')
|
->field('id,node,title,type,is_auth')
|
||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
$newNodeList = [];
|
$newNodeList = [];
|
||||||
foreach ($nodelList as $vo) {
|
foreach ($nodeList as $vo) {
|
||||||
if ($vo['type'] == 1) {
|
if ($vo['type'] == 1) {
|
||||||
$vo = array_merge($vo, ['field' => 'node', 'spread' => true]);
|
$vo = array_merge($vo, ['field' => 'node', 'spread' => true]);
|
||||||
$vo['checked'] = false;
|
$vo['checked'] = false;
|
||||||
$vo['title'] = "{$vo['title']}【{$vo['node']}】";
|
$vo['title'] = "{$vo['title']}【{$vo['node']}】";
|
||||||
$children = [];
|
$children = [];
|
||||||
foreach ($nodelList as $v) {
|
foreach ($nodeList as $v) {
|
||||||
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
|
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
|
||||||
$v = array_merge($v, ['field' => 'node', 'spread' => true]);
|
$v = array_merge($v, ['field' => 'node', 'spread' => true]);
|
||||||
$v['checked'] = in_array($v['id'], $checkNodeList) ? true : false;
|
$v['checked'] = in_array($v['id'], $checkNodeList) ? true : false;
|
||||||
$v['title'] = "{$v['title']}【{$v['node']}】";
|
$v['title'] = "{$v['title']}【{$v['node']}】";
|
||||||
$children[] = $v;
|
$children[] = $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
!empty($children) && $vo['children'] = $children;
|
!empty($children) && $vo['children'] = $children;
|
||||||
|
|||||||
@@ -4,24 +4,23 @@ namespace app\admin\model;
|
|||||||
|
|
||||||
use app\admin\service\SystemLogService;
|
use app\admin\service\SystemLogService;
|
||||||
use app\common\model\TimeModel;
|
use app\common\model\TimeModel;
|
||||||
|
use think\model\relation\BelongsTo;
|
||||||
|
|
||||||
class SystemLog extends TimeModel
|
class SystemLog extends TimeModel
|
||||||
{
|
{
|
||||||
|
|
||||||
public function __construct(array $data = [])
|
protected array $type = [
|
||||||
{
|
'content' => 'json',
|
||||||
parent::__construct($data);
|
'response' => 'json',
|
||||||
$this->name = 'system_log_' . date('Ym');
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public function setMonth($month)
|
protected function init(): void
|
||||||
{
|
{
|
||||||
SystemLogService::instance()->detectTable();
|
SystemLogService::instance()->detectTable();
|
||||||
$this->name = 'system_log_' . $month;
|
|
||||||
return $this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function admin()
|
|
||||||
|
public function admin(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo('app\admin\model\SystemAdmin', 'admin_id', 'id');
|
return $this->belongsTo('app\admin\model\SystemAdmin', 'admin_id', 'id');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,31 +4,41 @@ namespace app\admin\model;
|
|||||||
|
|
||||||
use app\common\constants\MenuConstant;
|
use app\common\constants\MenuConstant;
|
||||||
use app\common\model\TimeModel;
|
use app\common\model\TimeModel;
|
||||||
|
use think\db\exception\DataNotFoundException;
|
||||||
|
use think\db\exception\DbException;
|
||||||
|
use think\db\exception\ModelNotFoundException;
|
||||||
|
|
||||||
class SystemMenu extends TimeModel
|
class SystemMenu extends TimeModel
|
||||||
{
|
{
|
||||||
|
protected function getOptions(): array
|
||||||
protected $deleteTime = 'delete_time';
|
|
||||||
|
|
||||||
public function getPidMenuList()
|
|
||||||
{
|
{
|
||||||
$list = $this->field('id,pid,title')
|
return [
|
||||||
->where([
|
'deleteTime' => 'delete_time',
|
||||||
['pid', '<>', MenuConstant::HOME_PID],
|
];
|
||||||
['status', '=', 1],
|
}
|
||||||
])
|
|
||||||
->select()
|
|
||||||
->toArray();
|
/**
|
||||||
$pidMenuList = $this->buildPidMenu(0, $list);
|
* @throws ModelNotFoundException
|
||||||
$pidMenuList = array_merge([[
|
* @throws DbException
|
||||||
|
* @throws DataNotFoundException
|
||||||
|
*/
|
||||||
|
public static function getPidMenuList(): array
|
||||||
|
{
|
||||||
|
$list = self::field('id,pid,title')->where([
|
||||||
|
['pid', '<>', MenuConstant::HOME_PID],
|
||||||
|
['status', '=', 1],
|
||||||
|
])->select()->toArray();
|
||||||
|
|
||||||
|
$pidMenuList = self::buildPidMenu(0, $list);
|
||||||
|
return array_merge([[
|
||||||
'id' => 0,
|
'id' => 0,
|
||||||
'pid' => 0,
|
'pid' => 0,
|
||||||
'title' => '顶级菜单',
|
'title' => '顶级菜单',
|
||||||
]], $pidMenuList);
|
]], $pidMenuList);
|
||||||
return $pidMenuList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildPidMenu($pid, $list, $level = 0)
|
protected static function buildPidMenu($pid, $list, $level = 0): array
|
||||||
{
|
{
|
||||||
$newList = [];
|
$newList = [];
|
||||||
foreach ($list as $vo) {
|
foreach ($list as $vo) {
|
||||||
@@ -47,7 +57,7 @@ class SystemMenu extends TimeModel
|
|||||||
$vo['title'] = $markString . $vo['title'];
|
$vo['title'] = $markString . $vo['title'];
|
||||||
}
|
}
|
||||||
$newList[] = $vo;
|
$newList[] = $vo;
|
||||||
$childList = $this->buildPidMenu($vo['id'], $list, $level);
|
$childList = self::buildPidMenu($vo['id'], $list, $level);
|
||||||
!empty($childList) && $newList = array_merge($newList, $childList);
|
!empty($childList) && $newList = array_merge($newList, $childList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,22 +7,21 @@ use app\common\model\TimeModel;
|
|||||||
class SystemNode extends TimeModel
|
class SystemNode extends TimeModel
|
||||||
{
|
{
|
||||||
|
|
||||||
public function getNodeTreeList()
|
public static function getNodeTreeList(): array
|
||||||
{
|
{
|
||||||
$list = $this->select()->toArray();
|
$list = self::select()->toArray();
|
||||||
$list = $this->buildNodeTree($list);
|
return self::buildNodeTree($list);
|
||||||
return $list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildNodeTree($list)
|
protected static function buildNodeTree($list): array
|
||||||
{
|
{
|
||||||
$newList = [];
|
$newList = [];
|
||||||
$repeatString = " ";
|
$repeatString = " ";
|
||||||
foreach ($list as $vo) {
|
foreach ($list as $vo) {
|
||||||
if ($vo['type'] == 1) {
|
if ($vo['type'] == 1) {
|
||||||
$newList[] = $vo;
|
$newList[] = $vo;
|
||||||
foreach ($list as $v) {
|
foreach ($list as $v) {
|
||||||
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
|
if ($v['type'] == 2 && str_contains($v['node'], $vo['node'] . '/')) {
|
||||||
$v['node'] = "{$repeatString}├{$repeatString}" . $v['node'];
|
$v['node'] = "{$repeatString}├{$repeatString}" . $v['node'];
|
||||||
$newList[] = $v;
|
$newList[] = $v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ use app\common\model\TimeModel;
|
|||||||
class SystemQuick extends TimeModel
|
class SystemQuick extends TimeModel
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $deleteTime = 'delete_time';
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'deleteTime' => 'delete_time',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -9,11 +9,10 @@ class ConfigService
|
|||||||
|
|
||||||
public static function getVersion()
|
public static function getVersion()
|
||||||
{
|
{
|
||||||
$version = cache('version');
|
$version = cache('site_version');
|
||||||
if (empty($version)) {
|
if (empty($version)) {
|
||||||
$version = sysConfig('site', 'site_version');
|
$version = sysConfig('site', 'site_version');
|
||||||
cache('site_version', $version);
|
cache('site_version', $version);
|
||||||
Cache::set('version', $version, 3600);
|
|
||||||
}
|
}
|
||||||
return $version;
|
return $version;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,6 +355,7 @@ class BuildCurd
|
|||||||
if (!empty($bindSelectField) && !in_array($bindSelectField, array_column($columns, 'Field'))) {
|
if (!empty($bindSelectField) && !in_array($bindSelectField, array_column($columns, 'Field'))) {
|
||||||
throw new TableException("关联表{$relationTable}不存在该字段: {$bindSelectField}");
|
throw new TableException("关联表{$relationTable}不存在该字段: {$bindSelectField}");
|
||||||
}
|
}
|
||||||
|
$onlyFields = [];
|
||||||
foreach ($columns as $vo) {
|
foreach ($columns as $vo) {
|
||||||
if (empty($primaryKey) && $vo['Key'] == 'PRI') {
|
if (empty($primaryKey) && $vo['Key'] == 'PRI') {
|
||||||
$primaryKey = $vo['Field'];
|
$primaryKey = $vo['Field'];
|
||||||
@@ -362,6 +363,7 @@ class BuildCurd
|
|||||||
if (!empty($onlyShowFields) && !in_array($vo['Field'], $onlyShowFields)) {
|
if (!empty($onlyShowFields) && !in_array($vo['Field'], $onlyShowFields)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!empty($onlyShowFields)) $onlyFields[] = $vo['Field'];
|
||||||
$colum = [
|
$colum = [
|
||||||
'type' => $vo['Type'],
|
'type' => $vo['Type'],
|
||||||
'comment' => $vo['Comment'],
|
'comment' => $vo['Comment'],
|
||||||
@@ -388,6 +390,7 @@ class BuildCurd
|
|||||||
'bindSelectField' => $bindSelectField,
|
'bindSelectField' => $bindSelectField,
|
||||||
'delete' => $delete,
|
'delete' => $delete,
|
||||||
'tableColumns' => $formatColumns,
|
'tableColumns' => $formatColumns,
|
||||||
|
'onlyFields' => $onlyFields,
|
||||||
];
|
];
|
||||||
if (!empty($bindSelectField)) {
|
if (!empty($bindSelectField)) {
|
||||||
$relationArray = explode('\\', $modelFilename);
|
$relationArray = explode('\\', $modelFilename);
|
||||||
@@ -1038,9 +1041,9 @@ class BuildCurd
|
|||||||
$relationCode = '';
|
$relationCode = '';
|
||||||
foreach ($this->relationArray as $key => $val) {
|
foreach ($this->relationArray as $key => $val) {
|
||||||
$relation = CommonTool::lineToHump($key);
|
$relation = CommonTool::lineToHump($key);
|
||||||
$relationCode = "->withJoin('{$relation}', 'LEFT')\r";
|
$relationCode = "withJoin('{$relation}', 'LEFT')";
|
||||||
if (!empty($val['bindSelectField']) && !empty($val['primaryKey'])) {
|
if (!empty($val['bindSelectField']) && !empty($val['primaryKey'])) {
|
||||||
$constructRelation = '$notes["' . lcfirst($val['modelFilename']) . ucfirst($val['bindSelectField']) . '"] = \app\admin\model\\' . $val['modelFilename'] . '::column("' . $val['bindSelectField'] . '", "' . $val['primaryKey'] . '");';
|
$constructRelation = '$notes["' . lcfirst($val['foreignKey']) . '"] = \app\admin\model\\' . $val['modelFilename'] . '::column("' . $val['bindSelectField'] . '", "' . $val['primaryKey'] . '");';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$controllerIndexMethod = CommonTool::replaceTemplate(
|
$controllerIndexMethod = CommonTool::replaceTemplate(
|
||||||
@@ -1092,16 +1095,17 @@ class BuildCurd
|
|||||||
$relationList = '';
|
$relationList = '';
|
||||||
if (!empty($this->relationArray)) {
|
if (!empty($this->relationArray)) {
|
||||||
foreach ($this->relationArray as $key => $val) {
|
foreach ($this->relationArray as $key => $val) {
|
||||||
$relation = CommonTool::lineToHump($key);
|
$relation = CommonTool::lineToHump($key);
|
||||||
// $relationCode = CommonTool::replaceTemplate(
|
$relationCode = CommonTool::replaceTemplate(
|
||||||
// $this->getTemplate("model{$this->DS}relation"),
|
$this->getTemplate("model{$this->DS}relation"),
|
||||||
// [
|
[
|
||||||
// 'relationMethod' => $relation,
|
'relationMethod' => $relation,
|
||||||
// 'relationModel' => "\app\admin\model\\{$val['modelFilename']}",
|
'relationModel' => "{$val['modelFilename']}::class",
|
||||||
// 'foreignKey' => $val['foreignKey'],
|
'foreignKey' => $val['foreignKey'],
|
||||||
// 'primaryKey' => $val['primaryKey'],
|
'primaryKey' => $val['primaryKey'],
|
||||||
// ]);
|
'relationFields' => empty($val['onlyFields']) ? "" : "->field('{$val['primaryKey']}," . implode(',', $val['onlyFields']) . "')",
|
||||||
// $relationList .= $relationCode;
|
]);
|
||||||
|
$relationList .= $relationCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1213,6 +1217,7 @@ class BuildCurd
|
|||||||
} elseif ($val['formType'] == 'images') {
|
} elseif ($val['formType'] == 'images') {
|
||||||
$templateFile = "view{$this->DS}module{$this->DS}images";
|
$templateFile = "view{$this->DS}module{$this->DS}images";
|
||||||
$define = $val['define'] ?? '|';
|
$define = $val['define'] ?? '|';
|
||||||
|
if (strlen($define) > 5) $define = '|';
|
||||||
} elseif ($val['formType'] == 'file') {
|
} elseif ($val['formType'] == 'file') {
|
||||||
$templateFile = "view{$this->DS}module{$this->DS}file";
|
$templateFile = "view{$this->DS}module{$this->DS}file";
|
||||||
} elseif ($val['formType'] == 'files') {
|
} elseif ($val['formType'] == 'files') {
|
||||||
@@ -1230,17 +1235,17 @@ class BuildCurd
|
|||||||
} elseif ($val['formType'] == 'radio') {
|
} elseif ($val['formType'] == 'radio') {
|
||||||
$templateFile = "view{$this->DS}module{$this->DS}radio";
|
$templateFile = "view{$this->DS}module{$this->DS}radio";
|
||||||
if (!empty($val['define'])) {
|
if (!empty($val['define'])) {
|
||||||
$define = $this->buildRadioView($field, '{in name="k" value="' . $val['default'] . '"}checked=""{/in}');
|
$define = $this->buildRadioView($field, '');
|
||||||
}
|
}
|
||||||
} elseif ($val['formType'] == 'checkbox') {
|
} elseif ($val['formType'] == 'checkbox') {
|
||||||
$templateFile = "view{$this->DS}module{$this->DS}checkbox";
|
$templateFile = "view{$this->DS}module{$this->DS}checkbox";
|
||||||
if (!empty($val['define'])) {
|
if (!empty($val['define'])) {
|
||||||
$define = $this->buildCheckboxView($field, '{in name="k" value="' . $val['default'] . '"}checked=""{/in}');
|
$define = $this->buildCheckboxView($field, '');
|
||||||
}
|
}
|
||||||
} elseif ($val['formType'] == 'select') {
|
} elseif ($val['formType'] == 'select') {
|
||||||
$templateFile = "view{$this->DS}module{$this->DS}select";
|
$templateFile = "view{$this->DS}module{$this->DS}select";
|
||||||
if (isset($val['bindRelation'])) {
|
if (isset($val['bindRelation'])) {
|
||||||
$define = $this->buildOptionView($val['bindRelation']);
|
$define = $this->buildOptionView($field);
|
||||||
} elseif (!empty($val['define'])) {
|
} elseif (!empty($val['define'])) {
|
||||||
$define = $this->buildOptionView($field);
|
$define = $this->buildOptionView($field);
|
||||||
}
|
}
|
||||||
@@ -1304,19 +1309,19 @@ class BuildCurd
|
|||||||
} elseif ($val['formType'] == 'radio') {
|
} elseif ($val['formType'] == 'radio') {
|
||||||
$templateFile = "view{$this->DS}module{$this->DS}radio";
|
$templateFile = "view{$this->DS}module{$this->DS}radio";
|
||||||
if (!empty($val['define'])) {
|
if (!empty($val['define'])) {
|
||||||
$define = $this->buildRadioView($field, '{in name="k" value="$row.' . $field . '"}checked=""{/in}');
|
$define = $this->buildRadioView($field, '{if in_array($k, $row.' . $field . ')}checked{/if}');
|
||||||
}
|
}
|
||||||
} elseif ($val['formType'] == 'checkbox') {
|
} elseif ($val['formType'] == 'checkbox') {
|
||||||
$templateFile = "view{$this->DS}module{$this->DS}checkbox";
|
$templateFile = "view{$this->DS}module{$this->DS}checkbox";
|
||||||
if (!empty($val['define'])) {
|
if (!empty($val['define'])) {
|
||||||
$define = $this->buildCheckboxView($field, '{in name="k" value="$row.' . $field . '"}checked=""{/in}');
|
$define = $this->buildCheckboxView($field, '{if in_array($k, $row.' . $field . ')}checked{/if}');
|
||||||
}
|
}
|
||||||
} elseif ($val['formType'] == 'select') {
|
} elseif ($val['formType'] == 'select') {
|
||||||
$templateFile = "view{$this->DS}module{$this->DS}select";
|
$templateFile = "view{$this->DS}module{$this->DS}select";
|
||||||
if (isset($val['bindRelation'])) {
|
if (isset($val['bindRelation'])) {
|
||||||
$define = $this->buildOptionView($val['bindRelation'], '{in name="k" value="$row.' . $field . '"}selected=""{/in}');
|
$define = $this->buildOptionView($field, '{if $row.' . $field . '==$k}selected{/if}');
|
||||||
} elseif (!empty($val['define'])) {
|
} elseif (!empty($val['define'])) {
|
||||||
$define = $this->buildOptionView($field, '{in name="k" value="$row.' . $field . '"}selected=""{/in}');
|
$define = $this->buildOptionView($field, '{if $row.' . $field . '==$k}selected{/if}');
|
||||||
}
|
}
|
||||||
} elseif ($field == 'remark' || $val['formType'] == 'textarea') {
|
} elseif ($field == 'remark' || $val['formType'] == 'textarea') {
|
||||||
$templateFile = "view{$this->DS}module{$this->DS}textarea";
|
$templateFile = "view{$this->DS}module{$this->DS}textarea";
|
||||||
@@ -1343,6 +1348,15 @@ class BuildCurd
|
|||||||
);
|
);
|
||||||
$this->fileList[$viewEditFile] = $viewEditValue;
|
$this->fileList[$viewEditFile] = $viewEditValue;
|
||||||
|
|
||||||
|
$viewRecycleFile = "{$this->rootDir}app{$this->DS}admin{$this->DS}view{$this->DS}{$this->viewFilename}{$this->DS}recycle.html";
|
||||||
|
$viewRecycleValue = CommonTool::replaceTemplate(
|
||||||
|
$this->getTemplate("view{$this->DS}recycle"),
|
||||||
|
[
|
||||||
|
'controllerUrl' => $this->controllerUrl,
|
||||||
|
'notesScript' => $this->formatNotesScript(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$this->fileList[$viewRecycleFile] = $viewRecycleValue;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1361,6 +1375,8 @@ class BuildCurd
|
|||||||
|
|
||||||
if ($val['formType'] == 'image') {
|
if ($val['formType'] == 'image') {
|
||||||
$templateValue = "{field: '{$field}', title: '{$val['comment']}', templet: ea.table.image}";
|
$templateValue = "{field: '{$field}', title: '{$val['comment']}', templet: ea.table.image}";
|
||||||
|
} elseif ($val['formType'] == 'datetime') {
|
||||||
|
$templateValue = "{field: '{$field}', search: 'range', title: '{$val['comment']}'}";
|
||||||
} elseif ($val['formType'] == 'images') {
|
} elseif ($val['formType'] == 'images') {
|
||||||
continue;
|
continue;
|
||||||
} elseif ($val['formType'] == 'file') {
|
} elseif ($val['formType'] == 'file') {
|
||||||
@@ -1388,13 +1404,12 @@ class BuildCurd
|
|||||||
} else {
|
} else {
|
||||||
$templateValue = "{field: '{$field}', title: '{$val['comment']}'}";
|
$templateValue = "{field: '{$field}', title: '{$val['comment']}'}";
|
||||||
}
|
}
|
||||||
|
|
||||||
$indexCols .= $this->formatColsRow("{$templateValue},\r");
|
$indexCols .= $this->formatColsRow("{$templateValue},\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关联表
|
// 关联表
|
||||||
foreach ($this->relationArray as $table => $tableVal) {
|
foreach ($this->relationArray as $table => $tableVal) {
|
||||||
$table = CommonTool::lineToHump($table);
|
$table = CommonTool::humpToLine($table);
|
||||||
foreach ($tableVal['tableColumns'] as $field => $val) {
|
foreach ($tableVal['tableColumns'] as $field => $val) {
|
||||||
if ($val['formType'] == 'image') {
|
if ($val['formType'] == 'image') {
|
||||||
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}', templet: ea.table.image}";
|
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}', templet: ea.table.image}";
|
||||||
@@ -1418,17 +1433,19 @@ class BuildCurd
|
|||||||
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}'}";
|
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}'}";
|
||||||
}
|
}
|
||||||
|
|
||||||
$indexCols .= $this->formatColsRow("{$templateValue},\r");
|
if ($templateValue) $indexCols .= $this->formatColsRow("{$templateValue},\r");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$indexCols .= $this->formatColsRow("{width: 250, title: '操作', templet: ea.table.tool},\r");
|
$recycleCols = $indexCols;
|
||||||
|
$indexCols .= $this->formatColsRow("{width: 250, title: '操作', templet: ea.table.tool},\r");
|
||||||
|
|
||||||
$jsValue = CommonTool::replaceTemplate(
|
$jsValue = CommonTool::replaceTemplate(
|
||||||
$this->getTemplate("static{$this->DS}js"),
|
$this->getTemplate("static{$this->DS}js"),
|
||||||
[
|
[
|
||||||
'controllerUrl' => $this->controllerUrl,
|
'controllerUrl' => $this->controllerUrl,
|
||||||
'indexCols' => $indexCols,
|
'indexCols' => $indexCols,
|
||||||
|
'recycleCols' => $recycleCols,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
$this->fileList[$jsFile] = $jsValue;
|
$this->fileList[$jsFile] = $jsValue;
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ class {{controllerName}} extends AdminController
|
|||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
parent::__construct($app);
|
parent::__construct($app);
|
||||||
$this->model = new {{modelFilename}}();
|
self::$model = new {{modelFilename}}();
|
||||||
$this->notes = $notes = $this->model->notes;
|
$notes = self::$model::$notes;
|
||||||
{{constructRelation}}
|
{{constructRelation}}
|
||||||
|
$this->notes =$notes;
|
||||||
$this->assign(compact('notes'));
|
$this->assign(compact('notes'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
#[NodeAnnotation(title: '列表', auth: true)]
|
||||||
|
public function index(\app\Request $request): \think\response\Json|string
|
||||||
|
{
|
||||||
|
if ($request->isAjax()) {
|
||||||
|
if (input('selectFields')) {
|
||||||
|
return $this->selectList();
|
||||||
|
}
|
||||||
|
list($page, $limit, $where) = $this->buildTableParams();
|
||||||
|
$count = self::$model::where($where)->{{relationIndexMethod}}->count();
|
||||||
|
$list = self::$model::where($where)->{{relationIndexMethod}}->page($page, $limit)->order($this->sort)->select()->toArray();
|
||||||
|
$data = [
|
||||||
|
'code' => 0,
|
||||||
|
'msg' => '',
|
||||||
|
'count' => $count,
|
||||||
|
'data' => $list,
|
||||||
|
];
|
||||||
|
return json($data);
|
||||||
|
}
|
||||||
|
return $this->fetch();
|
||||||
|
}
|
||||||
@@ -7,12 +7,17 @@ use app\common\model\TimeModel;
|
|||||||
class {{modelName}} extends TimeModel
|
class {{modelName}} extends TimeModel
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $name = "{{table}}";
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => "{{table}}",
|
||||||
|
'table' => "{{prefix_table}}",
|
||||||
|
'deleteTime' => {{deleteTime}},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
protected $table = "{{prefix_table}}";
|
public static array $notes = {{selectArrays}};
|
||||||
|
|
||||||
protected $deleteTime = {{deleteTime}};
|
{{relationList}}
|
||||||
|
|
||||||
public array $notes = {{selectArrays}};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
public function {{relationMethod}}()
|
public function {{relationMethod}}()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('{{relationModel}}', '{{foreignKey}}', '{{primaryKey}}');
|
return $this->belongsTo({{relationModel}}, '{{foreignKey}}', '{{primaryKey}}'){{relationFields}};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
delete_url: '{{controllerUrl}}/delete',
|
delete_url: '{{controllerUrl}}/delete',
|
||||||
export_url: '{{controllerUrl}}/export',
|
export_url: '{{controllerUrl}}/export',
|
||||||
modify_url: '{{controllerUrl}}/modify',
|
modify_url: '{{controllerUrl}}/modify',
|
||||||
|
recycle_url: '{{controllerUrl}}/recycle',
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -29,5 +30,62 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
edit: function () {
|
edit: function () {
|
||||||
ea.listen();
|
ea.listen();
|
||||||
},
|
},
|
||||||
|
recycle: function () {
|
||||||
|
init.index_url = init.recycle_url;
|
||||||
|
ea.table.render({
|
||||||
|
init: init,
|
||||||
|
toolbar: ['refresh',
|
||||||
|
[{
|
||||||
|
class: 'layui-btn layui-btn-sm',
|
||||||
|
method: 'get',
|
||||||
|
field: 'id',
|
||||||
|
icon: 'fa fa-refresh',
|
||||||
|
text: '全部恢复',
|
||||||
|
title: '确定恢复?',
|
||||||
|
auth: 'recycle',
|
||||||
|
url: init.recycle_url + '?type=restore',
|
||||||
|
checkbox: true
|
||||||
|
}, {
|
||||||
|
class: 'layui-btn layui-btn-danger layui-btn-sm',
|
||||||
|
method: 'get',
|
||||||
|
field: 'id',
|
||||||
|
icon: 'fa fa-delete',
|
||||||
|
text: '彻底删除',
|
||||||
|
title: '确定彻底删除?',
|
||||||
|
auth: 'recycle',
|
||||||
|
url: init.recycle_url + '?type=delete',
|
||||||
|
checkbox: true
|
||||||
|
}], 'export',
|
||||||
|
],
|
||||||
|
cols: [[
|
||||||
|
{{recycleCols}}
|
||||||
|
{
|
||||||
|
width: 250,
|
||||||
|
title: '操作',
|
||||||
|
templet: ea.table.tool,
|
||||||
|
operat: [
|
||||||
|
[{
|
||||||
|
title: '确认恢复?',
|
||||||
|
text: '恢复数据',
|
||||||
|
filed: 'id',
|
||||||
|
url: init.recycle_url + '?type=restore',
|
||||||
|
method: 'get',
|
||||||
|
auth: 'recycle',
|
||||||
|
class: 'layui-btn layui-btn-xs layui-btn-success',
|
||||||
|
}, {
|
||||||
|
title: '想好了吗?',
|
||||||
|
text: '彻底删除',
|
||||||
|
filed: 'id',
|
||||||
|
method: 'get',
|
||||||
|
url: init.recycle_url + '?type=delete',
|
||||||
|
auth: 'recycle',
|
||||||
|
class: 'layui-btn layui-btn-xs layui-btn-normal layui-bg-red',
|
||||||
|
}]]
|
||||||
|
}
|
||||||
|
]],
|
||||||
|
});
|
||||||
|
|
||||||
|
ea.listen();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
data-auth-add="{:auth('{{controllerUrl}}/add')}"
|
data-auth-add="{:auth('{{controllerUrl}}/add')}"
|
||||||
data-auth-edit="{:auth('{{controllerUrl}}/edit')}"
|
data-auth-edit="{:auth('{{controllerUrl}}/edit')}"
|
||||||
data-auth-delete="{:auth('{{controllerUrl}}/delete')}"
|
data-auth-delete="{:auth('{{controllerUrl}}/delete')}"
|
||||||
|
data-auth-recycle="{:auth('{{controllerUrl}}/recycle')}"
|
||||||
lay-filter="currentTable">
|
lay-filter="currentTable">
|
||||||
<!-- searchTableShow="false" 隐藏搜索框 -->
|
<!-- searchTableShow="false" 隐藏搜索框 -->
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
13
app/admin/service/curd/templates/view/recycle.code
Normal file
13
app/admin/service/curd/templates/view/recycle.code
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<div class="layuimini-container">
|
||||||
|
<div class="layuimini-main">
|
||||||
|
<table id="currentTable" class="layui-table layui-hide"
|
||||||
|
data-auth-recycle="{:auth('{{controllerUrl}}/recycle')}"
|
||||||
|
lay-filter="currentTable">
|
||||||
|
<!-- searchTableShow="false" 隐藏搜索框 -->
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
{{notesScript}}
|
||||||
|
</script>
|
||||||
@@ -100,6 +100,9 @@ class CommonTool
|
|||||||
{
|
{
|
||||||
$arrayString = str_replace('array (', '[', $arrayString);
|
$arrayString = str_replace('array (', '[', $arrayString);
|
||||||
$arrayString = str_replace(')', ']', $arrayString);
|
$arrayString = str_replace(')', ']', $arrayString);
|
||||||
|
$arrayString = str_replace('=>
|
||||||
|
[', '=> [', $arrayString);
|
||||||
return $arrayString;
|
return $arrayString;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ namespace app\admin\traits;
|
|||||||
use app\admin\service\annotation\NodeAnnotation;
|
use app\admin\service\annotation\NodeAnnotation;
|
||||||
use app\admin\service\tool\CommonTool;
|
use app\admin\service\tool\CommonTool;
|
||||||
use app\Request;
|
use app\Request;
|
||||||
use jianyan\excel\Excel;
|
use think\db\exception\PDOException;
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
|
|
||||||
@@ -25,8 +25,8 @@ trait Curd
|
|||||||
return $this->selectList();
|
return $this->selectList();
|
||||||
}
|
}
|
||||||
list($page, $limit, $where) = $this->buildTableParams();
|
list($page, $limit, $where) = $this->buildTableParams();
|
||||||
$count = $this->model->where($where)->count();
|
$count = self::$model::where($where)->count();
|
||||||
$list = $this->model->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
|
$list = self::$model::where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
|
||||||
$data = [
|
$data = [
|
||||||
'code' => 0,
|
'code' => 0,
|
||||||
'msg' => '',
|
'msg' => '',
|
||||||
@@ -46,8 +46,8 @@ trait Curd
|
|||||||
$rule = [];
|
$rule = [];
|
||||||
$this->validate($post, $rule);
|
$this->validate($post, $rule);
|
||||||
try {
|
try {
|
||||||
Db::transaction(function () use ($post, &$save) {
|
Db::transaction(function() use ($post, &$save) {
|
||||||
$save = $this->model->save($post);
|
$save = self::$model::create($post);
|
||||||
});
|
});
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
$this->error('新增失败:' . $e->getMessage());
|
$this->error('新增失败:' . $e->getMessage());
|
||||||
@@ -60,14 +60,14 @@ trait Curd
|
|||||||
#[NodeAnnotation(title: '编辑', auth: true)]
|
#[NodeAnnotation(title: '编辑', auth: true)]
|
||||||
public function edit(Request $request, $id = 0): string
|
public function edit(Request $request, $id = 0): string
|
||||||
{
|
{
|
||||||
$row = $this->model->find($id);
|
$row = self::$model::find($id);
|
||||||
empty($row) && $this->error('数据不存在');
|
empty($row) && $this->error('数据不存在');
|
||||||
if ($request->isPost()) {
|
if ($request->isPost()) {
|
||||||
$post = $request->post();
|
$post = $request->post();
|
||||||
$rule = [];
|
$rule = [];
|
||||||
$this->validate($post, $rule);
|
$this->validate($post, $rule);
|
||||||
try {
|
try {
|
||||||
Db::transaction(function () use ($post, $row, &$save) {
|
Db::transaction(function() use ($post, $row, &$save) {
|
||||||
$save = $row->save($post);
|
$save = $row->save($post);
|
||||||
});
|
});
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
@@ -85,7 +85,7 @@ trait Curd
|
|||||||
// 如果不是id作为主键 请在对应的控制器中覆盖重写
|
// 如果不是id作为主键 请在对应的控制器中覆盖重写
|
||||||
$id = $request->param('id', []);
|
$id = $request->param('id', []);
|
||||||
$this->checkPostRequest();
|
$this->checkPostRequest();
|
||||||
$row = $this->model->whereIn('id', $id)->select();
|
$row = self::$model::whereIn('id', $id)->select();
|
||||||
$row->isEmpty() && $this->error('数据不存在');
|
$row->isEmpty() && $this->error('数据不存在');
|
||||||
try {
|
try {
|
||||||
$save = $row->delete();
|
$save = $row->delete();
|
||||||
@@ -102,7 +102,7 @@ trait Curd
|
|||||||
$this->error('演示环境下不允许操作');
|
$this->error('演示环境下不允许操作');
|
||||||
}
|
}
|
||||||
list($page, $limit, $where) = $this->buildTableParams();
|
list($page, $limit, $where) = $this->buildTableParams();
|
||||||
$tableName = $this->model->getName();
|
$tableName = (new self::$model)->getName();
|
||||||
$tableName = CommonTool::humpToLine(lcfirst($tableName));
|
$tableName = CommonTool::humpToLine(lcfirst($tableName));
|
||||||
$prefix = config('database.connections.mysql.prefix');
|
$prefix = config('database.connections.mysql.prefix');
|
||||||
$dbList = Db::query("show full columns from {$prefix}{$tableName}");
|
$dbList = Db::query("show full columns from {$prefix}{$tableName}");
|
||||||
@@ -113,14 +113,16 @@ trait Curd
|
|||||||
$header[] = [$comment, $vo['Field']];
|
$header[] = [$comment, $vo['Field']];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$list = $this->model
|
$list = self::$model::where($where)
|
||||||
->where($where)
|
|
||||||
->limit(100000)
|
->limit(100000)
|
||||||
->order('id', 'desc')
|
->order($this->sort)
|
||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
$fileName = time();
|
try {
|
||||||
return Excel::exportData($list, $header, $fileName, 'xlsx');
|
exportExcel($header, $list);
|
||||||
|
}catch (\Throwable $exception) {
|
||||||
|
$this->error('导出失败: ' . $exception->getMessage() . PHP_EOL . $exception->getFile() . PHP_EOL . $exception->getLine());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[NodeAnnotation(title: '属性修改', auth: true)]
|
#[NodeAnnotation(title: '属性修改', auth: true)]
|
||||||
@@ -134,7 +136,7 @@ trait Curd
|
|||||||
'value|值' => 'require',
|
'value|值' => 'require',
|
||||||
];
|
];
|
||||||
$this->validate($post, $rule);
|
$this->validate($post, $rule);
|
||||||
$row = $this->model->find($post['id']);
|
$row = self::$model::find($post['id']);
|
||||||
if (!$row) {
|
if (!$row) {
|
||||||
$this->error('数据不存在');
|
$this->error('数据不存在');
|
||||||
}
|
}
|
||||||
@@ -142,7 +144,7 @@ trait Curd
|
|||||||
$this->error('该字段不允许修改:' . $post['field']);
|
$this->error('该字段不允许修改:' . $post['field']);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Db::transaction(function () use ($post, $row) {
|
Db::transaction(function() use ($post, $row) {
|
||||||
$row->save([
|
$row->save([
|
||||||
$post['field'] => $post['value'],
|
$post['field'] => $post['value'],
|
||||||
]);
|
]);
|
||||||
@@ -153,4 +155,49 @@ trait Curd
|
|||||||
$this->success('保存成功');
|
$this->success('保存成功');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[NodeAnnotation(title: '回收站', auth: true)]
|
||||||
|
public function recycle(Request $request): Json|string
|
||||||
|
{
|
||||||
|
if (!$request->isAjax()) {
|
||||||
|
return $this->fetch();
|
||||||
|
}
|
||||||
|
$id = $request->param('id', []);
|
||||||
|
$type = $request->param('type', '');
|
||||||
|
$deleteTimeField = (new self::$model)->getOption('deleteTime'); // 获取软删除字段
|
||||||
|
$defaultErrorMsg = 'Model 中未设置软删除 deleteTime 对应字段 或 数据表中不存在该字段';
|
||||||
|
if (!$deleteTimeField) $this->success($defaultErrorMsg);
|
||||||
|
switch ($type) {
|
||||||
|
case 'restore':
|
||||||
|
self::$model::withTrashed()->whereIn('id', $id)->strict(false)->update([$deleteTimeField => null, 'update_time' => time()]);
|
||||||
|
$this->success('success');
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
self::$model::destroy($id, true);
|
||||||
|
$this->success('success');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
list($page, $limit, $where) = $this->buildTableParams();
|
||||||
|
try {
|
||||||
|
$count = self::$model::withTrashed()->where($where)->whereNotNull($deleteTimeField)->count();
|
||||||
|
$list = self::$model::withTrashed()->where($where)->page($page, $limit)->order($this->sort)->whereNotNull($deleteTimeField)->select()->toArray();
|
||||||
|
$data = [
|
||||||
|
'code' => 0,
|
||||||
|
'msg' => '',
|
||||||
|
'count' => $count,
|
||||||
|
'data' => $list,
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$error = $e->getMessage();
|
||||||
|
if ($e instanceof PDOException) $error .= '<br>' . $defaultErrorMsg;
|
||||||
|
$data = [
|
||||||
|
'code' => -1,
|
||||||
|
'msg' => $error,
|
||||||
|
'count' => 0,
|
||||||
|
'data' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="head_img" class="layui-input layui-col-xs6" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="{$row.head_img|default=''}">
|
<input name="head_img" class="layui-input layui-col-xs6" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="{$row.head_img|default=''}">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,12 +33,12 @@
|
|||||||
<a href="javascript:;" data-refresh="刷新"><i class="fa fa-refresh"></i></a>
|
<a href="javascript:;" data-refresh="刷新"><i class="fa fa-refresh"></i></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="layui-nav-item" lay-unselect>
|
<li class="layui-nav-item" lay-unselect>
|
||||||
<a href="javascript:;" data-clear="清理" class="layuimini-clear"><i class="fa fa-trash-o"></i></a>
|
<a href="javascript:;" data-clear="清理" class="layuimini-clear"><i class="fa fa-trash"></i></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="layui-nav-item mobile layui-hide-xs" lay-unselect>
|
<li class="layui-nav-item mobile layui-hide-xs" lay-unselect>
|
||||||
<a href="javascript:;" data-check-screen="full"><i class="fa fa-arrows-alt"></i></a>
|
<a href="javascript:;" data-check-screen="full"><i class="fa fa-arrows-alt"></i></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="layui-nav-item" lay-unselect>
|
<li class="layui-nav-item mobile layui-hide-xs" lay-unselect>
|
||||||
<div class="layui-form ws-header-theme" lay-filter="header-theme">
|
<div class="layui-form ws-header-theme" lay-filter="header-theme">
|
||||||
<input type="checkbox" name="theme-mode" lay-filter="header-theme-mode" lay-skin="switch">
|
<input type="checkbox" name="theme-mode" lay-filter="header-theme-mode" lay-skin="switch">
|
||||||
<div lay-checkbox>
|
<div lay-checkbox>
|
||||||
@@ -91,8 +91,8 @@
|
|||||||
<div class="layuimini-site-mobile"><i class="layui-icon"></i></div>
|
<div class="layuimini-site-mobile"><i class="layui-icon"></i></div>
|
||||||
|
|
||||||
<div class="layui-body">
|
<div class="layui-body">
|
||||||
<div class="layuimini-tab layui-tab-rollTool layui-tab" lay-filter="layuiminiTab" lay-allowclose="true">
|
<div class="layuimini-tab layui-tabs-rollTool layui-tabs" lay-filter="layuiminiTab" id="layuiminiTab">
|
||||||
<ul class="layui-tab-title">
|
<ul class="layui-tabs-header">
|
||||||
<li class="layui-this" id="layuiminiHomeTabId" lay-id=""></li>
|
<li class="layui-this" id="layuiminiHomeTabId" lay-id=""></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="layui-tab-control">
|
<div class="layui-tab-control">
|
||||||
@@ -111,8 +111,8 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-tab-content">
|
<div class="layui-tabs-body">
|
||||||
<div id="layuiminiHomeTabIframe" class="layui-tab-item layui-show"></div>
|
<div id="layuiminiHomeTabIframe" class="layui-tab-item layui-tabs-item layui-show"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,11 +13,11 @@
|
|||||||
<div class="layui-col-xs6">
|
<div class="layui-col-xs6">
|
||||||
<div class="layui-panel">
|
<div class="layui-panel">
|
||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
<span class="layui-badge layui-bg-cyan pull-right ">实时</span>
|
<span class="layui-badge layui-bg-cyan fa-pull-right ">实时</span>
|
||||||
<div class="panel-content">
|
<div class="panel-content">
|
||||||
<h5>用户统计</h5>
|
<h5>用户统计</h5>
|
||||||
<h1>1234</h1>
|
<h2>1234</h2>
|
||||||
<h6>当前分类总记录数</h6>
|
<h6>记录数</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,11 +25,11 @@
|
|||||||
<div class="layui-col-xs6">
|
<div class="layui-col-xs6">
|
||||||
<div class="layui-panel">
|
<div class="layui-panel">
|
||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
<span class="layui-badge layui-bg-purple pull-right ">实时</span>
|
<span class="layui-badge layui-bg-purple fa-pull-right ">实时</span>
|
||||||
<div class="panel-content">
|
<div class="panel-content">
|
||||||
<h5>商品统计</h5>
|
<h5>商品统计</h5>
|
||||||
<h1>1234</h1>
|
<h2>1234</h2>
|
||||||
<h6>当前分类总记录数</h6>
|
<h6>记录数</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,11 +37,11 @@
|
|||||||
<div class="layui-col-xs6">
|
<div class="layui-col-xs6">
|
||||||
<div class="layui-panel">
|
<div class="layui-panel">
|
||||||
<div class="layui-card-body ">
|
<div class="layui-card-body ">
|
||||||
<span class="layui-badge layui-bg-orange pull-right ">实时</span>
|
<span class="layui-badge layui-bg-orange fa-pull-right ">实时</span>
|
||||||
<div class="panel-content">
|
<div class="panel-content">
|
||||||
<h5>浏览统计</h5>
|
<h5>浏览统计</h5>
|
||||||
<h1>1234</h1>
|
<h2>1234</h2>
|
||||||
<h6>当前分类总记录数</h6>
|
<h6>记录数</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -49,11 +49,11 @@
|
|||||||
<div class="layui-col-xs6">
|
<div class="layui-col-xs6">
|
||||||
<div class="layui-panel">
|
<div class="layui-panel">
|
||||||
<div class="layui-card-body ">
|
<div class="layui-card-body ">
|
||||||
<span class="layui-badge layui-bg-red pull-right ">实时</span>
|
<span class="layui-badge layui-bg-red fa-pull-right ">实时</span>
|
||||||
<div class="panel-content">
|
<div class="panel-content">
|
||||||
<h5>订单统计</h5>
|
<h5>订单统计</h5>
|
||||||
<h1>1234</h1>
|
<h2>1234</h2>
|
||||||
<h6>当前分类总记录数</h6>
|
<h6>记录数</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,12 +151,18 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>DEBUG模式</td>
|
<td>DEBUG模式</td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="layui-btn layui-btn-xs {:env('APP_DEBUG')?'layui-btn-warm':'layui-bg-gray'}">
|
<span class="layui-badge {:env('APP_DEBUG')?'layui-bg-cyan':'layui-bg-gray'}">
|
||||||
{:env('APP_DEBUG')?'开启中':'已关闭'}
|
{:env('APP_DEBUG')?'开启中':'已关闭'}
|
||||||
</button>
|
</span>
|
||||||
<span class="layui-badge layui-bg-gray">建议线上环境关闭 APP_DEBUG</span>
|
<span class="layui-badge layui-bg-gray">建议线上环境关闭 APP_DEBUG</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>composer信息</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="layui-btn layui-btn-xs layui-bg-cyan" lay-on="showComposerInfo">点击查看</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>主要特色</td>
|
<td>主要特色</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -193,7 +199,7 @@
|
|||||||
<div class="layui-card-header"><i class="fa fa-paper-plane-o icon"></i>作者心语</div>
|
<div class="layui-card-header"><i class="fa fa-paper-plane-o icon"></i>作者心语</div>
|
||||||
<div class="layui-card-body layui-text">
|
<div class="layui-card-body layui-text">
|
||||||
<p>
|
<p>
|
||||||
本模板基于layui2.9.x以及font-awesome-4.7.0进行实现。
|
本模板基于layui2.x以及font-awesome-6.x进行实现。
|
||||||
<a class="layui-btn layui-btn-xs layui-btn-danger" style="vertical-align: baseline;" target="_blank" href="http://layui.dev/docs">layui文档</a>
|
<a class="layui-btn layui-btn-xs layui-btn-danger" style="vertical-align: baseline;" target="_blank" href="http://layui.dev/docs">layui文档</a>
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
<hr>
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="image" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
|
<input name="image" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="image" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="image" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_image" data-upload-select="image" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_image" data-upload-select="image" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="image" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传分类图片" placeholder="请上传分类图片" value="{$row.image|default=''}">
|
<input name="image" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传分类图片" placeholder="请上传分类图片" value="{$row.image|default=''}">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="image" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="image" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_image" data-upload-select="image" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_image" data-upload-select="image" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,22 +13,36 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--也可以使用该方式-->
|
<!--也可以使用该方式-->
|
||||||
<!-- <div class="layui-form-item">-->
|
<div class="layui-form-item">
|
||||||
<!-- <label class="layui-form-label">商品分类</label>-->
|
<label class="layui-form-label">商品分类2</label>
|
||||||
<!-- <div class="layui-input-block">-->
|
<div class="layui-input-block">
|
||||||
<!-- <select name="cate_id" lay-verify="required">-->
|
<select name="cate_id" lay-verify="required">
|
||||||
<!-- <option value="">请选择</option>-->
|
{volist name='cate' id='vo'}
|
||||||
<!-- {volist name='cate' id='vo'}-->
|
<option value="{$key}">{$vo}</option>
|
||||||
<!-- <option value="{$key}">{$vo}</option>-->
|
{/volist}
|
||||||
<!-- {/volist}-->
|
</select>
|
||||||
<!-- </select>-->
|
</div>
|
||||||
<!-- </div>-->
|
</div>
|
||||||
<!-- </div>-->
|
|
||||||
|
<!-- 展现形式不同的写法-->
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">商品分类3</label>
|
||||||
|
<div data-show="switchSelect" data-list='{$cate|json_encode|raw}' data-name="cate_id" data-value="" data-target="radio"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">商品标题</label>
|
<div class="layui-row">
|
||||||
<div class="layui-input-block">
|
<label class="layui-form-label required">商品标题</label>
|
||||||
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="">
|
<div class="layui-input-block layui-col-space5">
|
||||||
|
<div class="layui-col-xs10">
|
||||||
|
<div class="layui-input-wrap">
|
||||||
|
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-xs2">
|
||||||
|
<button class="layui-btn layui-bg-purple layui-btn-fluid" type="button" lay-on="AiOptimization">AI优化</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -37,8 +51,8 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
|
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -48,8 +62,8 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="">
|
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -82,6 +96,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 文档:https://xm-select.com/file/xm-select/v1.2.4/#/basic/use -->
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">模拟多选</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<div id="demo1" class="xm-select-demo"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="layui-form-item layui-form-text">
|
<div class="layui-form-item layui-form-text">
|
||||||
<label class="layui-form-label">备注信息</label>
|
<label class="layui-form-label">备注信息</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
|
|||||||
@@ -13,32 +13,47 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--也可以使用该方式-->
|
<!--也可以使用该方式-->
|
||||||
<!-- <div class="layui-form-item">-->
|
|
||||||
<!-- <label class="layui-form-label">商品分类</label>-->
|
|
||||||
<!-- <div class="layui-input-block">-->
|
|
||||||
<!-- <select name="cate_id" lay-verify="required">-->
|
|
||||||
<!-- <option value="">请选择</option>-->
|
|
||||||
<!-- {volist name='cate' id='vo'}-->
|
|
||||||
<!-- <option value="{$key}" {if $key==$row.cate_id}selected{/if}>{$vo}</option>-->
|
|
||||||
<!-- {/volist}-->
|
|
||||||
<!-- </select>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
|
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">商品标题</label>
|
<label class="layui-form-label">商品分类2</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="{$row.title|default=''}">
|
<select name="cate_id" lay-verify="required">
|
||||||
|
{volist name='cate' id='vo'}
|
||||||
|
<option value="{$key}" {if $key==$row.cate_id}selected{/if}>{$vo}</option>
|
||||||
|
{/volist}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 展现形式不同的写法-->
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">商品分类3</label>
|
||||||
|
<div data-show="switchSelect" data-list='{$cate|json_encode|raw}' data-name="cate_id" data-value="{$row.cate_id}" data-target="radio"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<div class="layui-row">
|
||||||
|
<label class="layui-form-label required">商品标题</label>
|
||||||
|
<div class="layui-input-block layui-col-space5">
|
||||||
|
<div class="layui-col-xs10">
|
||||||
|
<div class="layui-input-wrap">
|
||||||
|
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="{$row.title|default=''}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-xs2">
|
||||||
|
<button class="layui-btn layui-bg-purple" type="button" lay-on="AiOptimization">AI优化</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label required">商品LOGO</label>
|
<label class="layui-form-label required">商品LOGO</label>
|
||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="{$row.logo|default=''}">
|
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="{$row.logo|default=''}">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="logo" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_logo" data-upload-select="logo" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -48,8 +63,8 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="{$row.images|default=''}">
|
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="{$row.images|default=''}">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="images" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_images" data-upload-select="images" data-upload-number="more"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -82,6 +97,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 文档:https://xm-select.com/file/xm-select/v1.2.4/#/basic/use -->
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">模拟多选</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<div id="demo1" class="xm-select-demo"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="layui-form-item layui-form-text">
|
<div class="layui-form-item layui-form-text">
|
||||||
<label class="layui-form-label">备注信息</label>
|
<label class="layui-form-label">备注信息</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
data-auth-edit="{:auth('mall.goods/edit')}"
|
data-auth-edit="{:auth('mall.goods/edit')}"
|
||||||
data-auth-delete="{:auth('mall.goods/delete')}"
|
data-auth-delete="{:auth('mall.goods/delete')}"
|
||||||
data-auth-stock="{:auth('mall.goods/stock')}"
|
data-auth-stock="{:auth('mall.goods/stock')}"
|
||||||
|
data-auth-recycle="{:auth('mall.goods/recycle')}"
|
||||||
lay-filter="currentTable">
|
lay-filter="currentTable">
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
11
app/admin/view/mall/goods/recycle.html
Normal file
11
app/admin/view/mall/goods/recycle.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<div class="layuimini-container">
|
||||||
|
<div class="layuimini-main">
|
||||||
|
<table id="currentTable" class="layui-table layui-hide"
|
||||||
|
data-auth-recycle="{:auth('mall.goods/recycle')}"
|
||||||
|
lay-filter="currentTable">
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
let cateSelects = JSON.parse('{$cate|json_encode=256|raw}')
|
||||||
|
</script>
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="head_img" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="">
|
<input name="head_img" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="head_img" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="{$row.head_img|default=''}">
|
<input name="head_img" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="{$row.head_img|default=''}">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="head_img" data-upload-number="one" data-upload-exts="png|jpg|ico|jpeg" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_head_img" data-upload-select="head_img" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,36 @@
|
|||||||
<div class="layuimini-container">
|
<div class="layuimini-container">
|
||||||
<div class="layuimini-main">
|
<div class="layuimini-main">
|
||||||
<table id="currentTable" class="layui-table layui-hide"
|
|
||||||
data-auth-add="{:auth('system.admin/add')}"
|
<div class="layui-row layui-col-space8">
|
||||||
data-auth-edit="{:auth('system.admin/edit')}"
|
<div class="layui-col-md2 layui-hide-xs">
|
||||||
data-auth-delete="{:auth('system.admin/delete')}"
|
<div class="layui-card-body layui-border">
|
||||||
data-auth-password="{:auth('system.admin/password')}"
|
<h2>角色列表</h2>
|
||||||
lay-filter="currentTable">
|
<ul class="layui-menu layui-dropdown-menu">
|
||||||
</table>
|
<li class="layui-menu-item-checked">
|
||||||
|
<div class="layui-menu-body-title" lay-on="authSearch" data-auth_id="0">全部</div>
|
||||||
|
</li>
|
||||||
|
{volist name="auth_list" id="vo"}
|
||||||
|
<li class="">
|
||||||
|
<div class="layui-menu-body-title" lay-on="authSearch" data-auth_id="{$key}">{$vo}</div>
|
||||||
|
</li>
|
||||||
|
{/volist}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-md10">
|
||||||
|
<table id="currentTable" class="layui-table layui-hide"
|
||||||
|
data-auth-add="{:auth('system.admin/add')}"
|
||||||
|
data-auth-edit="{:auth('system.admin/edit')}"
|
||||||
|
data-auth-delete="{:auth('system.admin/delete')}"
|
||||||
|
data-auth-password="{:auth('system.admin/password')}"
|
||||||
|
lay-filter="currentTable">
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let auth_list = JSON.parse('{$auth_list|json_encode=256|raw}')
|
||||||
|
</script>
|
||||||
@@ -1,22 +1,16 @@
|
|||||||
<div class="layuimini-container">
|
<div class="layuimini-container">
|
||||||
<div class="layuimini-main" id="app">
|
<div class="layuimini-main" id="app">
|
||||||
|
|
||||||
<div class="layui-tab layui-tab-brief" lay-filter="docDemoTabBrief">
|
<div class="layui-tabs layui-tabs-card layui-panel " id="docDemoTabBrief">
|
||||||
<ul class="layui-tab-title">
|
<ul class="layui-tabs-header layui-bg-tint">
|
||||||
<li class="layui-this" data-group="site">网站设置</li>
|
<li class="layui-this" data-group="site">网站设置</li>
|
||||||
<li data-group="logo">LOGO配置</li>
|
<li data-group="logo">LOGO配置</li>
|
||||||
<li data-group="upload">上传配置</li>
|
<li data-group="upload">上传配置</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="layui-tab-content">
|
<div class="layui-tabs-body">
|
||||||
<div class="layui-tab-item layui-show">
|
<div class="layui-tabs-item layui-show"> {include file="system/config/site" /}</div>
|
||||||
{include file="system/config/site" /}
|
<div class="layui-tabs-item"> {include file="system/config/logo" /}</div>
|
||||||
</div>
|
<div class="layui-tabs-item">{include file="system/config/upload" /}</div>
|
||||||
<div class="layui-tab-item">
|
|
||||||
{include file="system/config/logo" /}
|
|
||||||
</div>
|
|
||||||
<div class="layui-tab-item">
|
|
||||||
{include file="system/config/upload" /}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="logo_image" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传LOGO图标" value="{:sysConfig('site','logo_image')}">
|
<input name="logo_image" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传LOGO图标" value="{:sysConfig('site','logo_image')}">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="logo_image" data-upload-number="one" data-upload-exts="ico|png|jpg|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="logo_image" data-upload-number="one" data-upload-exts="ico|png|jpg|jpeg" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_logo_image" data-upload-select="logo_image" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_logo_image" data-upload-select="logo_image" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="site_ico" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传浏览器图标,ico类型" value="{:sysConfig('site','site_ico')}">
|
<input name="site_ico" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传浏览器图标,ico类型" value="{:sysConfig('site','site_ico')}">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="site_ico" data-upload-number="one" data-upload-exts="ico"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="site_ico" data-upload-number="one" data-upload-exts="ico" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_site_ico" data-upload-select="site_ico" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_site_ico" data-upload-select="site_ico" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<div class="layui-input-block layuimini-upload">
|
<div class="layui-input-block layuimini-upload">
|
||||||
<input name="admin_background" class="layui-input layui-col-xs6" placeholder="不填默认#333333" value="{:sysConfig('site','admin_background')}">
|
<input name="admin_background" class="layui-input layui-col-xs6" placeholder="不填默认#333333" value="{:sysConfig('site','admin_background')}">
|
||||||
<div class="layuimini-upload-btn">
|
<div class="layuimini-upload-btn">
|
||||||
<span><a class="layui-btn" data-upload="admin_background" data-upload-number="one" data-upload-exts="png|jpg|jpeg"><i class="fa fa-upload"></i> 上传</a></span>
|
<span><a class="layui-btn" data-upload="admin_background" data-upload-number="one" data-upload-exts="png|jpg|jpeg" data-upload-mimetype="image/*"><i class="fa fa-upload"></i> 上传</a></span>
|
||||||
<span><a class="layui-btn layui-btn-normal" id="select_admin_background" data-upload-select="admin_background" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
<span><a class="layui-btn layui-btn-normal" id="select_admin_background" data-upload-select="admin_background" data-upload-number="one"><i class="fa fa-list"></i> 选择</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
23
app/admin/view/system/log/delete_month_log.html
Normal file
23
app/admin/view/system/log/delete_month_log.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<div class="layuimini-container">
|
||||||
|
|
||||||
|
<form id="app-form" class="layui-form layuimini-form">
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
|
||||||
|
<div class="layui-input-group">
|
||||||
|
<div class="layui-input-prefix layui-input-split">删除</div>
|
||||||
|
<label>
|
||||||
|
<input type="number" name="month" lay-affix="number" placeholder="" min="1" class="layui-input" value="3">
|
||||||
|
</label>
|
||||||
|
<div class="layui-input-suffix layui-input-split">个月前的日志</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hr-line"></div>
|
||||||
|
<div class="layui-form-item text-center">
|
||||||
|
<button type="button" class="layui-btn" lay-submit lay-filter="submit">提交</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
<div class="layuimini-main">
|
<div class="layuimini-main">
|
||||||
<table id="currentTable" class="layui-table layui-hide"
|
<table id="currentTable" class="layui-table layui-hide"
|
||||||
data-auth-record="{:auth('system.log/record')}"
|
data-auth-record="{:auth('system.log/record')}"
|
||||||
|
data-auth-deleteMonthLog="{:auth('system.log/deleteMonthLog')}"
|
||||||
lay-filter="currentTable">
|
lay-filter="currentTable">
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,4 +20,5 @@
|
|||||||
<button class="layui-btn layui-btn-sm layuimini-btn-primary" data-treetable-refresh><i class="fa fa-refresh"></i></button>
|
<button class="layui-btn layui-btn-sm layuimini-btn-primary" data-treetable-refresh><i class="fa fa-refresh"></i></button>
|
||||||
<button class="layui-btn layui-btn-normal layui-btn-sm {if !auth('system.menu/add')}layui-hide{/if}" data-open="system.menu/add" data-title="添加"><i class="fa fa-plus"></i> 添加</button>
|
<button class="layui-btn layui-btn-normal layui-btn-sm {if !auth('system.menu/add')}layui-hide{/if}" data-open="system.menu/add" data-title="添加"><i class="fa fa-plus"></i> 添加</button>
|
||||||
<button class="layui-btn layui-btn-sm layui-btn-danger {if !auth('system.menu/delete')}layui-hide{/if}" data-url="system.menu/delete" data-treetable-delete="currentTableRenderId"><i class="fa fa-trash-o"></i> 删除</button>
|
<button class="layui-btn layui-btn-sm layui-btn-danger {if !auth('system.menu/delete')}layui-hide{/if}" data-url="system.menu/delete" data-treetable-delete="currentTableRenderId"><i class="fa fa-trash-o"></i> 删除</button>
|
||||||
|
<button class="layui-btn layui-btn-sm" type="button" data-treetable-arrow data-arrow="up"><i class="fa fa-arrow-up"></i> 一键折叠</button>
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
// 应用公共文件
|
// 应用公共文件
|
||||||
|
|
||||||
use app\common\service\AuthService;
|
use app\common\service\AuthService;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||||
use think\db\exception\DataNotFoundException;
|
use think\db\exception\DataNotFoundException;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use think\db\exception\ModelNotFoundException;
|
use think\db\exception\ModelNotFoundException;
|
||||||
@@ -100,21 +102,63 @@ if (!function_exists('auth')) {
|
|||||||
$authService = new AuthService(session('admin.id'));
|
$authService = new AuthService(session('admin.id'));
|
||||||
return $authService->checkNode($node);
|
return $authService->checkNode($node);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* @param string|null $detail
|
/**
|
||||||
* @param string $name
|
* @param string|null $detail
|
||||||
* @param string $placeholder
|
* @param string $name
|
||||||
* @return string
|
* @param string $placeholder
|
||||||
*/
|
* @return string
|
||||||
function editor_textarea(?string $detail, string $name = 'desc', string $placeholder = '请输入'): string
|
*/
|
||||||
{
|
function editor_textarea(?string $detail, string $name = 'desc', string $placeholder = '请输入'): string
|
||||||
$editor_type = sysConfig('site', 'editor_type');
|
{
|
||||||
return match ($editor_type) {
|
$editor_type = sysConfig('site', 'editor_type');
|
||||||
'ckeditor' => "<textarea name='{$name}' rows='20' class='layui-textarea editor' placeholder='{$placeholder}'>{$detail}</textarea>",
|
return match ($editor_type) {
|
||||||
'ueditor' => "<script type='text/plain' id='{$name}' name='{$name}' class='editor' data-content='{$detail}'></script>",
|
'ckeditor' => "<textarea name='{$name}' rows='20' class='layui-textarea editor' placeholder='{$placeholder}'>{$detail}</textarea>",
|
||||||
'EasyMDE' => "<textarea id='{$name}' class='editor' name='{$name}'>{$detail}</textarea>",
|
'ueditor' => "<script type='text/plain' id='{$name}' name='{$name}' class='editor' data-content='{$detail}'></script>",
|
||||||
default => "<div class='wangEditor_div'><textarea name='{$name}' rows='20' class='layui-textarea editor layui-hide'>{$detail}</textarea><div id='editor_toolbar_{$name}'></div><div id='editor_{$name}' style='height: 300px'></div></div>",
|
'EasyMDE' => "<textarea id='{$name}' class='editor' name='{$name}'>{$detail}</textarea>",
|
||||||
};
|
default => "<div class='wangEditor_div'><textarea name='{$name}' rows='20' class='layui-textarea editor layui-hide'>{$detail}</textarea><div id='editor_toolbar_{$name}'></div><div id='editor_{$name}' style='height: 500px'></div></div>",
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc 导出excel
|
||||||
|
* @tip 追求性能请使用 xlsWriter https://xlswriter-docs.viest.me/zh-cn
|
||||||
|
* @param array $header
|
||||||
|
* @param array $list
|
||||||
|
* @param string $fileName
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
function exportExcel(array $header = [], array $list = [], string $fileName = ''): void
|
||||||
|
{
|
||||||
|
if (empty($fileName)) $fileName = time();
|
||||||
|
if (empty($header) || empty($list)) throw new \Exception('导出数据不能为空');
|
||||||
|
$spreadsheet = new Spreadsheet();
|
||||||
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
|
$headers = array_column($header, 0) ?? array_keys($list[0]);
|
||||||
|
$sheet->fromArray([$headers], null, 'A1');
|
||||||
|
$rowIndex = 2;
|
||||||
|
foreach ($list as $row) {
|
||||||
|
$rowData = [];
|
||||||
|
foreach ($header as $item) {
|
||||||
|
$value = $row[$item[1]] ?? '';
|
||||||
|
if ($value === null) {
|
||||||
|
$rowData[] = '';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$rowData[] = $value;
|
||||||
|
}
|
||||||
|
$sheet->fromArray([$rowData], null, "A{$rowIndex}");
|
||||||
|
$rowIndex++;
|
||||||
|
}
|
||||||
|
foreach (range('A', $sheet->getHighestColumn()) as $col) {
|
||||||
|
$sheet->getColumnDimension($col)->setAutoSize(true);
|
||||||
|
}
|
||||||
|
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||||
|
header('Content-Disposition: attachment;filename="' . $fileName . '.xlsx"');
|
||||||
|
header('Cache-Control: max-age=0');
|
||||||
|
$writer = new Xlsx($spreadsheet);
|
||||||
|
$writer->save('php://output');
|
||||||
|
die();
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ use app\admin\traits\Curd;
|
|||||||
use app\BaseController;
|
use app\BaseController;
|
||||||
use app\common\constants\AdminConstant;
|
use app\common\constants\AdminConstant;
|
||||||
use app\common\traits\JumpTrait;
|
use app\common\traits\JumpTrait;
|
||||||
|
use think\facade\Db;
|
||||||
use think\facade\View;
|
use think\facade\View;
|
||||||
use think\helper\Str;
|
use think\helper\Str;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
@@ -19,9 +20,9 @@ class AdminController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 当前模型
|
* 当前模型
|
||||||
* @Model
|
* @Model
|
||||||
* @var object
|
* @var mixed
|
||||||
*/
|
*/
|
||||||
protected object $model;
|
protected static mixed $model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字段排序
|
* 字段排序
|
||||||
@@ -133,9 +134,6 @@ class AdminController extends BaseController
|
|||||||
{
|
{
|
||||||
if ($layout) View::instance()->engine()->layout('/layout/default');
|
if ($layout) View::instance()->engine()->layout('/layout/default');
|
||||||
View::assign($vars);
|
View::assign($vars);
|
||||||
if (empty($template)) {
|
|
||||||
$template = strtolower(str_replace('.', '/', $this->request->pathinfo()));
|
|
||||||
}
|
|
||||||
return View::fetch($template);
|
return View::fetch($template);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +173,7 @@ class AdminController extends BaseController
|
|||||||
$where = [];
|
$where = [];
|
||||||
$excludes = [];
|
$excludes = [];
|
||||||
// 判断是否关联查询
|
// 判断是否关联查询
|
||||||
$tableName = Str::snake(lcfirst($this->model->getName()));
|
$tableName = Str::snake(lcfirst((new self::$model)->getName()));
|
||||||
foreach ($filters as $key => $val) {
|
foreach ($filters as $key => $val) {
|
||||||
if (in_array($key, $excludeFields)) {
|
if (in_array($key, $excludeFields)) {
|
||||||
$excludes[$key] = $val;
|
$excludes[$key] = $val;
|
||||||
@@ -202,11 +200,19 @@ class AdminController extends BaseController
|
|||||||
case 'in':
|
case 'in':
|
||||||
$where[] = [$key, 'IN', $val];
|
$where[] = [$key, 'IN', $val];
|
||||||
break;
|
break;
|
||||||
|
case 'find_in_set':
|
||||||
|
$where[] = ['', 'exp', Db::raw("FIND_IN_SET(:param,$key)", ['param' => $val])];
|
||||||
|
break;
|
||||||
case 'range':
|
case 'range':
|
||||||
[$beginTime, $endTime] = explode(' - ', $val);
|
[$beginTime, $endTime] = explode(' - ', $val);
|
||||||
$where[] = [$key, '>=', strtotime($beginTime)];
|
$where[] = [$key, '>=', strtotime($beginTime)];
|
||||||
$where[] = [$key, '<=', strtotime($endTime)];
|
$where[] = [$key, '<=', strtotime($endTime)];
|
||||||
break;
|
break;
|
||||||
|
case 'datetime':
|
||||||
|
[$beginTime, $endTime] = explode(' - ', $val);
|
||||||
|
$where[] = [$key, '>=', $beginTime];
|
||||||
|
$where[] = [$key, '<=', $endTime];
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$where[] = [$key, $op, "%{$val}"];
|
$where[] = [$key, $op, "%{$val}"];
|
||||||
}
|
}
|
||||||
@@ -221,7 +227,7 @@ class AdminController extends BaseController
|
|||||||
public function selectList(): Json
|
public function selectList(): Json
|
||||||
{
|
{
|
||||||
$fields = input('selectFields');
|
$fields = input('selectFields');
|
||||||
$data = $this->model->where($this->selectWhere)->field($fields)->select()->toArray();
|
$data = self::$model::where($this->selectWhere)->field($fields)->select()->toArray();
|
||||||
$this->success(null, $data);
|
$this->success(null, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
app/common/entity/BaseEntity.php
Normal file
22
app/common/entity/BaseEntity.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\entity;
|
||||||
|
|
||||||
|
use think\Entity;
|
||||||
|
use think\model\type\DateTime;
|
||||||
|
|
||||||
|
class BaseEntity extends Entity
|
||||||
|
{
|
||||||
|
|
||||||
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'type' => [
|
||||||
|
'create_time' => DateTime::class,
|
||||||
|
'update_time' => DateTime::class,
|
||||||
|
'delete_time' => DateTime::class,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,28 +13,20 @@ use think\model\concern\SoftDelete;
|
|||||||
class TimeModel extends Model
|
class TimeModel extends Model
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* 自动时间戳类型
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $autoWriteTimestamp = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加时间
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $createTime = 'create_time';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新时间
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $updateTime = 'update_time';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 软删除
|
* 软删除
|
||||||
*/
|
*/
|
||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
protected $deleteTime = false;
|
|
||||||
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'autoWriteTimestamp' => true,
|
||||||
|
'createTime' => 'create_time',
|
||||||
|
'updateTime' => 'update_time',
|
||||||
|
'deleteTime' => false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace app\common\service;
|
namespace app\common\service;
|
||||||
|
|
||||||
|
use app\admin\service\annotation\NodeAnnotation;
|
||||||
use app\common\constants\AdminConstant;
|
use app\common\constants\AdminConstant;
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ class AuthService
|
|||||||
/***
|
/***
|
||||||
* 构造方法
|
* 构造方法
|
||||||
* AuthService constructor.
|
* AuthService constructor.
|
||||||
* @param null $adminId
|
* @param null $adminId
|
||||||
* @throws \think\db\exception\DataNotFoundException
|
* @throws \think\db\exception\DataNotFoundException
|
||||||
* @throws \think\db\exception\DbException
|
* @throws \think\db\exception\DbException
|
||||||
* @throws \think\db\exception\ModelNotFoundException
|
* @throws \think\db\exception\ModelNotFoundException
|
||||||
@@ -68,7 +69,7 @@ class AuthService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测检测权限
|
* 检测检测权限
|
||||||
* @param null $node
|
* @param null $node
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \think\db\exception\DataNotFoundException
|
* @throws \think\db\exception\DataNotFoundException
|
||||||
* @throws \think\db\exception\DbException
|
* @throws \think\db\exception\DbException
|
||||||
@@ -87,7 +88,7 @@ class AuthService
|
|||||||
// 判断是否需要获取当前节点
|
// 判断是否需要获取当前节点
|
||||||
if (empty($node)) {
|
if (empty($node)) {
|
||||||
$node = $this->getCurrentNode();
|
$node = $this->getCurrentNode();
|
||||||
} else {
|
}else {
|
||||||
$node = $this->parseNodeStr($node);
|
$node = $this->parseNodeStr($node);
|
||||||
}
|
}
|
||||||
// 判断是否加入节点控制,优先获取缓存信息
|
// 判断是否加入节点控制,优先获取缓存信息
|
||||||
@@ -106,9 +107,30 @@ class AuthService
|
|||||||
if (in_array($node, $this->adminNode)) {
|
if (in_array($node, $this->adminNode)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if ($this->checkNodeAnnotationAttrAuth($node)) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function checkNodeAnnotationAttrAuth(string $node): bool
|
||||||
|
{
|
||||||
|
$bool = false;
|
||||||
|
$controller = request()->controller();
|
||||||
|
try {
|
||||||
|
$controllerExplode = explode('.', $controller);
|
||||||
|
[$_name, $_controller] = $controllerExplode;
|
||||||
|
$nodeExplode = explode('/', $node);
|
||||||
|
$action = end($nodeExplode);
|
||||||
|
$reflectionClass = new \ReflectionClass("app\admin\controller\\{$_name}\\{$_controller}");
|
||||||
|
$attributes = $reflectionClass->getMethod($action)->getAttributes(NodeAnnotation::class);
|
||||||
|
foreach ($attributes as $attribute) {
|
||||||
|
$annotation = $attribute->newInstance();
|
||||||
|
$bool = $annotation->auth === false;
|
||||||
|
}
|
||||||
|
}catch (\Throwable) {
|
||||||
|
}
|
||||||
|
return $bool;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前节点
|
* 获取当前节点
|
||||||
* @return string
|
* @return string
|
||||||
@@ -130,25 +152,25 @@ class AuthService
|
|||||||
{
|
{
|
||||||
$nodeList = [];
|
$nodeList = [];
|
||||||
$adminInfo = Db::name($this->config['system_admin'])
|
$adminInfo = Db::name($this->config['system_admin'])
|
||||||
->where([
|
->where([
|
||||||
'id' => $this->adminId,
|
'id' => $this->adminId,
|
||||||
'status' => 1,
|
'status' => 1,
|
||||||
])->find();
|
])->find();
|
||||||
if (!empty($adminInfo) && !empty($adminInfo['auth_ids'])) {
|
if (!empty($adminInfo) && !empty($adminInfo['auth_ids'])) {
|
||||||
$buildAuthSql = Db::name($this->config['system_auth'])
|
$buildAuthSql = Db::name($this->config['system_auth'])
|
||||||
->distinct(true)
|
->distinct(true)
|
||||||
->whereIn('id', $adminInfo['auth_ids'])
|
->whereIn('id', $adminInfo['auth_ids'])
|
||||||
->field('id')
|
->field('id')
|
||||||
->buildSql(true);
|
->buildSql(true);
|
||||||
$buildAuthNodeSql = Db::name($this->config['system_auth_node'])
|
$buildAuthNodeSql = Db::name($this->config['system_auth_node'])
|
||||||
->distinct(true)
|
->distinct(true)
|
||||||
->where("auth_id IN {$buildAuthSql}")
|
->where("auth_id IN {$buildAuthSql}")
|
||||||
->field('node_id')
|
->field('node_id')
|
||||||
->buildSql(true);
|
->buildSql(true);
|
||||||
$nodeList = Db::name($this->config['system_node'])
|
$nodeList = Db::name($this->config['system_node'])
|
||||||
->distinct(true)
|
->distinct(true)
|
||||||
->where("id IN {$buildAuthNodeSql}")
|
->where("id IN {$buildAuthNodeSql}")
|
||||||
->column('node');
|
->column('node');
|
||||||
}
|
}
|
||||||
return $nodeList;
|
return $nodeList;
|
||||||
}
|
}
|
||||||
@@ -162,7 +184,7 @@ class AuthService
|
|||||||
public function getNodeList()
|
public function getNodeList()
|
||||||
{
|
{
|
||||||
return Db::name($this->config['system_node'])
|
return Db::name($this->config['system_node'])
|
||||||
->column('id,node,title,type,is_auth', 'node');
|
->column('id,node,title,type,is_auth', 'node');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,13 +199,13 @@ class AuthService
|
|||||||
public function getAdminInfo()
|
public function getAdminInfo()
|
||||||
{
|
{
|
||||||
return Db::name($this->config['system_admin'])
|
return Db::name($this->config['system_admin'])
|
||||||
->where('id', $this->adminId)
|
->where('id', $this->adminId)
|
||||||
->find();
|
->find();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 驼峰转下划线规则
|
* 驼峰转下划线规则
|
||||||
* @param string $node
|
* @param string $node
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function parseNodeStr($node)
|
public function parseNodeStr($node)
|
||||||
|
|||||||
28
app/common/utils/Helper.php
Normal file
28
app/common/utils/Helper.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\common\utils;
|
||||||
|
|
||||||
|
class Helper
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前IP地址
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getIp(): string
|
||||||
|
{
|
||||||
|
return request()->ip();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前登录用户ID
|
||||||
|
* @return int|string
|
||||||
|
*/
|
||||||
|
public static function getAdminUid(): int|string
|
||||||
|
{
|
||||||
|
return session('admin.id') ?: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -24,8 +24,8 @@ class Install extends BaseController
|
|||||||
$errorInfo = '已安装系统,如需重新安装请删除文件:/config/install/lock/install.lock,或者删除 /install 路由';
|
$errorInfo = '已安装系统,如需重新安装请删除文件:/config/install/lock/install.lock,或者删除 /install 路由';
|
||||||
}elseif (version_compare(phpversion(), '8.1.0', '<')) {
|
}elseif (version_compare(phpversion(), '8.1.0', '<')) {
|
||||||
$errorInfo = 'PHP版本不能小于8.1.0';
|
$errorInfo = 'PHP版本不能小于8.1.0';
|
||||||
}elseif (!extension_loaded("PDO")) {
|
}elseif (!extension_loaded("pdo_mysql")) {
|
||||||
$errorInfo = '当前未开启PDO,无法进行安装';
|
$errorInfo = '当前未开启pdo_mysql,无法进行安装';
|
||||||
}
|
}
|
||||||
if (!is_file(root_path() . '.env')) {
|
if (!is_file(root_path() . '.env')) {
|
||||||
$errorInfo = '.env 文件不存在,请先配置 .env 文件';
|
$errorInfo = '.env 文件不存在,请先配置 .env 文件';
|
||||||
@@ -41,7 +41,7 @@ class Install extends BaseController
|
|||||||
];
|
];
|
||||||
$currentHost = '://';
|
$currentHost = '://';
|
||||||
$result = compact('errorInfo', 'currentHost', 'isInstall', 'envInfo');
|
$result = compact('errorInfo', 'currentHost', 'isInstall', 'envInfo');
|
||||||
return view('index/install/index', $result);
|
return view('index@install/index', $result);
|
||||||
}
|
}
|
||||||
if ($errorInfo) $this->error($errorInfo);
|
if ($errorInfo) $this->error($errorInfo);
|
||||||
$charset = 'utf8mb4';
|
$charset = 'utf8mb4';
|
||||||
@@ -105,12 +105,12 @@ class Install extends BaseController
|
|||||||
foreach ($sqlArray as $sql) {
|
foreach ($sqlArray as $sql) {
|
||||||
$pdo->query($sql);
|
$pdo->query($sql);
|
||||||
}
|
}
|
||||||
$_password = password($password);
|
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||||
$tableName = 'system_admin';
|
$tableName = 'system_admin';
|
||||||
$update = [
|
$update = [
|
||||||
'username' => $username,
|
'username' => $username,
|
||||||
'head_img' => '/static/admin/images/head.jpg',
|
'head_img' => '/static/admin/images/head.jpg',
|
||||||
'password' => $_password,
|
'password' => $hashedPassword,
|
||||||
'create_time' => time(),
|
'create_time' => time(),
|
||||||
'update_time' => time()
|
'update_time' => time()
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -22,20 +22,21 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.1.0",
|
"php": ">=8.1.0",
|
||||||
"topthink/framework": "^8.0",
|
"topthink/framework": "^8.0",
|
||||||
"topthink/think-orm": "^3.0",
|
"topthink/think-orm": "^4.0",
|
||||||
"topthink/think-multi-app": "^1.1.0",
|
"topthink/think-multi-app": "^1.1.0",
|
||||||
"topthink/think-view": "2.0.0",
|
"topthink/think-view": "^2.0",
|
||||||
"topthink/think-captcha": "^3.0",
|
"topthink/think-captcha": "^3.0",
|
||||||
"topthink/think-filesystem": "^2.0",
|
"topthink/think-filesystem": "^2.0",
|
||||||
"aliyuncs/oss-sdk-php": "^2.6",
|
"aliyuncs/oss-sdk-php": "^2.7.2",
|
||||||
"qcloud/cos-sdk-v5": "^2.6",
|
"qcloud/cos-sdk-v5": "^2.6",
|
||||||
"jianyan74/php-excel": "^1.0.2",
|
|
||||||
"doctrine/annotations": "^2.0.0",
|
"doctrine/annotations": "^2.0.0",
|
||||||
"phpoffice/phpspreadsheet": "^1.28",
|
"phpoffice/phpspreadsheet": "^4.1.0",
|
||||||
"myclabs/php-enum": "^1.8",
|
"myclabs/php-enum": "^1.8",
|
||||||
"qiniu/php-sdk": "^7.11.0",
|
"wolfcode/qiniu-php-sdk": "^8.0",
|
||||||
"wolf-leo/phplogviewer": "^0.11.3",
|
"wolf-leo/phplogviewer": "^0.11.3",
|
||||||
"wolfcode/authenticator": "^0.0.6",
|
"wolfcode/authenticator": "^0.0.6",
|
||||||
|
"wolfcode/rate-limiting": "^0.1.0",
|
||||||
|
"wolfcode/php-ai": "^0.1.2",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-mysqli": "*",
|
"ext-mysqli": "*",
|
||||||
"ext-pdo": "*"
|
"ext-pdo": "*"
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ CREATE TABLE `ea_system_admin`
|
|||||||
`auth_ids` varchar(255) DEFAULT NULL COMMENT '角色权限ID',
|
`auth_ids` varchar(255) DEFAULT NULL COMMENT '角色权限ID',
|
||||||
`head_img` varchar(255) DEFAULT NULL COMMENT '头像',
|
`head_img` varchar(255) DEFAULT NULL COMMENT '头像',
|
||||||
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户登录名',
|
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户登录名',
|
||||||
`password` char(40) NOT NULL DEFAULT '' COMMENT '用户登录密码',
|
`password` varchar(255) NOT NULL DEFAULT '' COMMENT '用户登录密码',
|
||||||
`phone` varchar(16) DEFAULT NULL COMMENT '联系手机号',
|
`phone` varchar(16) DEFAULT NULL COMMENT '联系手机号',
|
||||||
`remark` varchar(255) DEFAULT '' COMMENT '备注说明',
|
`remark` varchar(255) DEFAULT '' COMMENT '备注说明',
|
||||||
`login_num` bigint(20) unsigned DEFAULT '0' COMMENT '登录次数',
|
`login_num` bigint(20) unsigned DEFAULT '0' COMMENT '登录次数',
|
||||||
@@ -309,7 +309,7 @@ VALUES ('234', '228', '菜单管理', 'fa fa-tree', 'system.menu/index', '', '_s
|
|||||||
INSERT INTO `ea_system_menu`
|
INSERT INTO `ea_system_menu`
|
||||||
VALUES ('244', '228', '管理员管理', 'fa fa-user', 'system.admin/index', '', '_self', '12', '1', '', '1573185011', '1588228573', null);
|
VALUES ('244', '228', '管理员管理', 'fa fa-user', 'system.admin/index', '', '_self', '12', '1', '', '1573185011', '1588228573', null);
|
||||||
INSERT INTO `ea_system_menu`
|
INSERT INTO `ea_system_menu`
|
||||||
VALUES ('245', '228', '角色管理', 'fa fa-bitbucket-square', 'system.auth/index', '', '_self', '11', '1', '', '1573435877', '1588228634', null);
|
VALUES ('245', '228', '角色管理', 'fa fa-square-person-confined', 'system.auth/index', '', '_self', '11', '1', '', '1573435877', '1588228634', null);
|
||||||
INSERT INTO `ea_system_menu`
|
INSERT INTO `ea_system_menu`
|
||||||
VALUES ('246', '228', '节点管理', 'fa fa-list', 'system.node/index', '', '_self', '9', '1', '', '1573435919', '1588228648', null);
|
VALUES ('246', '228', '节点管理', 'fa fa-list', 'system.node/index', '', '_self', '9', '1', '', '1573435919', '1588228648', null);
|
||||||
INSERT INTO `ea_system_menu`
|
INSERT INTO `ea_system_menu`
|
||||||
@@ -319,7 +319,7 @@ VALUES ('248', '228', '上传管理', 'fa fa-arrow-up', 'system.uploadfile/index
|
|||||||
INSERT INTO `ea_system_menu`
|
INSERT INTO `ea_system_menu`
|
||||||
VALUES ('249', '0', '商城管理', 'fa fa-list', '', '', '_self', '0', '1', '', '1589439884', '1589439884', null);
|
VALUES ('249', '0', '商城管理', 'fa fa-list', '', '', '_self', '0', '1', '', '1589439884', '1589439884', null);
|
||||||
INSERT INTO `ea_system_menu`
|
INSERT INTO `ea_system_menu`
|
||||||
VALUES ('250', '249', '商品分类', 'fa fa-calendar-check-o', 'mall.cate/index', '', '_self', '0', '1', '', '1589439910', '1589439966', null);
|
VALUES ('250', '249', '商品分类', 'fa fa-calendar-check', 'mall.cate/index', '', '_self', '0', '1', '', '1589439910', '1589439966', null);
|
||||||
INSERT INTO `ea_system_menu`
|
INSERT INTO `ea_system_menu`
|
||||||
VALUES ('251', '249', '商品管理', 'fa fa-list', 'mall.goods/index', '', '_self', '0', '1', '', '1589439931', '1589439942', null);
|
VALUES ('251', '249', '商品管理', 'fa fa-list', 'mall.goods/index', '', '_self', '0', '1', '', '1589439931', '1589439942', null);
|
||||||
INSERT INTO `ea_system_menu`
|
INSERT INTO `ea_system_menu`
|
||||||
@@ -517,7 +517,7 @@ CREATE TABLE `ea_system_quick`
|
|||||||
INSERT INTO `ea_system_quick`
|
INSERT INTO `ea_system_quick`
|
||||||
VALUES ('1', '管理员管理', 'fa fa-user', 'system.admin/index', '0', '1', '', '1589624097', '1589624792', null);
|
VALUES ('1', '管理员管理', 'fa fa-user', 'system.admin/index', '0', '1', '', '1589624097', '1589624792', null);
|
||||||
INSERT INTO `ea_system_quick`
|
INSERT INTO `ea_system_quick`
|
||||||
VALUES ('2', '角色管理', 'fa fa-bitbucket-square', 'system.auth/index', '0', '1', '', '1589624772', '1589624781', null);
|
VALUES ('2', '角色管理', 'fa fa-square-person-confined', 'system.auth/index', '0', '1', '', '1589624772', '1589624781', null);
|
||||||
INSERT INTO `ea_system_quick`
|
INSERT INTO `ea_system_quick`
|
||||||
VALUES ('3', '菜单管理', 'fa fa-tree', 'system.menu/index', '0', '1', null, '1589624097', '1589624792', null);
|
VALUES ('3', '菜单管理', 'fa fa-tree', 'system.menu/index', '0', '1', null, '1589624097', '1589624792', null);
|
||||||
INSERT INTO `ea_system_quick`
|
INSERT INTO `ea_system_quick`
|
||||||
@@ -527,7 +527,7 @@ VALUES ('7', '配置管理', 'fa fa-asterisk', 'system.config/index', '0', '1',
|
|||||||
INSERT INTO `ea_system_quick`
|
INSERT INTO `ea_system_quick`
|
||||||
VALUES ('8', '上传管理', 'fa fa-arrow-up', 'system.uploadfile/index', '0', '1', null, '1589624772', '1589624781', null);
|
VALUES ('8', '上传管理', 'fa fa-arrow-up', 'system.uploadfile/index', '0', '1', null, '1589624772', '1589624781', null);
|
||||||
INSERT INTO `ea_system_quick`
|
INSERT INTO `ea_system_quick`
|
||||||
VALUES ('10', '商品分类', 'fa fa-calendar-check-o', 'mall.cate/index', '0', '1', null, '1589624097', '1589624792', null);
|
VALUES ('10', '商品分类', 'fa fa-calendar-check', 'mall.cate/index', '0', '1', null, '1589624097', '1589624792', null);
|
||||||
INSERT INTO `ea_system_quick`
|
INSERT INTO `ea_system_quick`
|
||||||
VALUES ('11', '商品管理', 'fa fa-list', 'mall.goods/index', '0', '1', null, '1589624772', '1589624781', null);
|
VALUES ('11', '商品管理', 'fa fa-list', 'mall.goods/index', '0', '1', null, '1589624772', '1589624781', null);
|
||||||
|
|
||||||
@@ -571,3 +571,22 @@ INSERT INTO `ea_system_uploadfile`
|
|||||||
VALUES ('290', 'oss', 'image/jpeg', 'https://lxn-99php.oss-cn-shenzhen.aliyuncs.com/upload/20191111/2c412adf1b30c8be3a913e603c7b6e4a.jpg', '', '', '', '0', 'image/jpeg', '0', 'jpg', '', 1573612437, null, null);
|
VALUES ('290', 'oss', 'image/jpeg', 'https://lxn-99php.oss-cn-shenzhen.aliyuncs.com/upload/20191111/2c412adf1b30c8be3a913e603c7b6e4a.jpg', '', '', '', '0', 'image/jpeg', '0', 'jpg', '', 1573612437, null, null);
|
||||||
INSERT INTO `ea_system_uploadfile`
|
INSERT INTO `ea_system_uploadfile`
|
||||||
VALUES ('296', 'cos', 'image/jpeg', 'https://easyadmin-1251997243.cos.ap-guangzhou.myqcloud.com/upload/20191114/2381eaf81208ac188fa994b6f2579953.jpg', '', '', '', '0', 'image/jpeg', '0', 'jpg', '', 1573612437, null, null);
|
VALUES ('296', 'cos', 'image/jpeg', 'https://easyadmin-1251997243.cos.ap-guangzhou.myqcloud.com/upload/20191114/2381eaf81208ac188fa994b6f2579953.jpg', '', '', '', '0', 'image/jpeg', '0', 'jpg', '', 1573612437, null, null);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for ea_system_log
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ea_system_log`;
|
||||||
|
CREATE TABLE `ea_system_log`
|
||||||
|
(
|
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||||
|
`admin_id` int unsigned DEFAULT '0' COMMENT '管理员ID',
|
||||||
|
`url` varchar(1500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '操作页面',
|
||||||
|
`method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '请求方法',
|
||||||
|
`title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '日志标题',
|
||||||
|
`content` json NOT NULL COMMENT '请求数据',
|
||||||
|
`response` json DEFAULT NULL COMMENT '回调数据',
|
||||||
|
`ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP',
|
||||||
|
`useragent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'User-Agent',
|
||||||
|
`create_time` int DEFAULT NULL COMMENT '操作时间',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='后台操作日志表 - 202412';
|
||||||
|
|||||||
2
log.md
2
log.md
@@ -1,3 +1,5 @@
|
|||||||
|
> 2025年03月27日 重构了 `model` 的调用方式 原因查看 [https://github.com/top-think/think-orm/issues/704](https://github.com/top-think/think-orm/issues/704)
|
||||||
|
>
|
||||||
> 2025年01月01日 `PHP` 要求升级到 `8.1+`
|
> 2025年01月01日 `PHP` 要求升级到 `8.1+`
|
||||||
>
|
>
|
||||||
> 2024年05月 更新 `EasyAdmin8` 重置版,多处语法、写法进行变更
|
> 2024年05月 更新 `EasyAdmin8` 重置版,多处语法、写法进行变更
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
@import url("../../plugs/layui-v2.x/css/layui.css");
|
@import url("../../plugs/layui-v2.x/css/layui.css");
|
||||||
@import url("../../plugs/font-awesome-4.7.0/css/font-awesome.min.css");
|
@import url("../../plugs/font-awesome-6.x/css/all.min.css");
|
||||||
@import url("../css/color.css");
|
@import url("../css/color.css");
|
||||||
@import url("../css/themes/index.css");
|
@import url("../css/themes/index.css");
|
||||||
@import url("../css/iconfont.css");
|
@import url("../css/iconfont.css");
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--ea8-theme-main-color: #16b777;
|
||||||
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
@@ -75,8 +79,8 @@ body {
|
|||||||
|
|
||||||
/**重写layui表格自适应*/
|
/**重写layui表格自适应*/
|
||||||
.layuimini-container .layui-table-cell {
|
.layuimini-container .layui-table-cell {
|
||||||
height: 100%;
|
height: 50px;
|
||||||
max-width: 100%;
|
line-height: 42px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**数据表格-搜索表单样式*/
|
/**数据表格-搜索表单样式*/
|
||||||
@@ -304,9 +308,17 @@ table样式
|
|||||||
}
|
}
|
||||||
|
|
||||||
.layui-form-select dl {
|
.layui-form-select dl {
|
||||||
border: 1px #16b777 solid;
|
border: 1px var(--ea8-theme-main-color) solid;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
z-index: 99999;
|
z-index: 99999;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layui-form-select dl dd.layui-this {
|
||||||
|
background-color: var(--ea8-theme-main-color);
|
||||||
|
border-top: none;
|
||||||
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-search .layui-form-select dl {
|
.form-search .layui-form-select dl {
|
||||||
@@ -518,3 +530,11 @@ table样式
|
|||||||
z-index: 99999;
|
z-index: 99999;
|
||||||
border: 1px solid var(--w-e-textarea-slight-border-color);
|
border: 1px solid var(--w-e-textarea-slight-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-input:focus, .layui-textarea:focus {
|
||||||
|
border-color: var(--ea8-theme-main-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layui-tabs-item {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
@@ -140,6 +140,39 @@ define(["jquery", "easy-admin", "echarts", "echarts-theme", "miniAdmin", "miniTh
|
|||||||
echartsRecords.resize();
|
echartsRecords.resize();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let util = layui.util;
|
||||||
|
util.on({
|
||||||
|
showComposerInfo: function () {
|
||||||
|
// <div style="padding: 25px;">12313</div>
|
||||||
|
let html = ``
|
||||||
|
ea.request.get({
|
||||||
|
url: ea.url('ajax/composerInfo'),
|
||||||
|
}, function (success) {
|
||||||
|
let data = success.data
|
||||||
|
data.forEach(function (item) {
|
||||||
|
html += `${item.name} ${item.version}\r\n`
|
||||||
|
})
|
||||||
|
html = `<pre class="layui-code code-demo">${html}</pre>`
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: 'composer 信息',
|
||||||
|
area: ['50%', '90%'],
|
||||||
|
shade: 0.8,
|
||||||
|
shadeClose: true,
|
||||||
|
scrollbar: false,
|
||||||
|
content: html,
|
||||||
|
success: function () {
|
||||||
|
layui.code({elem: '.code-demo', theme: 'dark', lang: 'php'});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, function (error) {
|
||||||
|
console.error(error)
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
editAdmin: function () {
|
editAdmin: function () {
|
||||||
let form = layui.form
|
let form = layui.form
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function (event) {
|
||||||
|
if (event.key === 'Enter' || event.keyCode === 13) {
|
||||||
|
$('.login-btn').trigger('click')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('.login-tip').on('click', function () {
|
$('.login-tip').on('click', function () {
|
||||||
$('.icon-nocheck').click();
|
$('.icon-nocheck').click();
|
||||||
});
|
});
|
||||||
@@ -40,7 +46,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
})
|
})
|
||||||
}, function (res) {
|
}, function (res) {
|
||||||
let data = res.data
|
let data = res.data
|
||||||
if (data.is_ga_code) {
|
if (data?.is_ga_code || false) {
|
||||||
let elem = $('#gaCode')
|
let elem = $('#gaCode')
|
||||||
elem.removeClass('layui-hide');
|
elem.removeClass('layui-hide');
|
||||||
elem.find('input').focus()
|
elem.find('input').focus()
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
export_url: 'mall.goods/export',
|
export_url: 'mall.goods/export',
|
||||||
modify_url: 'mall.goods/modify',
|
modify_url: 'mall.goods/modify',
|
||||||
stock_url: 'mall.goods/stock',
|
stock_url: 'mall.goods/stock',
|
||||||
|
recycle_url: 'mall.goods/recycle',
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -27,14 +28,14 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
icon: 'fa fa-plus ',
|
icon: 'fa fa-plus ',
|
||||||
extend: 'data-width="90%" data-height="95%"',
|
extend: 'data-width="90%" data-height="95%"',
|
||||||
}],
|
}],
|
||||||
'delete', 'export'],
|
'delete', 'export', 'recycle'],
|
||||||
cols: [[
|
cols: [[
|
||||||
{type: "checkbox"},
|
{type: "checkbox"},
|
||||||
{field: 'id', width: 80, title: 'ID', searchOp: '='},
|
{field: 'id', width: 80, title: 'ID', searchOp: '='},
|
||||||
{field: 'sort', width: 80, title: '排序', edit: 'text'},
|
{field: 'sort', width: 80, title: '排序', edit: 'text'},
|
||||||
{field: 'cate_id', minWidth: 80, title: '商品分类', search: 'select', selectList: cateSelects, laySearch: true},
|
{field: 'cate_id', width: 100, title: '商品分类', search: 'select', selectList: cateSelects, laySearch: true},
|
||||||
{field: 'title', minWidth: 80, title: '商品名称'},
|
{field: 'title', width: 100, title: '商品名称'},
|
||||||
{field: 'logo', minWidth: 80, title: '分类图片', search: false, templet: ea.table.image},
|
{field: 'logo', width: 100, title: '分类图片', search: false, templet: ea.table.image},
|
||||||
{field: 'market_price', width: 100, title: '市场价', templet: ea.table.price},
|
{field: 'market_price', width: 100, title: '市场价', templet: ea.table.price},
|
||||||
{field: 'discount_price', width: 100, title: '折扣价', templet: ea.table.price},
|
{field: 'discount_price', width: 100, title: '折扣价', templet: ea.table.price},
|
||||||
{field: 'total_stock', width: 100, title: '库存统计'},
|
{field: 'total_stock', width: 100, title: '库存统计'},
|
||||||
@@ -44,7 +45,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
{field: 'status', title: '状态', width: 85, selectList: {0: '禁用', 1: '启用'}, templet: ea.table.switch},
|
{field: 'status', title: '状态', width: 85, selectList: {0: '禁用', 1: '启用'}, templet: ea.table.switch},
|
||||||
// 演示多选,实际数据库并无 status2 字段,搜索后会报错
|
// 演示多选,实际数据库并无 status2 字段,搜索后会报错
|
||||||
{
|
{
|
||||||
field: 'status2', title: '演示多选', width: 105, search: 'xmSelect', selectList: {1: '模拟选项1', 2: '模拟选项2', 3: '模拟选项3', 4: '模拟选项4', 5: '模拟选项5'},
|
field: 'status2', title: '演示多选', width: 105, search: 'xmSelect', selectList: {1: '模拟选项1', 2: '模拟选项2', 3: '模拟选项3', 4: '模拟选项4', 5: '模拟选项5'}, hide: true,
|
||||||
searchOp: 'in', templet: function (res) {
|
searchOp: 'in', templet: function (res) {
|
||||||
// 根据自己实际项目进行输出
|
// 根据自己实际项目进行输出
|
||||||
return res?.status2 || '模拟数据'
|
return res?.status2 || '模拟数据'
|
||||||
@@ -80,18 +81,167 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
'delete']
|
'delete']
|
||||||
}
|
}
|
||||||
]],
|
]],
|
||||||
|
done: (res) => {
|
||||||
|
// 状态为1的商品背景高亮 展示写法 可根据自己项目自定义
|
||||||
|
$.each(res.data, function (idx, item) {
|
||||||
|
if (item.status === 1) {
|
||||||
|
$(`tr[data-index="${idx}"]`).css({
|
||||||
|
'background': 'linear-gradient(to left, #77eb7c, #bbffbe, #ffffff, transparent)',
|
||||||
|
'border': 'none',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ea.listen();
|
ea.listen();
|
||||||
},
|
},
|
||||||
add: function () {
|
add: function () {
|
||||||
|
layui.util.on({
|
||||||
|
AiOptimization: function (data) {
|
||||||
|
let layOn = $(data).attr('lay-on')
|
||||||
|
$(data).attr('lay-on', layOn + 'Loading')
|
||||||
|
aiOptimization(data)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var demo1 = xmSelect.render({
|
||||||
|
el: '#demo1',
|
||||||
|
name: 'xxx', // form表单提交的name
|
||||||
|
theme: {color: getComputedStyle(document.documentElement).getPropertyValue('--ea8-theme-main-color') || '#16b777'},
|
||||||
|
data: [
|
||||||
|
{name: 'Make', value: 1},
|
||||||
|
{name: 'PHP', value: 2},
|
||||||
|
{name: 'Great Again', value: 3},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
ea.listen();
|
ea.listen();
|
||||||
},
|
},
|
||||||
edit: function () {
|
edit: function () {
|
||||||
|
layui.util.on({
|
||||||
|
AiOptimization: function (data) {
|
||||||
|
let layOn = $(data).attr('lay-on')
|
||||||
|
$(data).attr('lay-on', layOn + 'Loading')
|
||||||
|
aiOptimization(data)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var demo1 = xmSelect.render({
|
||||||
|
el: '#demo1',
|
||||||
|
name: 'xxx', // form表单提交的name
|
||||||
|
theme: {color: getComputedStyle(document.documentElement).getPropertyValue('--ea8-theme-main-color') || '#16b777'},
|
||||||
|
data: [
|
||||||
|
{name: 'Make', value: 1},
|
||||||
|
{name: 'PHP', value: 2, selected: true,},
|
||||||
|
{name: 'Great Again', value: 3, selected: true,},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
ea.listen();
|
ea.listen();
|
||||||
},
|
},
|
||||||
stock: function () {
|
stock: function () {
|
||||||
ea.listen();
|
ea.listen();
|
||||||
},
|
},
|
||||||
|
recycle: function () {
|
||||||
|
init.index_url = init.recycle_url;
|
||||||
|
ea.table.render({
|
||||||
|
init: init,
|
||||||
|
toolbar: ['refresh',
|
||||||
|
[{
|
||||||
|
class: 'layui-btn layui-btn-sm',
|
||||||
|
method: 'get',
|
||||||
|
field: 'id',
|
||||||
|
icon: 'fa fa-refresh',
|
||||||
|
text: '全部恢复',
|
||||||
|
title: '确定恢复?',
|
||||||
|
auth: 'recycle',
|
||||||
|
url: init.recycle_url + '?type=restore',
|
||||||
|
checkbox: true
|
||||||
|
}, {
|
||||||
|
class: 'layui-btn layui-btn-danger layui-btn-sm',
|
||||||
|
method: 'get',
|
||||||
|
field: 'id',
|
||||||
|
icon: 'fa fa-delete',
|
||||||
|
text: '彻底删除',
|
||||||
|
title: '确定彻底删除?',
|
||||||
|
auth: 'recycle',
|
||||||
|
url: init.recycle_url + '?type=delete',
|
||||||
|
checkbox: true
|
||||||
|
}], 'export',
|
||||||
|
],
|
||||||
|
cols: [[
|
||||||
|
{type: "checkbox"},
|
||||||
|
{field: 'id', width: 80, title: 'ID', searchOp: '='},
|
||||||
|
{field: 'sort', width: 80, title: '排序', edit: 'text'},
|
||||||
|
{field: 'cate_id', minWidth: 80, title: '商品分类', search: 'select', selectList: cateSelects, laySearch: true},
|
||||||
|
{field: 'title', minWidth: 80, title: '商品名称'},
|
||||||
|
{field: 'logo', minWidth: 80, title: '分类图片', search: false, templet: ea.table.image},
|
||||||
|
{field: 'status', title: '状态', width: 85, selectList: {0: '禁用', 1: '启用'}},
|
||||||
|
// 演示多选,实际数据库并无 status2 字段,搜索后会报错
|
||||||
|
{
|
||||||
|
field: 'status2', title: '演示多选', width: 105, search: 'xmSelect', selectList: {1: '模拟选项1', 2: '模拟选项2', 3: '模拟选项3', 4: '模拟选项4', 5: '模拟选项5'}, hide: true,
|
||||||
|
searchOp: 'in', templet: function (res) {
|
||||||
|
// 根据自己实际项目进行输出
|
||||||
|
return res?.status2 || '模拟数据'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'create_time', minWidth: 80, title: '创建时间', search: 'range'},
|
||||||
|
{field: 'delete_time', minWidth: 80, title: '删除时间', search: 'range'},
|
||||||
|
{
|
||||||
|
width: 250,
|
||||||
|
title: '操作',
|
||||||
|
templet: ea.table.tool,
|
||||||
|
operat: [
|
||||||
|
[{
|
||||||
|
title: '确认恢复?',
|
||||||
|
text: '恢复数据',
|
||||||
|
filed: 'id',
|
||||||
|
url: init.recycle_url + '?type=restore',
|
||||||
|
method: 'get',
|
||||||
|
auth: 'recycle',
|
||||||
|
class: 'layui-btn layui-btn-xs layui-btn-success',
|
||||||
|
}, {
|
||||||
|
title: '想好了吗?',
|
||||||
|
text: '彻底删除',
|
||||||
|
filed: 'id',
|
||||||
|
method: 'get',
|
||||||
|
url: init.recycle_url + '?type=delete',
|
||||||
|
auth: 'recycle',
|
||||||
|
class: 'layui-btn layui-btn-xs layui-btn-normal layui-bg-red',
|
||||||
|
}]]
|
||||||
|
}
|
||||||
|
]],
|
||||||
|
});
|
||||||
|
ea.listen();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function aiOptimization(data) {
|
||||||
|
let layOn = $(data).attr('lay-on')
|
||||||
|
let title = $('input[name="title"]').val()
|
||||||
|
|
||||||
|
// 告诉AI 你需要做什么
|
||||||
|
let message = `优化这个标题 ${title}`
|
||||||
|
|
||||||
|
if ($.trim(title) === '') {
|
||||||
|
ea.msg.error('标题不能为空', function () {
|
||||||
|
$(data).attr('lay-on', layOn.split('Loading')[0])
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let url = ea.url('mall.goods/aiOptimization')
|
||||||
|
ea.request.post({url: url, data: {message: message}}, function (res) {
|
||||||
|
let content = res.data?.choices[0]?.message?.content
|
||||||
|
// stream 为true 时,AI 内容会逐字输出
|
||||||
|
let stream = true
|
||||||
|
ea.ai.chat(content, {stream: stream}, function () {
|
||||||
|
$(data).attr('lay-on', layOn.split('Loading')[0])
|
||||||
|
})
|
||||||
|
}, function (error) {
|
||||||
|
ea.msg.error(error.msg, function () {
|
||||||
|
$(data).attr('lay-on', layOn.split('Loading')[0])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
});
|
});
|
||||||
@@ -16,7 +16,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
|
|
||||||
index: function () {
|
index: function () {
|
||||||
|
|
||||||
ea.table.render({
|
let _table = ea.table.render({
|
||||||
init: init,
|
init: init,
|
||||||
cols: [[
|
cols: [[
|
||||||
{type: "checkbox"},
|
{type: "checkbox"},
|
||||||
@@ -26,6 +26,16 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
{field: 'head_img', minWidth: 80, title: '头像', search: false, templet: ea.table.image},
|
{field: 'head_img', minWidth: 80, title: '头像', search: false, templet: ea.table.image},
|
||||||
{field: 'phone', minWidth: 80, title: '手机'},
|
{field: 'phone', minWidth: 80, title: '手机'},
|
||||||
{field: 'login_num', minWidth: 80, title: '登录次数'},
|
{field: 'login_num', minWidth: 80, title: '登录次数'},
|
||||||
|
{
|
||||||
|
field: 'role', minWidth: 80, title: '角色权限', align: 'left', search: 'none', templet: function (d) {
|
||||||
|
let auth_ids = d.auth_ids || []
|
||||||
|
let html = ``
|
||||||
|
$.each(auth_ids, (idx, item) =>
|
||||||
|
html += `<span class="layui-badge">${auth_list[item] || '-'}</span> `
|
||||||
|
)
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
},
|
||||||
{field: 'remark', minWidth: 80, title: '备注信息'},
|
{field: 'remark', minWidth: 80, title: '备注信息'},
|
||||||
{field: 'status', title: '状态', width: 85, search: 'select', selectList: {0: '禁用', 1: '启用'}, templet: ea.table.switch},
|
{field: 'status', title: '状态', width: 85, search: 'select', selectList: {0: '禁用', 1: '启用'}, templet: ea.table.switch},
|
||||||
{field: 'create_time', minWidth: 80, title: '创建时间', search: 'range'},
|
{field: 'create_time', minWidth: 80, title: '创建时间', search: 'range'},
|
||||||
@@ -48,6 +58,25 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
]],
|
]],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('body').on('click', '[data-table-reset]', function () {
|
||||||
|
$('.layui-menu li').removeClass('layui-menu-item-checked').animate(
|
||||||
|
{}, 0, () => $('.layui-menu li:eq(0)').addClass('layui-menu-item-checked')
|
||||||
|
)
|
||||||
|
})
|
||||||
|
layui.util.on({
|
||||||
|
authSearch: function (e) {
|
||||||
|
let auth_id = $(this).data('auth_id')
|
||||||
|
$('.layui-menu li').removeClass('layui-menu-item-checked').animate(
|
||||||
|
{}, 0, () => $(this).parents('li').addClass('layui-menu-item-checked')
|
||||||
|
)
|
||||||
|
let _where = auth_id ? {
|
||||||
|
filter: JSON.stringify({auth_ids: auth_id}),
|
||||||
|
op: JSON.stringify({auth_ids: 'find_in_set'})
|
||||||
|
} : {}
|
||||||
|
_table.reload({where: _where})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
ea.listen();
|
ea.listen();
|
||||||
},
|
},
|
||||||
add: function () {
|
add: function () {
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
define(["jquery", "easy-admin", "vue"], function ($, ea, Vue) {
|
define(["jquery", "easy-admin"], function ($, ea) {
|
||||||
|
|
||||||
var form = layui.form;
|
var form = layui.form;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
index: function () {
|
index: function () {
|
||||||
var _group = 'site'
|
var _group = 'site'
|
||||||
var element = layui.element;
|
let tabs = layui.tabs
|
||||||
element.on('tab(docDemoTabBrief)', function (data) {
|
var TABS_ID = 'docDemoTabBrief';
|
||||||
|
tabs.on(`afterChange(${TABS_ID})`, function (data) {
|
||||||
_group = $(this).data('group')
|
_group = $(this).data('group')
|
||||||
});
|
})
|
||||||
|
|
||||||
let _upload_type = upload_type || 'local'
|
let _upload_type = upload_type || 'local'
|
||||||
$('.upload_type').addClass('layui-hide')
|
$('.upload_type').addClass('layui-hide')
|
||||||
$('.' + _upload_type).removeClass('layui-hide')
|
$('.' + _upload_type).removeClass('layui-hide')
|
||||||
@@ -20,12 +20,15 @@ define(["jquery", "easy-admin", "vue"], function ($, ea, Vue) {
|
|||||||
$('.' + _upload_type).removeClass('layui-hide')
|
$('.' + _upload_type).removeClass('layui-hide')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
form.on("submit", function (data) {
|
form.on("submit", function (data) {
|
||||||
data.field['group'] = _group
|
data.field['group'] = _group
|
||||||
});
|
});
|
||||||
|
|
||||||
ea.listen();
|
ea.listen('', function (res) {
|
||||||
|
ea.msg.success(res.msg);
|
||||||
|
}, function (err) {
|
||||||
|
ea.msg.error(err.msg);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -18,7 +18,7 @@ define(["jquery", "easy-admin", "miniTab"], function ($, ea, miniTab) {
|
|||||||
<fieldset class="layui-elem-field">
|
<fieldset class="layui-elem-field">
|
||||||
<legend>提示</legend>
|
<legend>提示</legend>
|
||||||
<div class="layui-field-box">
|
<div class="layui-field-box">
|
||||||
<p><a class="layui-font-blue" target="_blank" rel="nofollow" href="https://edocs.easyadmin8.top/curd/command.html">命令可查询文档</a></p>
|
<p><a class="layui-font-blue" target="_blank" rel="nofollow" href="https://edocs.easyadmin8.top/#/md/curd/command">命令可查询文档</a></p>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<form class="layui-form layui-form-pane" action="">
|
<form class="layui-form layui-form-pane" action="">
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
table_render_id: 'currentTableRenderId',
|
table_render_id: 'currentTableRenderId',
|
||||||
index_url: 'system.log/index',
|
index_url: 'system.log/index',
|
||||||
export_url: 'system.log/export',
|
export_url: 'system.log/export',
|
||||||
|
deleteMonthLog_url: 'system.log/deleteMonthLog',
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -23,8 +24,15 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
class: 'layui-btn layui-btn-sm',
|
class: 'layui-btn layui-btn-sm',
|
||||||
icon: 'fa fa-book',
|
icon: 'fa fa-book',
|
||||||
extend: 'data-width="95%" data-height="95%"'
|
extend: 'data-width="95%" data-height="95%"'
|
||||||
},
|
}, {
|
||||||
]
|
text: '删除部分日志',
|
||||||
|
url: 'system.log/deleteMonthLog',
|
||||||
|
method: 'open',
|
||||||
|
auth: 'deleteMonthLog',
|
||||||
|
class: 'layui-btn layui-btn-sm layui-btn-danger',
|
||||||
|
icon: 'fa fa-remove',
|
||||||
|
extend: 'data-width="35%" data-height="42%"'
|
||||||
|
},]
|
||||||
],
|
],
|
||||||
cols: [[
|
cols: [[
|
||||||
{field: 'id', width: 80, title: 'ID', search: false},
|
{field: 'id', width: 80, title: 'ID', search: false},
|
||||||
@@ -43,7 +51,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
field: 'content', minWidth: 200, title: '请求数据', align: "left", templet: function (res) {
|
field: 'content', minWidth: 200, title: '请求数据', align: "left", templet: function (res) {
|
||||||
let html = '<div class="layui-colla-item">' +
|
let html = '<div class="layui-colla-item">' +
|
||||||
'<div class="layui-colla-title">点击预览</div>' +
|
'<div class="layui-colla-title">点击预览</div>' +
|
||||||
'<div class="layui-colla-content">' + prettyFormat(res.content) + '</div>' +
|
'<div class="layui-colla-content">' + prettyFormat(JSON.stringify(res.content)) + '</div>' +
|
||||||
'</div>'
|
'</div>'
|
||||||
return '<div class="layui-collapse" lay-accordion>' + html + '</div>'
|
return '<div class="layui-collapse" lay-accordion>' + html + '</div>'
|
||||||
}
|
}
|
||||||
@@ -52,7 +60,7 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
field: 'response', minWidth: 200, title: '回调数据', align: "left", templet: function (res) {
|
field: 'response', minWidth: 200, title: '回调数据', align: "left", templet: function (res) {
|
||||||
let html = '<div class="layui-colla-item">' +
|
let html = '<div class="layui-colla-item">' +
|
||||||
'<div class="layui-colla-title">点击预览</div>' +
|
'<div class="layui-colla-title">点击预览</div>' +
|
||||||
'<div class="layui-colla-content">' + prettyFormat(res.response) + '</div>' +
|
'<div class="layui-colla-content">' + prettyFormat(JSON.stringify(res.response)) + '</div>' +
|
||||||
'</div>'
|
'</div>'
|
||||||
return '<div class="layui-collapse" lay-accordion>' + html + '</div>'
|
return '<div class="layui-collapse" lay-accordion>' + html + '</div>'
|
||||||
}
|
}
|
||||||
@@ -65,5 +73,20 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
});
|
});
|
||||||
ea.listen();
|
ea.listen();
|
||||||
},
|
},
|
||||||
|
deleteMonthLog: function () {
|
||||||
|
layui.form.on('submit(submit)', function (data) {
|
||||||
|
let field = data.field
|
||||||
|
let options = {
|
||||||
|
url: ea.url(init.deleteMonthLog_url),
|
||||||
|
data: field,
|
||||||
|
}
|
||||||
|
ea.msg.confirm('确认执行该操作?重要数据请先做好相关备份!', function () {
|
||||||
|
ea.request.post(options, function (rs) {
|
||||||
|
let msg = rs.msg || '未知~'
|
||||||
|
layer.msg(msg.replace(/\n/g, '<br>'), {shade: 0.3, shadeClose: true, time: 2000})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -121,6 +121,22 @@ define(["jquery", "easy-admin", "treetable", "iconPickerFa", "autocomplete"], fu
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('body').on('click', '[data-treetable-arrow]', function () {
|
||||||
|
const $icon = $(this).find('i');
|
||||||
|
const $textNode = $icon[0].nextSibling;
|
||||||
|
if ($icon.hasClass('fa-arrow-up')) {
|
||||||
|
treetable.foldAll(init.table_elem);
|
||||||
|
$icon.removeClass('fa-arrow-up').addClass('fa-arrow-down');
|
||||||
|
$textNode.textContent = ' 一键展开';
|
||||||
|
$(this).attr('data-arrow', 'down');
|
||||||
|
} else {
|
||||||
|
treetable.expandAll(init.table_elem);
|
||||||
|
$icon.removeClass('fa-arrow-down').addClass('fa-arrow-up');
|
||||||
|
$textNode.textContent = ' 一键折叠';
|
||||||
|
$(this).attr('data-arrow', 'up');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
ea.table.listenSwitch({filter: 'status', url: init.modify_url});
|
ea.table.listenSwitch({filter: 'status', url: init.modify_url});
|
||||||
|
|
||||||
ea.table.listenEdit(init, 'currentTable', init.table_render_id, true);
|
ea.table.listenEdit(init, 'currentTable', init.table_render_id, true);
|
||||||
|
|||||||
@@ -49,7 +49,11 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
|||||||
}
|
}
|
||||||
]],
|
]],
|
||||||
cols: [[
|
cols: [[
|
||||||
{field: 'node', minWidth: 200, align: 'left', title: '系统节点'},
|
{
|
||||||
|
field: 'node', minWidth: 200, align: 'left', title: '系统节点', templet: function (d) {
|
||||||
|
return `<span>${d.node}</span>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
{field: 'title', minWidth: 80, title: '节点名称 <i class="table-edit-tips color-red">*</i>', edit: 'text'},
|
{field: 'title', minWidth: 80, title: '节点名称 <i class="table-edit-tips color-red">*</i>', edit: 'text'},
|
||||||
{field: 'update_time', minWidth: 80, title: '更新时间', search: 'range'},
|
{field: 'update_time', minWidth: 80, title: '更新时间', search: 'range'},
|
||||||
{field: 'is_auth', title: '节点控制', width: 85, search: 'select', selectList: {0: '禁用', 1: '启用'}, templet: ea.table.switch},
|
{field: 'is_auth', title: '节点控制', width: 85, search: 'select', selectList: {0: '禁用', 1: '启用'}, templet: ea.table.switch},
|
||||||
|
|||||||
BIN
public/static/common/images/loading.gif
Normal file
BIN
public/static/common/images/loading.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
@@ -155,3 +155,45 @@ function prettyFormat(str) {
|
|||||||
}
|
}
|
||||||
return "<pre>" + result + "</pre>"
|
return "<pre>" + result + "</pre>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self === top) {
|
||||||
|
console.group('温馨提示');
|
||||||
|
console.log(`%c
|
||||||
|
|
||||||
|
▄▄ ▄▄
|
||||||
|
▀███▀▀▀███ ██ ▀███ ██ ▄█▄▀▄██▄
|
||||||
|
██ ▀█ ▄██▄ ██ ██ ██
|
||||||
|
██ █ ▄█▀██▄ ▄██▀█████▀ ▀██▀ ▄█▀██▄ ▄█▀▀███ ▀████████▄█████▄ ▀███ ▀████████▄ ▀██▄ ▄▄█
|
||||||
|
██████ ██ ██ ██ ▀▀ ██ ▄█ ▄█ ▀██ ▄██ ██ ██ ██ ██ ██ ██ ██ ▄█████▄
|
||||||
|
██ █ ▄▄█████ ▀█████▄ ██ ▄█ ████████ ███ ██ ██ ██ ██ ██ ██ ██ ██ ▀███
|
||||||
|
██ ▄██ ██ █▄ ██ ███ █▀ ██ ▀██ ██ ██ ██ ██ ██ ██ ██ ██ ▀██
|
||||||
|
▄██████████████▀██▄██████▀ ▄█ ▄███▄ ▄████▄ ▀████▀███▄████ ████ ████▄████▄████ ████▄███████
|
||||||
|
▄█
|
||||||
|
██▀
|
||||||
|
%c
|
||||||
|
|
||||||
|
官方网站:https://easyadmin8.top
|
||||||
|
|
||||||
|
官方文档:https://edocs.easyadmin8.top
|
||||||
|
|
||||||
|
问答社区:https://meta.easyadmin8.top
|
||||||
|
|
||||||
|
%c重要事情说3遍:
|
||||||
|
%c
|
||||||
|
常见问题:https://easyadmin8.top/guide/question.html
|
||||||
|
|
||||||
|
常见问题:https://easyadmin8.top/guide/question.html
|
||||||
|
|
||||||
|
常见问题:https://easyadmin8.top/guide/question.html
|
||||||
|
|
||||||
|
%c遇到问题先把 DEBUG 模式打开,然后把错误信息找出来,当不能解决的时候再去社区提问或者QQ群交流
|
||||||
|
`,
|
||||||
|
"color:#4290f7;font-weight:bold;font-size:10px;",
|
||||||
|
"color:#5672cd;",
|
||||||
|
"color:#ff5722;font-weight:bold;font-size:1rem;",
|
||||||
|
"color:#5672cd;",
|
||||||
|
"color:#ff5722;font-weight:bold;font-size:1rem;background:#f9de97;",
|
||||||
|
);
|
||||||
|
console.groupEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ require.config({
|
|||||||
baseUrl: BASE_URL,
|
baseUrl: BASE_URL,
|
||||||
paths: {
|
paths: {
|
||||||
"jquery": ["plugs/jquery-3.4.1/jquery-3.4.1.min"],
|
"jquery": ["plugs/jquery-3.4.1/jquery-3.4.1.min"],
|
||||||
"jquery-particleground": ["plugs/jq-module/jquery.particleground.min"],
|
|
||||||
"echarts": ["plugs/echarts/echarts.min"],
|
"echarts": ["plugs/echarts/echarts.min"],
|
||||||
"echarts-theme": ["plugs/echarts/echarts-theme"],
|
"echarts-theme": ["plugs/echarts/echarts-theme"],
|
||||||
"easy-admin": ["plugs/easy-admin/easy-admin"],
|
"easy-admin": ["plugs/easy-admin/easy-admin"],
|
||||||
"layuiall": ["plugs/layui-v2.x/layui.all"],
|
|
||||||
"layui": ["plugs/layui-v2.x/layui"],
|
"layui": ["plugs/layui-v2.x/layui"],
|
||||||
"miniAdmin": ["plugs/lay-module/layuimini/miniAdmin"],
|
"miniAdmin": ["plugs/lay-module/layuimini/miniAdmin"],
|
||||||
"miniMenu": ["plugs/lay-module/layuimini/miniMenu"],
|
"miniMenu": ["plugs/lay-module/layuimini/miniMenu"],
|
||||||
@@ -18,18 +16,20 @@ require.config({
|
|||||||
"miniTongji": ["plugs/lay-module/layuimini/miniTongji"],
|
"miniTongji": ["plugs/lay-module/layuimini/miniTongji"],
|
||||||
"treetable": ["plugs/lay-module/treetable-lay/treetable"],
|
"treetable": ["plugs/lay-module/treetable-lay/treetable"],
|
||||||
"tableSelect": ["plugs/lay-module/tableSelect/tableSelect"],
|
"tableSelect": ["plugs/lay-module/tableSelect/tableSelect"],
|
||||||
|
"switchSelect": ["plugs/lay-module/switchSelect/switchSelect"],
|
||||||
"iconPickerFa": ["plugs/lay-module/iconPicker/iconPickerFa"],
|
"iconPickerFa": ["plugs/lay-module/iconPicker/iconPickerFa"],
|
||||||
"autocomplete": ["plugs/lay-module/autocomplete/autocomplete"],
|
"autocomplete": ["plugs/lay-module/autocomplete/autocomplete"],
|
||||||
"xmSelect": ["plugs/xmSelect/xm-select"],
|
"xmSelect": ["plugs/xmSelect/xm-select"],
|
||||||
"vue": ["plugs/vue-2.6.10/vue.min"],
|
"vue": ["plugs/vue-2.6.10/vue.min"],
|
||||||
"swiper": ["plugs/swiper/swiper-bundle.min"],
|
"swiper": ["plugs/swiper/swiper-bundle.min"],
|
||||||
"colorMode": ["plugs/colorMode/colorMode"],
|
"colorMode": ["plugs/colorMode/colorMode"],
|
||||||
|
"lazyload": ["plugs/lazyload/lazyload.min"],
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 路径配置信息
|
// 路径配置信息
|
||||||
var PATH_CONFIG = {
|
var PATH_CONFIG = {
|
||||||
iconLess: BASE_URL + "plugs/font-awesome-4.7.0/less/variables.less",
|
iconLess: BASE_URL + "plugs/font-awesome-6.x/less/_variables.less",
|
||||||
};
|
};
|
||||||
window.PATH_CONFIG = PATH_CONFIG;
|
window.PATH_CONFIG = PATH_CONFIG;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSelect, miniTheme, xmSelect) {
|
define(["jquery", "tableSelect", "switchSelect", "miniTheme", "xmSelect", "lazyload"], function ($, tableSelect, switchSelect, miniTheme, xmSelect, lazyload) {
|
||||||
|
|
||||||
//切换日夜模式
|
//切换日夜模式
|
||||||
window.onInitElemStyle = function () {
|
window.onInitElemStyle = function () {
|
||||||
miniTheme.renderElemStyle();
|
try {
|
||||||
$('iframe').each(function (index, iframe) {
|
miniTheme.renderElemStyle();
|
||||||
if (typeof iframe.contentWindow.onInitElemStyle == "function") {
|
$('iframe').each(function (index, iframe) {
|
||||||
iframe.contentWindow.onInitElemStyle();
|
if (typeof iframe.contentWindow.onInitElemStyle == "function") {
|
||||||
}
|
iframe.contentWindow.onInitElemStyle();
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
miniTheme.changeThemeMainColor();
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
window.onInitElemStyle();
|
window.onInitElemStyle();
|
||||||
|
|
||||||
@@ -19,6 +23,7 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
element = layui.element,
|
element = layui.element,
|
||||||
laytpl = layui.laytpl,
|
laytpl = layui.laytpl,
|
||||||
tableSelect = layui.tableSelect,
|
tableSelect = layui.tableSelect,
|
||||||
|
switchSelect = layui.switchSelect,
|
||||||
util = layui.util;
|
util = layui.util;
|
||||||
|
|
||||||
layer.config({
|
layer.config({
|
||||||
@@ -253,7 +258,7 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 初始化表格左上方工具栏
|
// 初始化表格左上方工具栏
|
||||||
options.toolbar = options.toolbar || ['refresh', 'add', 'delete', 'export'];
|
options.toolbar = options.toolbar || ['refresh', 'add', 'delete', 'export', 'recycle'];
|
||||||
options.toolbar = admin.table.renderToolbar(options.toolbar, options.elem, options.id, options.init);
|
options.toolbar = admin.table.renderToolbar(options.toolbar, options.elem, options.id, options.init);
|
||||||
|
|
||||||
// 判断是否有操作列表权限
|
// 判断是否有操作列表权限
|
||||||
@@ -306,11 +311,19 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
}
|
}
|
||||||
} else if (v === 'delete') {
|
} else if (v === 'delete') {
|
||||||
if (admin.checkAuth('delete', elem)) {
|
if (admin.checkAuth('delete', elem)) {
|
||||||
toolbarHtml += '<button class="layui-btn layui-btn-sm layui-btn-danger" data-url="' + init.delete_url + '" data-table-delete="' + tableId + '"><i class="fa fa-trash-o"></i> 删除</button>\n';
|
toolbarHtml += '<button class="layui-btn layui-btn-sm layui-btn-danger" data-url="' + init.delete_url + '" data-table-delete="' + tableId + '"><i class="fa fa-trash"></i> 删除</button>\n';
|
||||||
}
|
}
|
||||||
} else if (v === 'export') {
|
} else if (v === 'export') {
|
||||||
if (admin.checkAuth('export', elem)) {
|
if (admin.checkAuth('export', elem)) {
|
||||||
toolbarHtml += '<button class="layui-btn layui-btn-sm layui-btn-success easyadmin-export-btn" data-url="' + init.export_url + '" data-table-export="' + tableId + '"><i class="fa fa-file-excel-o"></i> 导出</button>\n';
|
toolbarHtml += '<button class="layui-btn layui-btn-sm layui-btn-success easyadmin-export-btn" data-url="' + init.export_url + '" data-table-export="' + tableId + '"><i class="fa fa-file-excel"></i> 导出</button>\n';
|
||||||
|
}
|
||||||
|
} else if (v === 'recycle') {
|
||||||
|
if (init.recycle_url === undefined) {
|
||||||
|
console.warn('未定义回收站地址 init.recycle_url')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (admin.checkAuth('recycle', elem)) {
|
||||||
|
toolbarHtml += '<button class="layui-btn layui-btn-sm layui-bg-orange" data-open="' + init.recycle_url + '" data-title="回收站"><i class="fa fa-recycle"></i> 回收站</button>\n';
|
||||||
}
|
}
|
||||||
} else if (typeof v === "object") {
|
} else if (typeof v === "object") {
|
||||||
$.each(v, function (ii, vv) {
|
$.each(v, function (ii, vv) {
|
||||||
@@ -364,7 +377,7 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
var selectHtml = '';
|
var selectHtml = '';
|
||||||
$.each(d.selectList, function (sI, sV) {
|
$.each(d.selectList, function (sI, sV) {
|
||||||
var selected = '';
|
var selected = '';
|
||||||
if (sI === d.searchValue) {
|
if (sI == d.searchValue) {
|
||||||
selected = 'selected=""';
|
selected = 'selected=""';
|
||||||
}
|
}
|
||||||
selectHtml += '<option value="' + sI + '" ' + selected + '>' + sV + '</option>/n';
|
selectHtml += '<option value="' + sI + '" ' + selected + '>' + sV + '</option>/n';
|
||||||
@@ -387,7 +400,7 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
formHtml += '\t<div class="layui-form-item layui-inline">\n' +
|
formHtml += '\t<div class="layui-form-item layui-inline">\n' +
|
||||||
'<label class="layui-form-label">' + d.title + '</label>\n' +
|
'<label class="layui-form-label">' + d.title + '</label>\n' +
|
||||||
'<div class="layui-input-inline">\n' +
|
'<div class="layui-input-inline">\n' +
|
||||||
'<div id="c-' + d.fieldAlias + '" class="tableSearch-xmSelect xmSelect-' + d.fieldAlias + '" name="' + d.fieldAlias + '" data-search-op="' + d.searchOp + '"></div>\n' +
|
'<div id="c-' + d.fieldAlias + '" class="tableSearch-xmSelect xmSelect-' + d.fieldAlias + '" name="' + d.fieldAlias + '" data-search-op="' + d.searchOp + '" data-search-value="' + d.searchValue + '"></div>\n' +
|
||||||
'</div>\n' +
|
'</div>\n' +
|
||||||
'</div>';
|
'</div>';
|
||||||
init.xmSelectList[d.fieldAlias] = d.selectList
|
init.xmSelectList[d.fieldAlias] = d.selectList
|
||||||
@@ -419,6 +432,16 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
break;
|
break;
|
||||||
|
case 'datetime':
|
||||||
|
// 适用于日期格式:yyyy-MM-dd HH:mm:ss
|
||||||
|
d.searchOp = 'datetime';
|
||||||
|
formHtml += '<div class="layui-form-item layui-inline">\n' +
|
||||||
|
'<label class="layui-form-label">' + d.title + '</label>\n' +
|
||||||
|
'<div class="layui-input-inline">\n' +
|
||||||
|
'<input style="width: 275px;font-size: 0.82rem" id="c-' + d.fieldAlias + '" name="' + d.fieldAlias + '" data-search-op="' + d.searchOp + '" value="' + d.searchValue + '" placeholder="' + d.searchTip + '" class="layui-input">\n' +
|
||||||
|
'</div>\n' +
|
||||||
|
'</div>';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
newCols.push(d);
|
newCols.push(d);
|
||||||
}
|
}
|
||||||
@@ -451,7 +474,7 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
})
|
})
|
||||||
form.render();
|
form.render();
|
||||||
$.each(newCols, function (ncI, ncV) {
|
$.each(newCols, function (ncI, ncV) {
|
||||||
if (ncV.search === 'range') {
|
if (ncV.search === 'range' || ncV.search === 'datetime') {
|
||||||
laydate.render({
|
laydate.render({
|
||||||
range: true, type: ncV.timeType, elem: '[name="' + ncV.fieldAlias + '"]', rangeLinked: true,
|
range: true, type: ncV.timeType, elem: '[name="' + ncV.fieldAlias + '"]', rangeLinked: true,
|
||||||
shortcuts: getRangeShortcuts()
|
shortcuts: getRangeShortcuts()
|
||||||
@@ -748,8 +771,11 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
var values = value.split(option.imageSplit),
|
var values = value.split(option.imageSplit),
|
||||||
valuesHtml = [];
|
valuesHtml = [];
|
||||||
values.forEach((value, index) => {
|
values.forEach((value, index) => {
|
||||||
valuesHtml.push('<img style="max-width: ' + option.imageWidth + 'px; max-height: ' + option.imageHeight + 'px;" src="' + value + '" data-image="' + title + '">');
|
valuesHtml.push('<img style="max-width: ' + option.imageWidth + 'px; max-height: ' + option.imageHeight + 'px;" class="lazyload" src="/static/common/images/loading.gif" data-src="' + value + '" data-image="' + title + '">');
|
||||||
});
|
});
|
||||||
|
$(function () {
|
||||||
|
$("img.lazyload").lazyload({threshold: 1});
|
||||||
|
})
|
||||||
return valuesHtml.join(option.imageJoin);
|
return valuesHtml.join(option.imageJoin);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -862,12 +888,15 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
listenTableSearch: function (tableId) {
|
listenTableSearch: function (tableId) {
|
||||||
if (Object.keys(init.xmSelectList).length > 0) {
|
if (Object.keys(init.xmSelectList).length > 0) {
|
||||||
$.each(init.xmSelectList, function (index, value) {
|
$.each(init.xmSelectList, function (index, value) {
|
||||||
|
let xmSearchValue = $('#c-' + index).data('search-value') || [];
|
||||||
|
if (!Array.isArray(xmSearchValue)) xmSearchValue = (xmSearchValue.toString()).split(',')
|
||||||
const keysArray = Object.keys(value).map((key) => {
|
const keysArray = Object.keys(value).map((key) => {
|
||||||
return {name: value[key], value: key}
|
return {name: value[key], value: key, selected: xmSearchValue.indexOf(key) !== -1}
|
||||||
})
|
})
|
||||||
init.xmSelectModel[index] = xmSelect.render({
|
init.xmSelectModel[index] = xmSelect.render({
|
||||||
el: '.xmSelect-' + index, language: 'zn', data: keysArray, name: index,
|
el: '.xmSelect-' + index, language: 'zn', data: keysArray, name: index,
|
||||||
filterable: true, paging: true, pageSize: 10, theme: {color: '#16b777'}, toolbar: {show: true},
|
filterable: true, paging: true, pageSize: 10, toolbar: {show: true},
|
||||||
|
theme: {color: getComputedStyle(document.documentElement).getPropertyValue('--ea8-theme-main-color') || '#16b777'}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -983,7 +1012,21 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
},
|
},
|
||||||
listenSort: function (options) {
|
listenSort: function (options) {
|
||||||
table.on('sort(' + options.layFilter + ')', function (obj) {
|
table.on('sort(' + options.layFilter + ')', function (obj) {
|
||||||
let defaultWhere = options.where || {}
|
let defaultWhere = {}
|
||||||
|
$.each(options.cols, function (_, colsV) {
|
||||||
|
let formatFilter = {}
|
||||||
|
let formatOp = {}
|
||||||
|
$.each(colsV, function (i, v) {
|
||||||
|
if (v.field) {
|
||||||
|
if ($('#c-' + v.field).val()) {
|
||||||
|
formatFilter[v.field] = $('#c-' + v.field).val()
|
||||||
|
formatOp[v.field] = v.searchOp || '='
|
||||||
|
defaultWhere['filter'] = JSON.stringify(formatFilter);
|
||||||
|
defaultWhere['op'] = JSON.stringify(formatOp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
let sortWhere = {tableOrder: obj.field + ' ' + obj.type}
|
let sortWhere = {tableOrder: obj.field + ' ' + obj.type}
|
||||||
table.reload(options.id, {
|
table.reload(options.id, {
|
||||||
where: {...defaultWhere, ...sortWhere}
|
where: {...defaultWhere, ...sortWhere}
|
||||||
@@ -1020,8 +1063,9 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
maxmin: true,
|
maxmin: true,
|
||||||
anim: 0,
|
anim: 0,
|
||||||
moveOut: true,
|
moveOut: true,
|
||||||
move: false,
|
shade: 0.3,
|
||||||
shadeClose: shadeClose,
|
shadeClose: shadeClose,
|
||||||
|
scrollbar: false,
|
||||||
before: function () {
|
before: function () {
|
||||||
},
|
},
|
||||||
success: function (layero, index) {
|
success: function (layero, index) {
|
||||||
@@ -1593,7 +1637,7 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
cols: [[
|
cols: [[
|
||||||
{type: selectCheck},
|
{type: selectCheck},
|
||||||
{field: 'id', title: 'ID'},
|
{field: 'id', title: 'ID'},
|
||||||
{field: 'url', minWidth: 80, search: false, title: '图片信息', imageHeight: 40, align: "center", templet: admin.table.image},
|
{field: 'url', minWidth: 80, search: false, title: '图片信息', imageHeight: 30, align: "center", templet: admin.table.image},
|
||||||
{field: 'original_name', width: 150, title: '文件原名', align: "center"},
|
{field: 'original_name', width: 150, title: '文件原名', align: "center"},
|
||||||
{field: 'mime_type', width: 120, title: 'mime类型', align: "center"},
|
{field: 'mime_type', width: 120, title: 'mime类型', align: "center"},
|
||||||
{field: 'create_time', width: 200, title: '创建时间', align: "center", search: 'range'},
|
{field: 'create_time', width: 200, title: '创建时间', align: "center", search: 'range'},
|
||||||
@@ -1635,6 +1679,7 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
html: $(this).text(),
|
html: $(this).text(),
|
||||||
config: {
|
config: {
|
||||||
MENU_CONF: {
|
MENU_CONF: {
|
||||||
|
// 上传图片
|
||||||
uploadImage: {
|
uploadImage: {
|
||||||
server: window.CONFIG.ADMIN_UPLOAD_URL,
|
server: window.CONFIG.ADMIN_UPLOAD_URL,
|
||||||
fieldName: 'file',
|
fieldName: 'file',
|
||||||
@@ -1652,6 +1697,23 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
let href = ''
|
let href = ''
|
||||||
insertFn(url, alt, href)
|
insertFn(url, alt, href)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// 上传视频
|
||||||
|
uploadVideo: {
|
||||||
|
server: window.CONFIG.ADMIN_UPLOAD_URL,
|
||||||
|
fieldName: 'file',
|
||||||
|
meta: {editor: 'editor',},
|
||||||
|
async customInsert(res, insertFn) {
|
||||||
|
let code = res.code || 0
|
||||||
|
if (code != '1') {
|
||||||
|
layer.msg(res.msg || '上传失败', {icon: 2});
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let url = res.data?.url || ''
|
||||||
|
let alt = ''
|
||||||
|
let href = ''
|
||||||
|
insertFn(url, alt, href)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1732,6 +1794,24 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let switchSelectList = document.querySelectorAll("[data-show]");
|
||||||
|
$.each(switchSelectList, function (i, v) {
|
||||||
|
let _show = $(this).attr('data-show');
|
||||||
|
if (_show === 'switchSelect') {
|
||||||
|
let _data = $(this).attr('data-list');
|
||||||
|
let _value = $(this).attr('data-value') || ''
|
||||||
|
let _target = $(this).attr('data-target') || ''
|
||||||
|
let _name = $(this).attr('data-name') || ''
|
||||||
|
try {
|
||||||
|
new switchSelect({
|
||||||
|
elem: $(this), data: JSON.parse(_data), default: _value, target: _target, name: _name
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
date: function () {
|
date: function () {
|
||||||
var dateList = document.querySelectorAll("[data-date]");
|
var dateList = document.querySelectorAll("[data-date]");
|
||||||
@@ -1761,6 +1841,53 @@ define(["jquery", "tableSelect", "miniTheme", "xmSelect"], function ($, tableSel
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ai: {
|
||||||
|
chat: function (content, options, cancel) {
|
||||||
|
let id = 'chat_' + (new Date()).getTime()
|
||||||
|
layer.open({
|
||||||
|
'title': options?.title || 'AI建议',
|
||||||
|
type: 1,
|
||||||
|
area: options?.area || (admin.checkMobile() ? ['95%', '60%'] : ['50%', '60%']),
|
||||||
|
shade: options?.shade || 0,
|
||||||
|
shadeClose: options?.shadeClose || false,
|
||||||
|
scrollbar: options?.scrollbar || false,
|
||||||
|
maxmin: options?.maxmin || true,
|
||||||
|
anim: options?.anim || 0,
|
||||||
|
content: `<div style="padding: 20px;white-space: pre-wrap;" id="${id}"></div>`,
|
||||||
|
success: function (layero, index) {
|
||||||
|
let elem = document.getElementById(id)
|
||||||
|
if (options?.stream) {
|
||||||
|
let index = 0;
|
||||||
|
let lastTime = performance.now();
|
||||||
|
const interval = options.interval || 100;
|
||||||
|
|
||||||
|
function typeCharacter(currentTime) {
|
||||||
|
if (index < content.length) {
|
||||||
|
if (currentTime - lastTime >= interval) {
|
||||||
|
elem.innerHTML += content.charAt(index);
|
||||||
|
index++;
|
||||||
|
lastTime = currentTime;
|
||||||
|
elem.scrollIntoView({behavior: "smooth", block: "end"});
|
||||||
|
}
|
||||||
|
requestAnimationFrame(typeCharacter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(typeCharacter);
|
||||||
|
} else {
|
||||||
|
content = content.replace(/\r\n/g, '<br>').replace(/\n/g, '<br>')
|
||||||
|
setTimeout(() => {
|
||||||
|
elem.innerHTML = content
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cancel: function (index, layero) {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return admin;
|
return admin;
|
||||||
});
|
});
|
||||||
|
|||||||
165
public/static/plugs/font-awesome-6.x/LICENSE.txt
Normal file
165
public/static/plugs/font-awesome-6.x/LICENSE.txt
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
Fonticons, Inc. (https://fontawesome.com)
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Font Awesome Free License
|
||||||
|
|
||||||
|
Font Awesome Free is free, open source, and GPL friendly. You can use it for
|
||||||
|
commercial projects, open source projects, or really almost whatever you want.
|
||||||
|
Full Font Awesome Free license: https://fontawesome.com/license/free.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
|
||||||
|
|
||||||
|
The Font Awesome Free download is licensed under a Creative Commons
|
||||||
|
Attribution 4.0 International License and applies to all icons packaged
|
||||||
|
as SVG and JS file types.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Fonts: SIL OFL 1.1 License
|
||||||
|
|
||||||
|
In the Font Awesome Free download, the SIL OFL license applies to all icons
|
||||||
|
packaged as web and desktop font files.
|
||||||
|
|
||||||
|
Copyright (c) 2024 Fonticons, Inc. (https://fontawesome.com)
|
||||||
|
with Reserved Font Name: "Font Awesome".
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
SIL OPEN FONT LICENSE
|
||||||
|
Version 1.1 - 26 February 2007
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting — in part or in whole — any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Code: MIT License (https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
In the Font Awesome Free download, the MIT license applies to all non-font and
|
||||||
|
non-icon files.
|
||||||
|
|
||||||
|
Copyright 2024 Fonticons, Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
and to permit persons to whom the Software is furnished to do so, subject to the
|
||||||
|
following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Attribution
|
||||||
|
|
||||||
|
Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
|
||||||
|
Awesome Free files already contain embedded comments with sufficient
|
||||||
|
attribution, so you shouldn't need to do anything additional when using these
|
||||||
|
files normally.
|
||||||
|
|
||||||
|
We've kept attribution comments terse, so we ask that you do not actively work
|
||||||
|
to remove them from files, especially code. They're a great way for folks to
|
||||||
|
learn about Font Awesome.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Brand Icons
|
||||||
|
|
||||||
|
All brand icons are trademarks of their respective owners. The use of these
|
||||||
|
trademarks does not indicate endorsement of the trademark holder by Font
|
||||||
|
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
|
||||||
|
to represent the company, product, or service to which they refer.**
|
||||||
7913
public/static/plugs/font-awesome-6.x/css/all.css
Normal file
7913
public/static/plugs/font-awesome-6.x/css/all.css
Normal file
File diff suppressed because it is too large
Load Diff
9
public/static/plugs/font-awesome-6.x/css/all.min.css
vendored
Normal file
9
public/static/plugs/font-awesome-6.x/css/all.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1609
public/static/plugs/font-awesome-6.x/css/brands.css
Normal file
1609
public/static/plugs/font-awesome-6.x/css/brands.css
Normal file
File diff suppressed because it is too large
Load Diff
6
public/static/plugs/font-awesome-6.x/css/brands.min.css
vendored
Normal file
6
public/static/plugs/font-awesome-6.x/css/brands.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6243
public/static/plugs/font-awesome-6.x/css/fontawesome.css
vendored
Normal file
6243
public/static/plugs/font-awesome-6.x/css/fontawesome.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
public/static/plugs/font-awesome-6.x/css/fontawesome.min.css
vendored
Normal file
9
public/static/plugs/font-awesome-6.x/css/fontawesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
19
public/static/plugs/font-awesome-6.x/css/regular.css
Normal file
19
public/static/plugs/font-awesome-6.x/css/regular.css
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2024 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-style-family-classic: 'Font Awesome 6 Free';
|
||||||
|
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Font Awesome 6 Free';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
.far,
|
||||||
|
.fa-regular {
|
||||||
|
font-weight: 400; }
|
||||||
6
public/static/plugs/font-awesome-6.x/css/regular.min.css
vendored
Normal file
6
public/static/plugs/font-awesome-6.x/css/regular.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2024 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}
|
||||||
19
public/static/plugs/font-awesome-6.x/css/solid.css
Normal file
19
public/static/plugs/font-awesome-6.x/css/solid.css
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2024 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-style-family-classic: 'Font Awesome 6 Free';
|
||||||
|
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Font Awesome 6 Free';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
.fas,
|
||||||
|
.fa-solid {
|
||||||
|
font-weight: 900; }
|
||||||
6
public/static/plugs/font-awesome-6.x/css/solid.min.css
vendored
Normal file
6
public/static/plugs/font-awesome-6.x/css/solid.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2024 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}
|
||||||
461
public/static/plugs/font-awesome-6.x/css/svg-with-js.css
Normal file
461
public/static/plugs/font-awesome-6.x/css/svg-with-js.css
Normal file
@@ -0,0 +1,461 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2024 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free';
|
||||||
|
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free';
|
||||||
|
--fa-font-light: normal 300 1em/1 'Font Awesome 6 Pro';
|
||||||
|
--fa-font-thin: normal 100 1em/1 'Font Awesome 6 Pro';
|
||||||
|
--fa-font-duotone: normal 900 1em/1 'Font Awesome 6 Duotone';
|
||||||
|
--fa-font-duotone-regular: normal 400 1em/1 'Font Awesome 6 Duotone';
|
||||||
|
--fa-font-duotone-light: normal 300 1em/1 'Font Awesome 6 Duotone';
|
||||||
|
--fa-font-duotone-thin: normal 100 1em/1 'Font Awesome 6 Duotone';
|
||||||
|
--fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands';
|
||||||
|
--fa-font-sharp-solid: normal 900 1em/1 'Font Awesome 6 Sharp';
|
||||||
|
--fa-font-sharp-regular: normal 400 1em/1 'Font Awesome 6 Sharp';
|
||||||
|
--fa-font-sharp-light: normal 300 1em/1 'Font Awesome 6 Sharp';
|
||||||
|
--fa-font-sharp-thin: normal 100 1em/1 'Font Awesome 6 Sharp';
|
||||||
|
--fa-font-sharp-duotone-solid: normal 900 1em/1 'Font Awesome 6 Sharp Duotone';
|
||||||
|
--fa-font-sharp-duotone-regular: normal 400 1em/1 'Font Awesome 6 Sharp Duotone';
|
||||||
|
--fa-font-sharp-duotone-light: normal 300 1em/1 'Font Awesome 6 Sharp Duotone';
|
||||||
|
--fa-font-sharp-duotone-thin: normal 100 1em/1 'Font Awesome 6 Sharp Duotone'; }
|
||||||
|
|
||||||
|
svg.svg-inline--fa:not(:root), svg.svg-inline--fa:not(:host) {
|
||||||
|
overflow: visible;
|
||||||
|
box-sizing: content-box; }
|
||||||
|
|
||||||
|
.svg-inline--fa {
|
||||||
|
display: var(--fa-display, inline-block);
|
||||||
|
height: 1em;
|
||||||
|
overflow: visible;
|
||||||
|
vertical-align: -.125em; }
|
||||||
|
.svg-inline--fa.fa-2xs {
|
||||||
|
vertical-align: 0.1em; }
|
||||||
|
.svg-inline--fa.fa-xs {
|
||||||
|
vertical-align: 0em; }
|
||||||
|
.svg-inline--fa.fa-sm {
|
||||||
|
vertical-align: -0.07143em; }
|
||||||
|
.svg-inline--fa.fa-lg {
|
||||||
|
vertical-align: -0.2em; }
|
||||||
|
.svg-inline--fa.fa-xl {
|
||||||
|
vertical-align: -0.25em; }
|
||||||
|
.svg-inline--fa.fa-2xl {
|
||||||
|
vertical-align: -0.3125em; }
|
||||||
|
.svg-inline--fa.fa-pull-left {
|
||||||
|
margin-right: var(--fa-pull-margin, 0.3em);
|
||||||
|
width: auto; }
|
||||||
|
.svg-inline--fa.fa-pull-right {
|
||||||
|
margin-left: var(--fa-pull-margin, 0.3em);
|
||||||
|
width: auto; }
|
||||||
|
.svg-inline--fa.fa-li {
|
||||||
|
width: var(--fa-li-width, 2em);
|
||||||
|
top: 0.25em; }
|
||||||
|
.svg-inline--fa.fa-fw {
|
||||||
|
width: var(--fa-fw-width, 1.25em); }
|
||||||
|
|
||||||
|
.fa-layers svg.svg-inline--fa {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0; }
|
||||||
|
|
||||||
|
.fa-layers-counter, .fa-layers-text {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center; }
|
||||||
|
|
||||||
|
.fa-layers {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1em;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: -.125em;
|
||||||
|
width: 1em; }
|
||||||
|
.fa-layers svg.svg-inline--fa {
|
||||||
|
transform-origin: center center; }
|
||||||
|
|
||||||
|
.fa-layers-text {
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transform-origin: center center; }
|
||||||
|
|
||||||
|
.fa-layers-counter {
|
||||||
|
background-color: var(--fa-counter-background-color, #ff253a);
|
||||||
|
border-radius: var(--fa-counter-border-radius, 1em);
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: var(--fa-inverse, #fff);
|
||||||
|
line-height: var(--fa-counter-line-height, 1);
|
||||||
|
max-width: var(--fa-counter-max-width, 5em);
|
||||||
|
min-width: var(--fa-counter-min-width, 1.5em);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: var(--fa-counter-padding, 0.25em 0.5em);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
transform: scale(var(--fa-counter-scale, 0.25));
|
||||||
|
transform-origin: top right; }
|
||||||
|
|
||||||
|
.fa-layers-bottom-right {
|
||||||
|
bottom: var(--fa-bottom, 0);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
top: auto;
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: bottom right; }
|
||||||
|
|
||||||
|
.fa-layers-bottom-left {
|
||||||
|
bottom: var(--fa-bottom, 0);
|
||||||
|
left: var(--fa-left, 0);
|
||||||
|
right: auto;
|
||||||
|
top: auto;
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: bottom left; }
|
||||||
|
|
||||||
|
.fa-layers-top-right {
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: top right; }
|
||||||
|
|
||||||
|
.fa-layers-top-left {
|
||||||
|
left: var(--fa-left, 0);
|
||||||
|
right: auto;
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: top left; }
|
||||||
|
|
||||||
|
.fa-1x {
|
||||||
|
font-size: 1em; }
|
||||||
|
|
||||||
|
.fa-2x {
|
||||||
|
font-size: 2em; }
|
||||||
|
|
||||||
|
.fa-3x {
|
||||||
|
font-size: 3em; }
|
||||||
|
|
||||||
|
.fa-4x {
|
||||||
|
font-size: 4em; }
|
||||||
|
|
||||||
|
.fa-5x {
|
||||||
|
font-size: 5em; }
|
||||||
|
|
||||||
|
.fa-6x {
|
||||||
|
font-size: 6em; }
|
||||||
|
|
||||||
|
.fa-7x {
|
||||||
|
font-size: 7em; }
|
||||||
|
|
||||||
|
.fa-8x {
|
||||||
|
font-size: 8em; }
|
||||||
|
|
||||||
|
.fa-9x {
|
||||||
|
font-size: 9em; }
|
||||||
|
|
||||||
|
.fa-10x {
|
||||||
|
font-size: 10em; }
|
||||||
|
|
||||||
|
.fa-2xs {
|
||||||
|
font-size: 0.625em;
|
||||||
|
line-height: 0.1em;
|
||||||
|
vertical-align: 0.225em; }
|
||||||
|
|
||||||
|
.fa-xs {
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 0.08333em;
|
||||||
|
vertical-align: 0.125em; }
|
||||||
|
|
||||||
|
.fa-sm {
|
||||||
|
font-size: 0.875em;
|
||||||
|
line-height: 0.07143em;
|
||||||
|
vertical-align: 0.05357em; }
|
||||||
|
|
||||||
|
.fa-lg {
|
||||||
|
font-size: 1.25em;
|
||||||
|
line-height: 0.05em;
|
||||||
|
vertical-align: -0.075em; }
|
||||||
|
|
||||||
|
.fa-xl {
|
||||||
|
font-size: 1.5em;
|
||||||
|
line-height: 0.04167em;
|
||||||
|
vertical-align: -0.125em; }
|
||||||
|
|
||||||
|
.fa-2xl {
|
||||||
|
font-size: 2em;
|
||||||
|
line-height: 0.03125em;
|
||||||
|
vertical-align: -0.1875em; }
|
||||||
|
|
||||||
|
.fa-fw {
|
||||||
|
text-align: center;
|
||||||
|
width: 1.25em; }
|
||||||
|
|
||||||
|
.fa-ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-left: var(--fa-li-margin, 2.5em);
|
||||||
|
padding-left: 0; }
|
||||||
|
.fa-ul > li {
|
||||||
|
position: relative; }
|
||||||
|
|
||||||
|
.fa-li {
|
||||||
|
left: calc(-1 * var(--fa-li-width, 2em));
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
width: var(--fa-li-width, 2em);
|
||||||
|
line-height: inherit; }
|
||||||
|
|
||||||
|
.fa-border {
|
||||||
|
border-color: var(--fa-border-color, #eee);
|
||||||
|
border-radius: var(--fa-border-radius, 0.1em);
|
||||||
|
border-style: var(--fa-border-style, solid);
|
||||||
|
border-width: var(--fa-border-width, 0.08em);
|
||||||
|
padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); }
|
||||||
|
|
||||||
|
.fa-pull-left {
|
||||||
|
float: left;
|
||||||
|
margin-right: var(--fa-pull-margin, 0.3em); }
|
||||||
|
|
||||||
|
.fa-pull-right {
|
||||||
|
float: right;
|
||||||
|
margin-left: var(--fa-pull-margin, 0.3em); }
|
||||||
|
|
||||||
|
.fa-beat {
|
||||||
|
animation-name: fa-beat;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
|
||||||
|
|
||||||
|
.fa-bounce {
|
||||||
|
animation-name: fa-bounce;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); }
|
||||||
|
|
||||||
|
.fa-fade {
|
||||||
|
animation-name: fa-fade;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
|
||||||
|
|
||||||
|
.fa-beat-fade {
|
||||||
|
animation-name: fa-beat-fade;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
|
||||||
|
|
||||||
|
.fa-flip {
|
||||||
|
animation-name: fa-flip;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
|
||||||
|
|
||||||
|
.fa-shake {
|
||||||
|
animation-name: fa-shake;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, linear); }
|
||||||
|
|
||||||
|
.fa-spin {
|
||||||
|
animation-name: fa-spin;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 2s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, linear); }
|
||||||
|
|
||||||
|
.fa-spin-reverse {
|
||||||
|
--fa-animation-direction: reverse; }
|
||||||
|
|
||||||
|
.fa-pulse,
|
||||||
|
.fa-spin-pulse {
|
||||||
|
animation-name: fa-spin;
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, steps(8)); }
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.fa-beat,
|
||||||
|
.fa-bounce,
|
||||||
|
.fa-fade,
|
||||||
|
.fa-beat-fade,
|
||||||
|
.fa-flip,
|
||||||
|
.fa-pulse,
|
||||||
|
.fa-shake,
|
||||||
|
.fa-spin,
|
||||||
|
.fa-spin-pulse {
|
||||||
|
animation-delay: -1ms;
|
||||||
|
animation-duration: 1ms;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
transition-delay: 0s;
|
||||||
|
transition-duration: 0s; } }
|
||||||
|
|
||||||
|
@keyframes fa-beat {
|
||||||
|
0%, 90% {
|
||||||
|
transform: scale(1); }
|
||||||
|
45% {
|
||||||
|
transform: scale(var(--fa-beat-scale, 1.25)); } }
|
||||||
|
|
||||||
|
@keyframes fa-bounce {
|
||||||
|
0% {
|
||||||
|
transform: scale(1, 1) translateY(0); }
|
||||||
|
10% {
|
||||||
|
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
|
||||||
|
30% {
|
||||||
|
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
|
||||||
|
50% {
|
||||||
|
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
|
||||||
|
57% {
|
||||||
|
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
|
||||||
|
64% {
|
||||||
|
transform: scale(1, 1) translateY(0); }
|
||||||
|
100% {
|
||||||
|
transform: scale(1, 1) translateY(0); } }
|
||||||
|
|
||||||
|
@keyframes fa-fade {
|
||||||
|
50% {
|
||||||
|
opacity: var(--fa-fade-opacity, 0.4); } }
|
||||||
|
|
||||||
|
@keyframes fa-beat-fade {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: var(--fa-beat-fade-opacity, 0.4);
|
||||||
|
transform: scale(1); }
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
|
||||||
|
|
||||||
|
@keyframes fa-flip {
|
||||||
|
50% {
|
||||||
|
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
|
||||||
|
|
||||||
|
@keyframes fa-shake {
|
||||||
|
0% {
|
||||||
|
transform: rotate(-15deg); }
|
||||||
|
4% {
|
||||||
|
transform: rotate(15deg); }
|
||||||
|
8%, 24% {
|
||||||
|
transform: rotate(-18deg); }
|
||||||
|
12%, 28% {
|
||||||
|
transform: rotate(18deg); }
|
||||||
|
16% {
|
||||||
|
transform: rotate(-22deg); }
|
||||||
|
20% {
|
||||||
|
transform: rotate(22deg); }
|
||||||
|
32% {
|
||||||
|
transform: rotate(-12deg); }
|
||||||
|
36% {
|
||||||
|
transform: rotate(12deg); }
|
||||||
|
40%, 100% {
|
||||||
|
transform: rotate(0deg); } }
|
||||||
|
|
||||||
|
@keyframes fa-spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg); }
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg); } }
|
||||||
|
|
||||||
|
.fa-rotate-90 {
|
||||||
|
transform: rotate(90deg); }
|
||||||
|
|
||||||
|
.fa-rotate-180 {
|
||||||
|
transform: rotate(180deg); }
|
||||||
|
|
||||||
|
.fa-rotate-270 {
|
||||||
|
transform: rotate(270deg); }
|
||||||
|
|
||||||
|
.fa-flip-horizontal {
|
||||||
|
transform: scale(-1, 1); }
|
||||||
|
|
||||||
|
.fa-flip-vertical {
|
||||||
|
transform: scale(1, -1); }
|
||||||
|
|
||||||
|
.fa-flip-both,
|
||||||
|
.fa-flip-horizontal.fa-flip-vertical {
|
||||||
|
transform: scale(-1, -1); }
|
||||||
|
|
||||||
|
.fa-rotate-by {
|
||||||
|
transform: rotate(var(--fa-rotate-angle, 0)); }
|
||||||
|
|
||||||
|
.fa-stack {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 2em;
|
||||||
|
position: relative;
|
||||||
|
width: 2.5em; }
|
||||||
|
|
||||||
|
.fa-stack-1x,
|
||||||
|
.fa-stack-2x {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: var(--fa-stack-z-index, auto); }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-stack-1x {
|
||||||
|
height: 1em;
|
||||||
|
width: 1.25em; }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-stack-2x {
|
||||||
|
height: 2em;
|
||||||
|
width: 2.5em; }
|
||||||
|
|
||||||
|
.fa-inverse {
|
||||||
|
color: var(--fa-inverse, #fff); }
|
||||||
|
|
||||||
|
.sr-only,
|
||||||
|
.fa-sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border-width: 0; }
|
||||||
|
|
||||||
|
.sr-only-focusable:not(:focus),
|
||||||
|
.fa-sr-only-focusable:not(:focus) {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border-width: 0; }
|
||||||
|
|
||||||
|
.svg-inline--fa .fa-primary {
|
||||||
|
fill: var(--fa-primary-color, currentColor);
|
||||||
|
opacity: var(--fa-primary-opacity, 1); }
|
||||||
|
|
||||||
|
.svg-inline--fa .fa-secondary {
|
||||||
|
fill: var(--fa-secondary-color, currentColor);
|
||||||
|
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-swap-opacity .fa-primary {
|
||||||
|
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-swap-opacity .fa-secondary {
|
||||||
|
opacity: var(--fa-primary-opacity, 1); }
|
||||||
|
|
||||||
|
.svg-inline--fa mask .fa-primary,
|
||||||
|
.svg-inline--fa mask .fa-secondary {
|
||||||
|
fill: black; }
|
||||||
6
public/static/plugs/font-awesome-6.x/css/svg-with-js.min.css
vendored
Normal file
6
public/static/plugs/font-awesome-6.x/css/svg-with-js.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
26
public/static/plugs/font-awesome-6.x/css/v4-font-face.css
Normal file
26
public/static/plugs/font-awesome-6.x/css/v4-font-face.css
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2024 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype");
|
||||||
|
unicode-range: U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC; }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype");
|
||||||
|
unicode-range: U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A; }
|
||||||
6
public/static/plugs/font-awesome-6.x/css/v4-font-face.min.css
vendored
Normal file
6
public/static/plugs/font-awesome-6.x/css/v4-font-face.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2024 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}
|
||||||
2194
public/static/plugs/font-awesome-6.x/css/v4-shims.css
Normal file
2194
public/static/plugs/font-awesome-6.x/css/v4-shims.css
Normal file
File diff suppressed because it is too large
Load Diff
6
public/static/plugs/font-awesome-6.x/css/v4-shims.min.css
vendored
Normal file
6
public/static/plugs/font-awesome-6.x/css/v4-shims.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user