Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
f9f25b76dd | ||
|
|
7603cdfa7e | ||
|
|
2e0cc85966 | ||
|
|
5814fed0da | ||
|
|
40f7ee82cd | ||
|
|
936cb56c7f | ||
|
|
2d1940522c | ||
|
|
264cf56ae4 | ||
|
|
57ea9a3f47 | ||
|
|
31c06cff69 | ||
|
|
4c8d21fccf | ||
|
|
817582bed5 | ||
|
|
3a0c0c1624 | ||
|
|
30c7615e53 | ||
|
|
9d58da3cc3 | ||
|
|
1f5ca39226 | ||
|
|
82f17301a7 | ||
|
|
4ef7879ae3 | ||
|
|
0c9b369e2e | ||
|
|
e981852422 | ||
|
|
1d258621c8 | ||
|
|
9534f2c2fe | ||
|
|
9fb8dd022a | ||
|
|
fc264630ec | ||
|
|
3d19c8d337 | ||
|
|
4baa4e185d | ||
|
|
88bc6441e5 | ||
|
|
0efb70b3b7 | ||
|
|
c22be8ac76 | ||
|
|
ebce7f3b0e | ||
|
|
f8b6d847d5 | ||
|
|
55a9b13e69 | ||
|
|
5d58248cf4 | ||
|
|
bbd0320a35 | ||
|
|
d62a67aafe | ||
|
|
c6cc9d4164 | ||
|
|
add8c5144c | ||
|
|
62f591045e | ||
|
|
7470790657 | ||
|
|
11fa69afaf | ||
|
|
8983705ce4 | ||
|
|
95ccd4071b | ||
|
|
09f3ea7e54 | ||
|
|
9cadb27c9e | ||
|
|
2772034a93 | ||
|
|
08ea79033c | ||
|
|
e7f09d9c68 | ||
|
|
e2effb762c | ||
|
|
0e18825808 | ||
|
|
c031b09422 | ||
|
|
231fd48e2f | ||
|
|
53772badd4 | ||
|
|
34354837d5 |
13
.example.env
13
.example.env
@@ -1,5 +1,8 @@
|
||||
APP_DEBUG=true
|
||||
|
||||
# 后台系统日志开关
|
||||
APP_ADMIN_SYSTEM_LOG=true
|
||||
|
||||
DEFAULT_TIMEZONE=Asia/Shanghai
|
||||
|
||||
DB_TYPE=mysql
|
||||
@@ -11,6 +14,16 @@ DB_PORT=3306
|
||||
DB_CHARSET=utf8mb4
|
||||
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]
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -9,4 +9,4 @@ Thumbs.db
|
||||
/vendor
|
||||
/.settings
|
||||
/.buildpath
|
||||
/.project
|
||||
/.project
|
||||
|
||||
40
README.md
40
README.md
@@ -1,27 +1,31 @@
|
||||
<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" />
|
||||
|
||||
<span><img src="https://img.shields.io/badge/php-%3E=8.0.0-brightgreen.svg?style=for-the-badge&logo=php&colorB=ff69b4" alt="php"></span>
|
||||
<span><img src="https://img.shields.io/badge/mysql-%3E=5.7-brightgreen.svg?style=for-the-badge&logo=mysql&colorB=blue" alt="MySQL"></span>
|
||||
<span><img src="https://img.shields.io/badge/thinkphp-%3E=8.0.0-brightgreen.svg?style=for-the-badge&logo=thinkphp" alt="ThinkPHP"></span>
|
||||
<span><img src="https://img.shields.io/badge/layui-%3E=2.9.0-brightgreen.svg?style=for-the-badge&logo=layui&colorB=orange" alt="layui"></span>
|
||||
<span><img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge&logo=license&colorB=purple" alt="License"></span>
|
||||
<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/mysql-%3E=5.7-brightgreen.svg?style=for-the-badge&logo=mysql&colorB=blue" alt="MySQL">
|
||||
<img src="https://img.shields.io/badge/thinkphp-%3E=8.0.0-brightgreen.svg?style=for-the-badge&logo=thinkphp" alt="ThinkPHP">
|
||||
<img src="https://img.shields.io/badge/layui-%3E=2.9.0-brightgreen.svg?style=for-the-badge&logo=layui&colorB=orange" alt="layui">
|
||||
<img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge&logo=license&colorB=purple" alt="License">
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
## `EasyAdmin8`所有版本 (当前项目为`ThinkPHP`版本)
|
||||
|
||||
| | Github | Gitee |
|
||||
|----------|:--------------------------------------------------------------------:|:-----------------------------------------------------------------:|
|
||||
| ThinkPHP | [EasyAdmin8](https://github.com/wolf-leo/EasyAdmin8) | [EasyAdmin8](https://gitee.com/wolf18/EasyAdmin8) |
|
||||
| Laravel | [EasyAdmin8-Laravel](https://github.com/wolf-leo/EasyAdmin8-Laravel) | [EasyAdmin8-Laravel](https://gitee.com/wolf18/EasyAdmin8-Laravel) |
|
||||
| webman | [EasyAdmin8-webman](https://github.com/wolf-leo/EasyAdmin8-webman) | [EasyAdmin8-webman](https://gitee.com/wolf18/EasyAdmin8-webman) |
|
||||
| | Github | Gitee |
|
||||
|----------|:----------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|
||||
| ThinkPHP | [EasyAdmin8](https://github.com/EasyAdmin8/EasyAdmin8) | [EasyAdmin8](https://gitee.com/EasyAdmin8/EasyAdmin8) |
|
||||
| Laravel | [EasyAdmin8-Laravel](https://github.com/EasyAdmin8/EasyAdmin8-Laravel) | [EasyAdmin8-Laravel](https://gitee.com/EasyAdmin8/EasyAdmin8-Laravel) |
|
||||
| webman | [EasyAdmin8-webman](https://github.com/EasyAdmin8/EasyAdmin8-webman) | [EasyAdmin8-webman](https://gitee.com/EasyAdmin8/EasyAdmin8-webman) |
|
||||
|
||||
## 项目介绍
|
||||
|
||||
> `EasyAdmin8` 在 [`EasyAdmin`](https://gitee.com/zhongshaofa/easyadmin) 的基础上更新 ThinkPHP 框架到 8.0 ,PHP 最低版本要求不低于 8.0
|
||||
> `EasyAdmin8` 在 [`EasyAdmin`](https://gitee.com/zhongshaofa/easyadmin) 的基础上更新 ThinkPHP 框架到 8.1+ ,PHP 最低版本要求不低于 8.1
|
||||
>
|
||||
> 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)
|
||||
>
|
||||
@@ -50,13 +54,13 @@ if [ -f /usr/bin/curl ];then curl -sSO https://easyadmin8.top/auto-install-EasyA
|
||||
```
|
||||
1.下载安装包
|
||||
|
||||
git clone https://github.com/wolf-leo/EasyAdmin8
|
||||
git clone https://github.com/EasyAdmin8/EasyAdmin8
|
||||
|
||||
或者
|
||||
|
||||
git clone https://gitee.com/wolf18/EasyAdmin8
|
||||
git clone https://gitee.com/EasyAdmin8/EasyAdmin8
|
||||
|
||||
2.安装依赖包(确保 PHP 版本 >= 8.0)
|
||||
2.安装依赖包(确保 PHP 版本 >= 8.1)
|
||||
|
||||
在根目录下 composer install ,如果有报错信息可以使用命令 composer install --ignore-platform-reqs
|
||||
|
||||
@@ -75,7 +79,7 @@ if [ -f /usr/bin/curl ];then curl -sSO https://easyadmin8.top/auto-install-EasyA
|
||||
|
||||
## CURD命令大全
|
||||
|
||||
> 参考 [CURD命令大全](CURD.md)
|
||||
> 参考 [CURD命令大全](https://edocs.easyadmin8.top/curd/command.html)
|
||||
|
||||
## 常见问题
|
||||
|
||||
@@ -97,7 +101,7 @@ if [ -f /usr/bin/curl ];then curl -sSO https://easyadmin8.top/auto-install-EasyA
|
||||
|
||||
## 相关文档
|
||||
|
||||
* [ThinkPHP 8.0](https://doc.thinkphp.cn/v8_0)
|
||||
* [ThinkPHP 8.1](https://doc.thinkphp.cn)
|
||||
|
||||
* [EasyAdmin](http://easyadmin.99php.cn/docs)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use app\admin\middleware\CheckInstall;
|
||||
use app\admin\middleware\CheckLogin;
|
||||
use app\admin\middleware\CheckAuth;
|
||||
use app\admin\middleware\SystemLog;
|
||||
use app\admin\middleware\RateLimiting;
|
||||
|
||||
// 你可以在这里继续写你需要的路由
|
||||
|
||||
@@ -16,6 +17,8 @@ use app\admin\middleware\SystemLog;
|
||||
|
||||
return [
|
||||
'middleware' => [
|
||||
// 限流中间件
|
||||
RateLimiting::class,
|
||||
// 判断是否已经安装后台系统
|
||||
CheckInstall::class,
|
||||
// 检测是否登录
|
||||
|
||||
@@ -109,24 +109,21 @@ class Ajax extends AdminController
|
||||
*/
|
||||
public function getUploadFiles(Request $request): Json
|
||||
{
|
||||
$get = $request->get();
|
||||
$page = !empty($get['page']) ? $get['page'] : 1;
|
||||
$limit = !empty($get['limit']) ? $get['limit'] : 10;
|
||||
$title = !empty($get['title']) ? $get['title'] : null;
|
||||
$this->model = new SystemUploadfile();
|
||||
$count = $this->model
|
||||
->where(function (Query $query) use ($title) {
|
||||
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
|
||||
})
|
||||
$get = $request->get();
|
||||
$page = !empty($get['page']) ? $get['page'] : 1;
|
||||
$limit = !empty($get['limit']) ? $get['limit'] : 10;
|
||||
$title = !empty($get['title']) ? $get['title'] : null;
|
||||
$count = SystemUploadfile::where(function(Query $query) use ($title) {
|
||||
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
|
||||
})
|
||||
->count();
|
||||
$list = $this->model
|
||||
->where(function (Query $query) use ($title) {
|
||||
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
|
||||
})
|
||||
$list = SystemUploadfile::where(function(Query $query) use ($title) {
|
||||
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
|
||||
})
|
||||
->page($page, $limit)
|
||||
->order($this->sort)
|
||||
->select()->toArray();
|
||||
$data = [
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '',
|
||||
'count' => $count,
|
||||
@@ -149,7 +146,7 @@ class Ajax extends AdminController
|
||||
$upload_allow_size = $uploadConfig['upload_allow_size'];
|
||||
$_upload_allow_ext = explode(',', $uploadConfig['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);
|
||||
$config = [
|
||||
@@ -213,4 +210,23 @@ class Ajax extends AdminController
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -141,7 +141,7 @@ class Index extends AdminController
|
||||
$old_secret = $row->ga_secret;
|
||||
$secret = $ga->createSecret(32);
|
||||
$ga_title = $this->isDemo ? 'EasyAdmin8演示环境' : '可自定义修改显示标题';
|
||||
$dataUri = $ga->getQRCode($ga_title, $secret)->getDataUri();
|
||||
$dataUri = $ga->getQRCode($ga_title, $secret);
|
||||
$this->assign(compact('row', 'dataUri', 'old_secret', 'secret'));
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
@@ -4,17 +4,19 @@ namespace app\admin\controller;
|
||||
|
||||
use app\admin\model\SystemAdmin;
|
||||
use app\common\controller\AdminController;
|
||||
use app\common\utils\Helper;
|
||||
use think\captcha\facade\Captcha;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use app\Request;
|
||||
use think\Response;
|
||||
use Wolfcode\RateLimiting\Attributes\RateLimitingMiddleware;
|
||||
|
||||
class Login extends AdminController
|
||||
{
|
||||
|
||||
protected bool $ignoreAuth = true;
|
||||
protected bool $ignoreLogin = true;
|
||||
|
||||
public function initialize(): void
|
||||
{
|
||||
@@ -34,6 +36,7 @@ class Login extends AdminController
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
#[RateLimitingMiddleware(key: [Helper::class, 'getIp'], seconds: 1, limit: 1, message: '请求过于频繁')]
|
||||
public function index(Request $request): string
|
||||
{
|
||||
$captcha = env('EASYADMIN.CAPTCHA', 1);
|
||||
|
||||
@@ -8,18 +8,14 @@ use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
use think\App;
|
||||
|
||||
/**
|
||||
* Class Admin
|
||||
* @package app\admin\controller\system
|
||||
* @ControllerAnnotation(title="商品分类管理")
|
||||
*/
|
||||
#[ControllerAnnotation(title: '商品分类管理')]
|
||||
class Cate extends AdminController
|
||||
{
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new MallCate();
|
||||
self::$model = MallCate::class;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,40 +4,38 @@ namespace app\admin\controller\mall;
|
||||
|
||||
use app\admin\model\MallCate;
|
||||
use app\admin\model\MallGoods;
|
||||
use app\admin\service\annotation\MiddlewareAnnotation;
|
||||
use app\common\controller\AdminController;
|
||||
use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
use app\Request;
|
||||
use think\App;
|
||||
use think\db\exception\DbException;
|
||||
use think\response\Json;
|
||||
use Wolfcode\Ai\Enum\AiType;
|
||||
use Wolfcode\Ai\Service\AiChatService;
|
||||
|
||||
/**
|
||||
* Class Goods
|
||||
* @package app\admin\controller\mall
|
||||
* @ControllerAnnotation(title="商城商品管理")
|
||||
*/
|
||||
#[ControllerAnnotation(title: '商城商品管理')]
|
||||
class Goods extends AdminController
|
||||
{
|
||||
|
||||
#[NodeAnnotation(ignore: ['export'])] // 过滤不需要生成的权限节点 默认 CURD 中会自动生成部分节点 可以在此处过滤
|
||||
protected array $ignoreNode;
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new MallGoods();
|
||||
$this->assign('cate', (new MallCate())->column('title', 'id'));
|
||||
self::$model = MallGoods::class;
|
||||
$this->assign('cate', MallCate::column('title', 'id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="列表")
|
||||
* @throws DbException
|
||||
*/
|
||||
#[NodeAnnotation(title: '列表', auth: true)]
|
||||
public function index(Request $request): Json|string
|
||||
{
|
||||
if ($request->isAjax()) {
|
||||
if (input('selectFields')) return $this->selectList();
|
||||
list($page, $limit, $where) = $this->buildTableParams();
|
||||
$count = $this->model->where($where)->count();
|
||||
$list = $this->model->with(['cate'])->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
|
||||
$count = self::$model::where($where)->count();
|
||||
$list = self::$model::with(['cate'])->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '',
|
||||
@@ -49,12 +47,10 @@ class Goods extends AdminController
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="入库")
|
||||
*/
|
||||
#[NodeAnnotation(title: '入库', auth: true)]
|
||||
public function stock(Request $request, $id): string
|
||||
{
|
||||
$row = $this->model->find($id);
|
||||
$row = self::$model::find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
if ($request->isPost()) {
|
||||
$post = $request->post();
|
||||
@@ -73,4 +69,67 @@ class Goods extends AdminController
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
#[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOGIN)]
|
||||
public function no_check_login(Request $request): string
|
||||
{
|
||||
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'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,14 +10,9 @@ use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
use app\Request;
|
||||
use think\App;
|
||||
use think\db\exception\DbException;
|
||||
use think\response\Json;
|
||||
|
||||
/**
|
||||
* Class Admin
|
||||
* @package app\admin\controller\system
|
||||
* @ControllerAnnotation(title="管理员管理")
|
||||
*/
|
||||
#[ControllerAnnotation(title: '管理员管理')]
|
||||
class Admin extends AdminController
|
||||
{
|
||||
|
||||
@@ -29,14 +24,11 @@ class Admin extends AdminController
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new SystemAdmin();
|
||||
$this->assign('auth_list', $this->model->getAuthList());
|
||||
self::$model = SystemAdmin::class;
|
||||
$this->assign('auth_list', self::$model::getAuthList());
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="列表")
|
||||
* @throws DbException
|
||||
*/
|
||||
#[NodeAnnotation(title: '列表', auth: true)]
|
||||
public function index(Request $request): Json|string
|
||||
{
|
||||
if ($request->isAjax()) {
|
||||
@@ -44,11 +36,8 @@ class Admin extends AdminController
|
||||
return $this->selectList();
|
||||
}
|
||||
list($page, $limit, $where) = $this->buildTableParams();
|
||||
$count = $this->model
|
||||
->where($where)
|
||||
->count();
|
||||
$list = $this->model
|
||||
->withoutField('password')
|
||||
$count = self::$model::where($where)->count();
|
||||
$list = self::$model::withoutField('password')
|
||||
->where($where)
|
||||
->page($page, $limit)
|
||||
->order($this->sort)
|
||||
@@ -64,9 +53,7 @@ class Admin extends AdminController
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="添加")
|
||||
*/
|
||||
#[NodeAnnotation(title: '添加', auth: true)]
|
||||
public function add(Request $request): string
|
||||
{
|
||||
if ($request->isPost()) {
|
||||
@@ -78,21 +65,19 @@ class Admin extends AdminController
|
||||
if (empty($post['password'])) $post['password'] = '123456';
|
||||
$post['password'] = password($post['password']);
|
||||
try {
|
||||
$save = $this->model->save($post);
|
||||
$save = self::$model::create($post);
|
||||
}catch (\Exception $e) {
|
||||
$this->error('保存失败');
|
||||
$this->error('保存失败' . $e->getMessage());
|
||||
}
|
||||
$save ? $this->success('保存成功') : $this->error('保存失败');
|
||||
}
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="编辑")
|
||||
*/
|
||||
#[NodeAnnotation(title: '编辑', auth: true)]
|
||||
public function edit(Request $request, $id = 0): string
|
||||
{
|
||||
$row = $this->model->find($id);
|
||||
$row = self::$model::find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
if ($request->isPost()) {
|
||||
$post = $request->post();
|
||||
@@ -100,28 +85,22 @@ class Admin extends AdminController
|
||||
$post['auth_ids'] = implode(',', array_keys($authIds));
|
||||
$rule = [];
|
||||
$this->validate($post, $rule);
|
||||
if (isset($row['password'])) {
|
||||
unset($row['password']);
|
||||
}
|
||||
try {
|
||||
$save = $row->save($post);
|
||||
TriggerService::updateMenu($id);
|
||||
}catch (\Exception $e) {
|
||||
$this->error('保存失败');
|
||||
$this->error('保存失败' . $e->getMessage());
|
||||
}
|
||||
$save ? $this->success('保存成功') : $this->error('保存失败');
|
||||
}
|
||||
$row->auth_ids = explode(',', $row->auth_ids ?: '');
|
||||
$this->assign('row', $row);
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="编辑")
|
||||
*/
|
||||
#[NodeAnnotation(title: '设置密码', auth: true)]
|
||||
public function password(Request $request, $id): string
|
||||
{
|
||||
$row = $this->model->find($id);
|
||||
$row = self::$model::find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
if ($request->isAjax()) {
|
||||
$post = $request->post();
|
||||
@@ -142,18 +121,16 @@ class Admin extends AdminController
|
||||
}
|
||||
$save ? $this->success('保存成功') : $this->error('保存失败');
|
||||
}
|
||||
$row->auth_ids = explode(',', $row->auth_ids ?: '');
|
||||
$this->assign('row', $row);
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="删除")
|
||||
*/
|
||||
public function delete($id): void
|
||||
#[NodeAnnotation(title: '删除', auth: true)]
|
||||
public function delete(Request $request): void
|
||||
{
|
||||
$this->checkPostRequest();
|
||||
$row = $this->model->whereIn('id', $id)->select();
|
||||
$id = $request->param('id');
|
||||
$row = self::$model::whereIn('id', $id)->select();
|
||||
$row->isEmpty() && $this->error('数据不存在');
|
||||
$id == AdminConstant::SUPER_ADMIN_ID && $this->error('超级管理员不允许修改');
|
||||
if (is_array($id)) {
|
||||
@@ -169,9 +146,7 @@ class Admin extends AdminController
|
||||
$save ? $this->success('删除成功') : $this->error('删除失败');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="属性修改")
|
||||
*/
|
||||
#[NodeAnnotation(title: '属性修改', auth: true)]
|
||||
public function modify(Request $request): void
|
||||
{
|
||||
$this->checkPostRequest();
|
||||
@@ -188,7 +163,7 @@ class Admin extends AdminController
|
||||
if ($post['id'] == AdminConstant::SUPER_ADMIN_ID && $post['field'] == 'status') {
|
||||
$this->error('超级管理员状态不允许修改');
|
||||
}
|
||||
$row = $this->model->find($post['id']);
|
||||
$row = self::$model::find($post['id']);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
try {
|
||||
$row->save([
|
||||
|
||||
@@ -11,11 +11,7 @@ use app\admin\service\annotation\NodeAnnotation;
|
||||
use app\Request;
|
||||
use think\App;
|
||||
|
||||
/**
|
||||
* @ControllerAnnotation(title="角色权限管理")
|
||||
* Class Auth
|
||||
* @package app\admin\controller\system
|
||||
*/
|
||||
#[ControllerAnnotation(title: '角色权限管理', auth: true)]
|
||||
class Auth extends AdminController
|
||||
{
|
||||
|
||||
@@ -27,34 +23,30 @@ class Auth extends AdminController
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new SystemAuth();
|
||||
self::$model = SystemAuth::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="授权")
|
||||
*/
|
||||
#[NodeAnnotation(title: '授权', auth: true)]
|
||||
public function authorize(Request $request, $id): string
|
||||
{
|
||||
$row = $this->model->find($id);
|
||||
$row = self::$model::find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
if ($request->isAjax()) {
|
||||
$list = $this->model->getAuthorizeNodeListByAdminId($id);
|
||||
$list = self::$model::getAuthorizeNodeListByAdminId($id);
|
||||
$this->success('获取成功', $list);
|
||||
}
|
||||
$this->assign('row', $row);
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="授权保存")
|
||||
*/
|
||||
#[NodeAnnotation(title: '授权保存', auth: true)]
|
||||
public function saveAuthorize(Request $request): void
|
||||
{
|
||||
$this->checkPostRequest();
|
||||
$id = $request->post('id');
|
||||
$node = $request->post('node', "[]");
|
||||
$node = json_decode($node, true);
|
||||
$row = $this->model->find($id);
|
||||
$row = self::$model::find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
try {
|
||||
$authNode = new SystemAuthNode();
|
||||
|
||||
@@ -12,33 +12,25 @@ use think\App;
|
||||
use think\facade\Cache;
|
||||
use think\response\Json;
|
||||
|
||||
/**
|
||||
* Class Config
|
||||
* @package app\admin\controller\system
|
||||
* @ControllerAnnotation(title="系统配置管理")
|
||||
*/
|
||||
#[ControllerAnnotation(title: '系统配置管理')]
|
||||
class Config extends AdminController
|
||||
{
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new SystemConfig();
|
||||
self::$model = SystemConfig::class;
|
||||
$this->assign('upload_types', config('admin.upload_types'));
|
||||
$this->assign('editor_types', config('admin.editor_types'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="列表")
|
||||
*/
|
||||
#[NodeAnnotation(title: '列表', auth: true)]
|
||||
public function index(Request $request): Json|string
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="保存")
|
||||
*/
|
||||
#[NodeAnnotation(title: '保存', auth: true)]
|
||||
public function save(Request $request): void
|
||||
{
|
||||
$this->checkPostRequest();
|
||||
@@ -50,25 +42,26 @@ class Config extends AdminController
|
||||
if ($group == 'upload') {
|
||||
$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) {
|
||||
if (in_array($key, $notAddFields)) continue;
|
||||
if ($this->model->where('name', $key)->count()) {
|
||||
$this->model->where('name', $key)->update(['value' => $val,]);
|
||||
if (self::$model::where('name', $key)->count()) {
|
||||
self::$model::where('name', $key)->update(['value' => $val,]);
|
||||
}else {
|
||||
$this->model->create(
|
||||
self::$model::create(
|
||||
[
|
||||
'name' => $key,
|
||||
'value' => $val,
|
||||
'group' => $group,
|
||||
]);
|
||||
}
|
||||
if (Cache::has($key)) Cache::set($key, $val);
|
||||
}
|
||||
TriggerService::updateMenu();
|
||||
TriggerService::updateSysConfig();
|
||||
}catch (\Exception $e) {
|
||||
$this->error('保存失败');
|
||||
$this->error('保存失败' . $e->getMessage());
|
||||
}
|
||||
$this->success('保存成功');
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace app\admin\controller\system;
|
||||
|
||||
use app\admin\service\curd\BuildCurd;
|
||||
use app\admin\service\curd\exceptions\TableException;
|
||||
use app\common\controller\AdminController;
|
||||
use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
@@ -15,24 +14,16 @@ use think\facade\Db;
|
||||
use think\helper\Str;
|
||||
use think\response\Json;
|
||||
|
||||
/**
|
||||
* @ControllerAnnotation(title="CURD可视化管理")
|
||||
* @package app\admin\controller\system
|
||||
*/
|
||||
#[ControllerAnnotation(title: 'CURD可视化管理')]
|
||||
class CurdGenerate extends AdminController
|
||||
{
|
||||
/**
|
||||
* @NodeAnnotation(title="列表")
|
||||
*/
|
||||
#[NodeAnnotation(title: '列表', auth: true)]
|
||||
public function index(Request $request): Json|string
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="操作")
|
||||
* @throws TableException
|
||||
*/
|
||||
#[NodeAnnotation(title: '操作', auth: true)]
|
||||
public function save(Request $request, string $type = ''): ?Json
|
||||
{
|
||||
if (!$request->isAjax()) $this->error();
|
||||
@@ -146,6 +137,7 @@ class CurdGenerate extends AdminController
|
||||
$command = $request->post('command', '');
|
||||
if (empty($command)) $this->error('请输入命令');
|
||||
$commandExp = explode(' ', $command);
|
||||
$commandExp = array_values(array_filter($commandExp));
|
||||
try {
|
||||
|
||||
$output = Console::call('curd', [...$commandExp]);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace app\admin\controller\system;
|
||||
|
||||
use app\admin\model\SystemLog;
|
||||
use app\admin\service\annotation\MiddlewareAnnotation;
|
||||
use app\admin\service\tool\CommonTool;
|
||||
use app\common\controller\AdminController;
|
||||
use app\admin\service\annotation\ControllerAnnotation;
|
||||
@@ -15,24 +16,16 @@ use think\db\exception\PDOException;
|
||||
use think\facade\Db;
|
||||
use think\response\Json;
|
||||
|
||||
/**
|
||||
* @ControllerAnnotation(title="操作日志管理")
|
||||
* Class Auth
|
||||
* @package app\admin\controller\system
|
||||
*/
|
||||
#[ControllerAnnotation(title: '操作日志管理')]
|
||||
class Log extends AdminController
|
||||
{
|
||||
protected array $ignoreLog = ['record'];
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new SystemLog();
|
||||
self::$model = SystemLog::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="列表")
|
||||
*/
|
||||
#[NodeAnnotation(title: '列表', auth: true)]
|
||||
public function index(Request $request): Json|string
|
||||
{
|
||||
if ($request->isAjax()) {
|
||||
@@ -41,7 +34,7 @@ class Log extends AdminController
|
||||
}
|
||||
[$page, $limit, $where, $excludeFields] = $this->buildTableParams(['month']);
|
||||
$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 {
|
||||
$count = $model->count();
|
||||
$list = $model->page($page, $limit)->order($this->sort)->select();
|
||||
@@ -60,16 +53,15 @@ class Log extends AdminController
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="导出")
|
||||
*/
|
||||
public function export(): bool
|
||||
#[NodeAnnotation(title: '导出', auth: true)]
|
||||
public function export()
|
||||
{
|
||||
if (env('EASYADMIN.IS_DEMO', false)) {
|
||||
$this->error('演示环境下不允许操作');
|
||||
}
|
||||
[$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));
|
||||
$prefix = config('database.connections.mysql.prefix');
|
||||
$dbList = Db::query("show full columns from {$prefix}{$tableName}");
|
||||
@@ -80,25 +72,64 @@ class Log extends AdminController
|
||||
$header[] = [$comment, $vo['Field']];
|
||||
}
|
||||
}
|
||||
$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 {
|
||||
$list = $model
|
||||
->where($where)
|
||||
->limit(100000)
|
||||
->limit(10000)
|
||||
->order('id', 'desc')
|
||||
->select()
|
||||
->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());
|
||||
}
|
||||
$fileName = time();
|
||||
return Excel::exportData($list, $header, $fileName, 'xlsx');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="框架日志")
|
||||
*/
|
||||
|
||||
#[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)]
|
||||
#[NodeAnnotation(title: '框架日志', auth: true, ignore: NodeAnnotation::IGNORE_NODE)]
|
||||
public function record(): Json|string
|
||||
{
|
||||
return (new \Wolfcode\PhpLogviewer\thinkphp\LogViewer())->fetch();
|
||||
|
||||
@@ -11,14 +11,9 @@ use app\admin\service\annotation\NodeAnnotation;
|
||||
use app\common\controller\AdminController;
|
||||
use app\Request;
|
||||
use think\App;
|
||||
use think\db\exception\DbException;
|
||||
use think\response\Json;
|
||||
|
||||
/**
|
||||
* Class Menu
|
||||
* @package app\admin\controller\system
|
||||
* @ControllerAnnotation(title="菜单管理",auth=true)
|
||||
*/
|
||||
#[ControllerAnnotation(title: '菜单管理')]
|
||||
class Menu extends AdminController
|
||||
{
|
||||
|
||||
@@ -30,21 +25,18 @@ class Menu extends AdminController
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new SystemMenu();
|
||||
self::$model = SystemMenu::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="列表")
|
||||
* @throws DbException
|
||||
*/
|
||||
#[NodeAnnotation(title: '列表', auth: true)]
|
||||
public function index(Request $request): Json|string
|
||||
{
|
||||
if ($request->isAjax()) {
|
||||
if (input('selectFields')) {
|
||||
return $this->selectList();
|
||||
}
|
||||
$count = $this->model->count();
|
||||
$list = $this->model->order($this->sort)->select()->toArray();
|
||||
$count = self::$model::count();
|
||||
$list = self::$model::order($this->sort)->select()->toArray();
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '',
|
||||
@@ -56,13 +48,11 @@ class Menu extends AdminController
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="添加")
|
||||
*/
|
||||
#[NodeAnnotation(title: '添加', auth: true)]
|
||||
public function add(Request $request): string
|
||||
{
|
||||
$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) {
|
||||
$this->error('首页不能添加子菜单');
|
||||
}
|
||||
@@ -75,7 +65,7 @@ class Menu extends AdminController
|
||||
];
|
||||
$this->validate($post, $rule);
|
||||
try {
|
||||
$save = $this->model->save($post);
|
||||
$save = self::$model::create($post);
|
||||
}catch (\Exception $e) {
|
||||
$this->error('保存失败');
|
||||
}
|
||||
@@ -86,18 +76,16 @@ class Menu extends AdminController
|
||||
$this->error('保存失败');
|
||||
}
|
||||
}
|
||||
$pidMenuList = $this->model->getPidMenuList();
|
||||
$pidMenuList = self::$model::getPidMenuList();
|
||||
$this->assign('id', $id);
|
||||
$this->assign('pidMenuList', $pidMenuList);
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="编辑")
|
||||
*/
|
||||
#[NodeAnnotation(title: '编辑', auth: true)]
|
||||
public function edit(Request $request, $id = 0): string
|
||||
{
|
||||
$row = $this->model->find($id);
|
||||
$row = self::$model::find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
if ($request->isPost()) {
|
||||
$post = $request->post();
|
||||
@@ -120,7 +108,7 @@ class Menu extends AdminController
|
||||
$this->error('保存失败');
|
||||
}
|
||||
}
|
||||
$pidMenuList = $this->model->getPidMenuList();
|
||||
$pidMenuList = self::$model::getPidMenuList();
|
||||
$this->assign([
|
||||
'id' => $id,
|
||||
'pidMenuList' => $pidMenuList,
|
||||
@@ -129,13 +117,12 @@ class Menu extends AdminController
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="删除")
|
||||
*/
|
||||
public function delete($id): void
|
||||
#[NodeAnnotation(title: '删除', auth: true)]
|
||||
public function delete(Request $request): void
|
||||
{
|
||||
$this->checkPostRequest();
|
||||
$row = $this->model->whereIn('id', $id)->select();
|
||||
$id = $request->param('id');
|
||||
$row = self::$model::whereIn('id', $id)->select();
|
||||
empty($row) && $this->error('数据不存在');
|
||||
try {
|
||||
$save = $row->delete();
|
||||
@@ -150,9 +137,7 @@ class Menu extends AdminController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="属性修改")
|
||||
*/
|
||||
#[NodeAnnotation(title: '属性修改', auth: true)]
|
||||
public function modify(Request $request): void
|
||||
{
|
||||
$this->checkPostRequest();
|
||||
@@ -163,17 +148,16 @@ class Menu extends AdminController
|
||||
'value|值' => 'require',
|
||||
];
|
||||
$this->validate($post, $rule);
|
||||
$row = $this->model->find($post['id']);
|
||||
$row = self::$model::find($post['id']);
|
||||
if (!$row) {
|
||||
$this->error('数据不存在');
|
||||
}
|
||||
if (!in_array($post['field'], $this->allowModifyFields)) {
|
||||
$this->error('该字段不允许修改:' . $post['field']);
|
||||
}
|
||||
$homeId = $this->model
|
||||
->where([
|
||||
'pid' => MenuConstant::HOME_PID,
|
||||
])
|
||||
$homeId = self::$model::where([
|
||||
'pid' => MenuConstant::HOME_PID,
|
||||
])
|
||||
->value('id');
|
||||
if ($post['id'] == $homeId && $post['field'] == 'status') {
|
||||
$this->error('首页状态不允许关闭');
|
||||
@@ -189,9 +173,7 @@ class Menu extends AdminController
|
||||
$this->success('保存成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="添加菜单提示")
|
||||
*/
|
||||
#[NodeAnnotation(title: '添加菜单提示', auth: true)]
|
||||
public function getMenuTips(): Json
|
||||
{
|
||||
$node = input('get.keywords');
|
||||
|
||||
@@ -10,37 +10,30 @@ use app\admin\service\annotation\NodeAnnotation;
|
||||
use app\admin\service\NodeService;
|
||||
use app\Request;
|
||||
use think\App;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\response\Json;
|
||||
|
||||
/**
|
||||
* @ControllerAnnotation(title="系统节点管理")
|
||||
* Class Node
|
||||
* @package app\admin\controller\system
|
||||
*/
|
||||
#[ControllerAnnotation(title: '系统节点管理')]
|
||||
class Node extends AdminController
|
||||
{
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new SystemNode();
|
||||
self::$model = SystemNode::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="列表")
|
||||
* @throws DbException
|
||||
*/
|
||||
#[NodeAnnotation(title: '列表', auth: true)]
|
||||
public function index(Request $request): Json|string
|
||||
{
|
||||
if ($request->isAjax()) {
|
||||
if (input('selectFields')) {
|
||||
return $this->selectList();
|
||||
}
|
||||
$count = $this->model
|
||||
->count();
|
||||
$list = $this->model
|
||||
->getNodeTreeList();
|
||||
$count = self::$model::count();
|
||||
$list = self::$model::getNodeTreeList();
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '',
|
||||
@@ -52,24 +45,21 @@ class Node extends AdminController
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="系统节点更新")
|
||||
*/
|
||||
#[NodeAnnotation(title: '系统节点更新', auth: true)]
|
||||
public function refreshNode($force = 0): void
|
||||
{
|
||||
|
||||
$this->checkPostRequest();
|
||||
$nodeList = (new NodeService())->getNodeList();
|
||||
empty($nodeList) && $this->error('暂无需要更新的系统节点');
|
||||
$model = new SystemNode();
|
||||
|
||||
try {
|
||||
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');
|
||||
foreach ($updateNodeList as $vo) {
|
||||
isset($formatNodeList[$vo['node']])
|
||||
&& $model->where('id', $vo['id'])->update(
|
||||
&& self::$model::where('id', $vo['id'])->update(
|
||||
[
|
||||
'title' => $formatNodeList[$vo['node']]['title'],
|
||||
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
|
||||
@@ -77,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 ($existNodeList as $v) {
|
||||
if ($vo['node'] == $v->node) {
|
||||
@@ -86,27 +76,26 @@ class Node extends AdminController
|
||||
}
|
||||
}
|
||||
}
|
||||
$model->saveAll($nodeList);
|
||||
TriggerService::updateNode();
|
||||
if (!empty($nodeList)) {
|
||||
(new self::$model)->saveAll($nodeList);
|
||||
TriggerService::updateNode();
|
||||
}
|
||||
}catch (\Exception $e) {
|
||||
$this->error('节点更新失败');
|
||||
}
|
||||
$this->success('节点更新成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="清除失效节点")
|
||||
*/
|
||||
#[NodeAnnotation(title: '清除失效节点', auth: true)]
|
||||
public function clearNode(): void
|
||||
{
|
||||
$this->checkPostRequest();
|
||||
$nodeList = (new NodeService())->getNodeList();
|
||||
$model = new SystemNode();
|
||||
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');
|
||||
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();
|
||||
}catch (\Exception $e) {
|
||||
|
||||
@@ -9,11 +9,7 @@ use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
use think\App;
|
||||
|
||||
/**
|
||||
* @ControllerAnnotation(title="快捷入口管理")
|
||||
* Class Quick
|
||||
* @package app\admin\controller\system
|
||||
*/
|
||||
#[ControllerAnnotation(title: '快捷入口管理')]
|
||||
class Quick extends AdminController
|
||||
{
|
||||
|
||||
@@ -25,7 +21,7 @@ class Quick extends AdminController
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new SystemQuick();
|
||||
self::$model = SystemQuick::class;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,17 +8,14 @@ use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
use think\App;
|
||||
|
||||
/**
|
||||
* @ControllerAnnotation(title="上传文件管理")
|
||||
* @package app\admin\controller\system
|
||||
*/
|
||||
#[ControllerAnnotation(title: '上传文件管理')]
|
||||
class Uploadfile extends AdminController
|
||||
{
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new SystemUploadfile();
|
||||
self::$model = SystemUploadfile::class;
|
||||
$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('无权限访问');
|
||||
// 判断是否为演示环境
|
||||
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);
|
||||
|
||||
@@ -7,6 +7,7 @@ use app\Request;
|
||||
use Closure;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use app\admin\service\annotation\MiddlewareAnnotation;
|
||||
|
||||
class CheckLogin
|
||||
{
|
||||
@@ -24,13 +25,25 @@ class CheckLogin
|
||||
$controllerClass = 'app\\admin\\controller\\' . $controller;
|
||||
$classObj = new ReflectionClass($controllerClass);
|
||||
$properties = $classObj->getDefaultProperties();
|
||||
$ignoreAuth = $properties['ignoreAuth'] ?? false;
|
||||
$adminUserInfo = session('admin');
|
||||
if (!$ignoreAuth) {
|
||||
// 整个控制器是否忽略登录
|
||||
$ignoreLogin = $properties['ignoreLogin'] ?? false;
|
||||
$adminUserInfo = session('admin');
|
||||
if (!$ignoreLogin) {
|
||||
$noNeedCheck = $properties['noNeedCheck'] ?? [];
|
||||
if (in_array($action, $noNeedCheck)) {
|
||||
return $next($request);
|
||||
}
|
||||
try {
|
||||
$reflectionMethod = new \ReflectionMethod($controllerClass, $action);
|
||||
$attributes = $reflectionMethod->getAttributes(MiddlewareAnnotation::class);
|
||||
foreach ($attributes as $attribute) {
|
||||
$annotation = $attribute->newInstance();
|
||||
$_ignore = (array)$annotation->ignore;
|
||||
// 控制器中的某个方法忽略登录
|
||||
if (in_array('LOGIN', $_ignore)) return $next($request);
|
||||
}
|
||||
}catch (\Throwable) {
|
||||
}
|
||||
if (empty($adminUserInfo)) {
|
||||
return redirect(__url('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);
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,12 @@
|
||||
namespace app\admin\middleware;
|
||||
|
||||
use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\MiddlewareAnnotation;
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
use app\admin\service\SystemLogService;
|
||||
use app\common\traits\JumpTrait;
|
||||
use app\Request;
|
||||
use ReflectionClass;
|
||||
use Closure;
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\Common\Annotations\DocParser;
|
||||
use ReflectionException;
|
||||
|
||||
class SystemLog
|
||||
@@ -34,7 +32,8 @@ class SystemLog
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$response = $next($request);
|
||||
$params = $request->param();
|
||||
if (!env('APP_ADMIN_SYSTEM_LOG', true)) return $response;
|
||||
$params = $request->param();
|
||||
if (isset($params['s'])) unset($params['s']);
|
||||
foreach ($params as $key => $val) {
|
||||
in_array($key, $this->sensitiveParams) && $params[$key] = "***********";
|
||||
@@ -56,19 +55,27 @@ class SystemLog
|
||||
$pathInfoExp = explode('.', $pathInfoExp[0] ?? '');
|
||||
$_name = $pathInfoExp[0] ?? '';
|
||||
$_controller = ucfirst($pathInfoExp[1] ?? '');
|
||||
if ($_name && $_controller && $_action) {
|
||||
$className = "app\admin\controller\\{$_name}\\{$_controller}";
|
||||
$reflectionClass = new \ReflectionClass($className);
|
||||
$properties = $reflectionClass->getDefaultProperties();
|
||||
$ignoreLog = $properties['ignoreLog'] ?? [];
|
||||
if (in_array($_action, $ignoreLog)) return $response;
|
||||
$parser = new DocParser();
|
||||
$parser->setIgnoreNotImportedAnnotations(true);
|
||||
$reader = new AnnotationReader($parser);
|
||||
$controllerAnnotation = $reader->getClassAnnotation($reflectionClass, ControllerAnnotation::class);
|
||||
$reflectionAction = $reflectionClass->getMethod($_action);
|
||||
$nodeAnnotation = $reader->getMethodAnnotation($reflectionAction, NodeAnnotation::class);
|
||||
$title = $controllerAnnotation->title . ' - ' . $nodeAnnotation->title;
|
||||
$className = $_controller ? "app\admin\controller\\{$_name}\\{$_controller}" : "app\admin\controller\\{$_name}";
|
||||
if ($_name && $_action) {
|
||||
$reflectionMethod = new \ReflectionMethod($className, $_action);
|
||||
$attributes = $reflectionMethod->getAttributes(MiddlewareAnnotation::class);
|
||||
foreach ($attributes as $attribute) {
|
||||
$annotation = $attribute->newInstance();
|
||||
$_ignore = (array)$annotation->ignore;
|
||||
if (in_array('log', array_map('strtolower', $_ignore))) return $response;
|
||||
}
|
||||
$controllerTitle = $nodeTitle = '';
|
||||
$controllerAttributes = (new \ReflectionClass($className))->getAttributes(ControllerAnnotation::class);
|
||||
$actionAttributes = $reflectionMethod->getAttributes(NodeAnnotation::class);
|
||||
foreach ($controllerAttributes as $controllerAttribute) {
|
||||
$controllerAnnotation = $controllerAttribute->newInstance();
|
||||
$controllerTitle = $controllerAnnotation->title ?? '';
|
||||
}
|
||||
foreach ($actionAttributes as $actionAttribute) {
|
||||
$actionAnnotation = $actionAttribute->newInstance();
|
||||
$nodeTitle = $actionAnnotation->title ?? '';
|
||||
}
|
||||
$title = $controllerTitle . ' - ' . $nodeTitle;
|
||||
}
|
||||
}catch (\Throwable $exception) {
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@ use app\common\model\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
|
||||
{
|
||||
|
||||
protected $table = "";
|
||||
|
||||
protected $deleteTime = 'delete_time';
|
||||
protected function getOptions(): array
|
||||
{
|
||||
return [
|
||||
'deleteTime' => 'delete_time',
|
||||
];
|
||||
}
|
||||
|
||||
// * +++++++++++++++++++++++++++
|
||||
// | 以下两种写法适用于 with 关联
|
||||
|
||||
@@ -8,7 +8,12 @@ use app\common\model\TimeModel;
|
||||
class SystemAdmin extends TimeModel
|
||||
{
|
||||
|
||||
protected $deleteTime = 'delete_time';
|
||||
protected function getOptions(): array
|
||||
{
|
||||
return [
|
||||
'deleteTime' => 'delete_time',
|
||||
];
|
||||
}
|
||||
|
||||
public array $notes = [
|
||||
'login_type' => [
|
||||
@@ -17,12 +22,15 @@ class SystemAdmin extends TimeModel
|
||||
],
|
||||
];
|
||||
|
||||
public function getAuthList()
|
||||
public static function getAuthIdsAttr($value): array
|
||||
{
|
||||
$list = (new SystemAuth())
|
||||
->where('status', 1)
|
||||
->column('title', 'id');
|
||||
return $list;
|
||||
if (!$value) return [];
|
||||
return explode(',', $value);
|
||||
}
|
||||
|
||||
public static function getAuthList(): array
|
||||
{
|
||||
return SystemAuth::where('status', 1)->column('title', 'id');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,44 +3,52 @@
|
||||
namespace app\admin\model;
|
||||
|
||||
use app\common\model\TimeModel;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
|
||||
class SystemAuth extends TimeModel
|
||||
{
|
||||
|
||||
protected $deleteTime = 'delete_time';
|
||||
protected function getOptions(): array
|
||||
{
|
||||
return [
|
||||
'deleteTime' => 'delete_time',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID获取授权节点
|
||||
* @param $authId
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getAuthorizeNodeListByAdminId($authId)
|
||||
public static function getAuthorizeNodeListByAdminId($authId): array
|
||||
{
|
||||
$checkNodeList = (new SystemAuthNode())
|
||||
->where('auth_id', $authId)
|
||||
->column('node_id');
|
||||
$systemNode = new SystemNode();
|
||||
$nodelList = $systemNode
|
||||
$systemNode = new SystemNode();
|
||||
$nodeList = $systemNode
|
||||
->where('is_auth', 1)
|
||||
->field('id,node,title,type,is_auth')
|
||||
->select()
|
||||
->toArray();
|
||||
$newNodeList = [];
|
||||
foreach ($nodelList as $vo) {
|
||||
$newNodeList = [];
|
||||
foreach ($nodeList as $vo) {
|
||||
if ($vo['type'] == 1) {
|
||||
$vo = array_merge($vo, ['field' => 'node', 'spread' => true]);
|
||||
$vo = array_merge($vo, ['field' => 'node', 'spread' => true]);
|
||||
$vo['checked'] = false;
|
||||
$vo['title'] = "{$vo['title']}【{$vo['node']}】";
|
||||
$children = [];
|
||||
foreach ($nodelList as $v) {
|
||||
$vo['title'] = "{$vo['title']}【{$vo['node']}】";
|
||||
$children = [];
|
||||
foreach ($nodeList as $v) {
|
||||
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['title'] = "{$v['title']}【{$v['node']}】";
|
||||
$children[] = $v;
|
||||
$v['title'] = "{$v['title']}【{$v['node']}】";
|
||||
$children[] = $v;
|
||||
}
|
||||
}
|
||||
!empty($children) && $vo['children'] = $children;
|
||||
|
||||
@@ -4,24 +4,23 @@ namespace app\admin\model;
|
||||
|
||||
use app\admin\service\SystemLogService;
|
||||
use app\common\model\TimeModel;
|
||||
use think\model\relation\BelongsTo;
|
||||
|
||||
class SystemLog extends TimeModel
|
||||
{
|
||||
|
||||
public function __construct(array $data = [])
|
||||
{
|
||||
parent::__construct($data);
|
||||
$this->name = 'system_log_' . date('Ym');
|
||||
}
|
||||
protected array $type = [
|
||||
'content' => 'json',
|
||||
'response' => 'json',
|
||||
];
|
||||
|
||||
public function setMonth($month)
|
||||
protected function init(): void
|
||||
{
|
||||
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');
|
||||
}
|
||||
|
||||
@@ -4,31 +4,41 @@ namespace app\admin\model;
|
||||
|
||||
use app\common\constants\MenuConstant;
|
||||
use app\common\model\TimeModel;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
|
||||
class SystemMenu extends TimeModel
|
||||
{
|
||||
|
||||
protected $deleteTime = 'delete_time';
|
||||
|
||||
public function getPidMenuList()
|
||||
protected function getOptions(): array
|
||||
{
|
||||
$list = $this->field('id,pid,title')
|
||||
->where([
|
||||
['pid', '<>', MenuConstant::HOME_PID],
|
||||
['status', '=', 1],
|
||||
])
|
||||
->select()
|
||||
->toArray();
|
||||
$pidMenuList = $this->buildPidMenu(0, $list);
|
||||
$pidMenuList = array_merge([[
|
||||
return [
|
||||
'deleteTime' => 'delete_time',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ModelNotFoundException
|
||||
* @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,
|
||||
'pid' => 0,
|
||||
'title' => '顶级菜单',
|
||||
]], $pidMenuList);
|
||||
return $pidMenuList;
|
||||
}
|
||||
|
||||
protected function buildPidMenu($pid, $list, $level = 0)
|
||||
protected static function buildPidMenu($pid, $list, $level = 0): array
|
||||
{
|
||||
$newList = [];
|
||||
foreach ($list as $vo) {
|
||||
@@ -47,7 +57,7 @@ class SystemMenu extends TimeModel
|
||||
$vo['title'] = $markString . $vo['title'];
|
||||
}
|
||||
$newList[] = $vo;
|
||||
$childList = $this->buildPidMenu($vo['id'], $list, $level);
|
||||
$childList = self::buildPidMenu($vo['id'], $list, $level);
|
||||
!empty($childList) && $newList = array_merge($newList, $childList);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,22 +7,21 @@ use app\common\model\TimeModel;
|
||||
class SystemNode extends TimeModel
|
||||
{
|
||||
|
||||
public function getNodeTreeList()
|
||||
public static function getNodeTreeList(): array
|
||||
{
|
||||
$list = $this->select()->toArray();
|
||||
$list = $this->buildNodeTree($list);
|
||||
return $list;
|
||||
$list = self::select()->toArray();
|
||||
return self::buildNodeTree($list);
|
||||
}
|
||||
|
||||
protected function buildNodeTree($list)
|
||||
protected static function buildNodeTree($list): array
|
||||
{
|
||||
$newList = [];
|
||||
$newList = [];
|
||||
$repeatString = " ";
|
||||
foreach ($list as $vo) {
|
||||
if ($vo['type'] == 1) {
|
||||
$newList[] = $vo;
|
||||
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'];
|
||||
$newList[] = $v;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@ use app\common\model\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()
|
||||
{
|
||||
$version = cache('version');
|
||||
$version = cache('site_version');
|
||||
if (empty($version)) {
|
||||
$version = sysConfig('site', 'site_version');
|
||||
cache('site_version', $version);
|
||||
Cache::set('version', $version, 3600);
|
||||
}
|
||||
return $version;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace app\admin\service;
|
||||
|
||||
use app\admin\model\SystemUploadfile;
|
||||
use OSS\Core\OssException;
|
||||
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
|
||||
use OSS\OssClient;
|
||||
use think\facade\Env;
|
||||
use think\file\UploadedFile;
|
||||
@@ -112,10 +113,21 @@ class UploadService
|
||||
$accessKeySecret = $config['oss_access_key_secret'];
|
||||
$endpoint = $config['oss_endpoint'];
|
||||
$bucket = $config['oss_bucket'];
|
||||
// 升级 aliyuncs/oss-sdk-php 到 v2.7.2 以上, 使用签名 v4 版本
|
||||
putenv('OSS_ACCESS_KEY_ID=' . $accessKeyId);
|
||||
putenv('OSS_ACCESS_KEY_SECRET=' . $accessKeySecret);
|
||||
$region = str_replace(['http://oss-', 'https://oss-', 'oss-'], '', explode('.aliyuncs.com', $endpoint)[0] ?? '');
|
||||
$provider = new EnvironmentVariableCredentialsProvider();
|
||||
$args = [
|
||||
"provider" => $provider,
|
||||
"endpoint" => $endpoint,
|
||||
"signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
|
||||
"region" => $region
|
||||
];
|
||||
if ($file->isValid()) {
|
||||
$object = $this->setFilePath($file, Env::get('EASYADMIN.OSS_STATIC_PREFIX', 'easyadmin8') . '/');
|
||||
try {
|
||||
$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
|
||||
$ossClient = new OssClient($args);
|
||||
$_rs = $ossClient->putObject($bucket, $object, file_get_contents($file->getRealPath()));
|
||||
$oss_request_url = $_rs['oss-request-url'] ?? '';
|
||||
if (empty($oss_request_url)) return ['code' => 0, 'data' => '上传至OSS失败'];
|
||||
@@ -164,7 +176,7 @@ class UploadService
|
||||
if (empty($location)) return ['code' => 0, 'data' => '上传至COS失败'];
|
||||
$location = 'https://' . $location;
|
||||
$this->setSaveData($file);
|
||||
} catch (Exception $e) {
|
||||
}catch (Exception $e) {
|
||||
return ['code' => 0, 'data' => $e->getMessage()];
|
||||
}
|
||||
$data = ['url' => $location];
|
||||
|
||||
@@ -2,38 +2,20 @@
|
||||
|
||||
namespace app\admin\service\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation\Attributes;
|
||||
use Doctrine\Common\Annotations\Annotation\Required;
|
||||
use Doctrine\Common\Annotations\Annotation\Target;
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Class ControllerAnnotation
|
||||
*
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
* @Attributes({
|
||||
* @Attribute("title", type="string"),
|
||||
* })
|
||||
*
|
||||
* @since 2.0
|
||||
* controller 节点注解类
|
||||
*/
|
||||
#[Attribute]
|
||||
final class ControllerAnnotation
|
||||
{
|
||||
|
||||
/**
|
||||
* Route group prefix for the controller
|
||||
*
|
||||
* @Required()
|
||||
*
|
||||
* @var string
|
||||
* @param string $title
|
||||
* @param bool $auth 是否需要权限
|
||||
* @param string|array $ignore
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* 是否开启权限控制
|
||||
* @Enum({true,false})
|
||||
* @var bool
|
||||
*/
|
||||
public $auth = true;
|
||||
|
||||
public function __construct(public string $title = '', public bool $auth = true, public string|array $ignore = '')
|
||||
{
|
||||
}
|
||||
}
|
||||
19
app/admin/service/annotation/MiddlewareAnnotation.php
Normal file
19
app/admin/service/annotation/MiddlewareAnnotation.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\service\annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
final class MiddlewareAnnotation
|
||||
{
|
||||
/** 过滤日志 */
|
||||
const IGNORE_LOG = 'LOG';
|
||||
|
||||
/** 免登录 */
|
||||
const IGNORE_LOGIN = 'LOGIN';
|
||||
|
||||
public function __construct(public string $type = '', public string|array $ignore = '')
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -2,32 +2,24 @@
|
||||
|
||||
namespace app\admin\service\annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation\Attributes;
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* 创建节点注解类
|
||||
*
|
||||
* @Annotation
|
||||
* @Target({"METHOD","CLASS"})
|
||||
* @Attributes({
|
||||
* @Attribute("time", type = "int")
|
||||
* })
|
||||
* action 节点注解类
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD| Attribute::TARGET_PROPERTY)]
|
||||
final class NodeAnnotation
|
||||
{
|
||||
/** 过滤节点 */
|
||||
const IGNORE_NODE = 'NODE';
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
* @Required()
|
||||
* @var string
|
||||
* @param string $title
|
||||
* @param bool $auth 是否需要权限
|
||||
* @param string|array $ignore
|
||||
*/
|
||||
public string $title;
|
||||
|
||||
/**
|
||||
* 是否开启权限控制
|
||||
* @Enum({true,false})
|
||||
* @var bool
|
||||
*/
|
||||
public bool $auth = true;
|
||||
public function __construct(public string $title = '', public bool $auth = true, public string|array $ignore = '')
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@@ -67,15 +67,23 @@ class Node
|
||||
|
||||
// 遍历读取所有方法的注释的参数信息
|
||||
foreach ($methods as $method) {
|
||||
// 读取NodeAnnotation的注解
|
||||
$nodeAnnotation = $reader->getMethodAnnotation($method, NodeAnnotation::class);
|
||||
if (!empty($nodeAnnotation)) {
|
||||
$actionTitle = !empty($nodeAnnotation->title) ? $nodeAnnotation->title : null;
|
||||
$actionAuth = !empty($nodeAnnotation->auth) ? $nodeAnnotation->auth : false;
|
||||
|
||||
// 忽略掉不需要的节点
|
||||
$property = $reflectionClass->getProperty('ignoreNode');
|
||||
$propertyAttributes = $property->getAttributes(NodeAnnotation::class);
|
||||
if (!empty($propertyAttributes[0])) {
|
||||
$propertyAttribute = $propertyAttributes[0]->newInstance();
|
||||
if (in_array($method->name, $propertyAttribute->ignore)) continue;
|
||||
}
|
||||
|
||||
$attributes = $reflectionClass->getMethod($method->name)->getAttributes(NodeAnnotation::class);
|
||||
foreach ($attributes as $attribute) {
|
||||
$annotation = $attribute->newInstance();
|
||||
if (!empty($annotation->ignore)) if (strtolower($annotation->ignore) == 'node') continue;
|
||||
$actionList[] = [
|
||||
'node' => $controllerFormat . '/' . $method->name,
|
||||
'title' => $actionTitle,
|
||||
'is_auth' => $actionAuth,
|
||||
'title' => $annotation->title ?? null,
|
||||
'is_auth' => $annotation->auth ?? false,
|
||||
'type' => 2,
|
||||
];
|
||||
}
|
||||
@@ -83,16 +91,17 @@ class Node
|
||||
// 方法非空才读取控制器注解
|
||||
if (!empty($actionList)) {
|
||||
// 读取Controller的注解
|
||||
$controllerAnnotation = $reader->getClassAnnotation($reflectionClass, ControllerAnnotation::class);
|
||||
$controllerTitle = !empty($controllerAnnotation->title) ? $controllerAnnotation->title : null;
|
||||
$controllerAuth = !empty($controllerAnnotation->auth) ? $controllerAnnotation->auth : false;
|
||||
$nodeList[] = [
|
||||
'node' => $controllerFormat,
|
||||
'title' => $controllerTitle,
|
||||
'is_auth' => $controllerAuth,
|
||||
'type' => 1,
|
||||
];
|
||||
$nodeList = array_merge($nodeList, $actionList);
|
||||
$attributes = $reflectionClass->getAttributes(ControllerAnnotation::class);
|
||||
foreach ($attributes as $attribute) {
|
||||
$controllerAnnotation = $attribute->newInstance();
|
||||
$nodeList[] = [
|
||||
'node' => $controllerFormat,
|
||||
'title' => $controllerAnnotation->title ?? null,
|
||||
'is_auth' => $controllerAnnotation->auth ?? false,
|
||||
'type' => 1,
|
||||
];
|
||||
}
|
||||
$nodeList = array_merge($nodeList, $actionList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ class BuildCurd
|
||||
}
|
||||
}
|
||||
$this->tableComment = $this->table;
|
||||
}catch (Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
throw new TableException($e->getMessage());
|
||||
}
|
||||
|
||||
@@ -308,11 +308,11 @@ class BuildCurd
|
||||
$nodeArray = explode('_', $this->table);
|
||||
if (count($nodeArray) == 1) {
|
||||
$this->controllerFilename = ucfirst($nodeArray[0]);
|
||||
}else {
|
||||
} else {
|
||||
foreach ($nodeArray as $k => $v) {
|
||||
if ($k == 0) {
|
||||
$this->controllerFilename = "{$v}{$this->DS}";
|
||||
}else {
|
||||
} else {
|
||||
$this->controllerFilename .= ucfirst($v);
|
||||
}
|
||||
}
|
||||
@@ -355,6 +355,7 @@ class BuildCurd
|
||||
if (!empty($bindSelectField) && !in_array($bindSelectField, array_column($columns, 'Field'))) {
|
||||
throw new TableException("关联表{$relationTable}不存在该字段: {$bindSelectField}");
|
||||
}
|
||||
$onlyFields = [];
|
||||
foreach ($columns as $vo) {
|
||||
if (empty($primaryKey) && $vo['Key'] == 'PRI') {
|
||||
$primaryKey = $vo['Field'];
|
||||
@@ -362,6 +363,7 @@ class BuildCurd
|
||||
if (!empty($onlyShowFields) && !in_array($vo['Field'], $onlyShowFields)) {
|
||||
continue;
|
||||
}
|
||||
if (!empty($onlyShowFields)) $onlyFields[] = $vo['Field'];
|
||||
$colum = [
|
||||
'type' => $vo['Type'],
|
||||
'comment' => $vo['Comment'],
|
||||
@@ -388,15 +390,16 @@ class BuildCurd
|
||||
'bindSelectField' => $bindSelectField,
|
||||
'delete' => $delete,
|
||||
'tableColumns' => $formatColumns,
|
||||
'onlyFields' => $onlyFields,
|
||||
];
|
||||
if (!empty($bindSelectField)) {
|
||||
$relationArray = explode('\\', $modelFilename);
|
||||
$this->tableColumns[$foreignKey]['bindSelectField'] = $bindSelectField;
|
||||
$this->tableColumns[$foreignKey]['bindRelation'] = end($relationArray);
|
||||
$this->tableColumns[$foreignKey]['bindRelation'] = lcfirst(end($relationArray)) . ucfirst($bindSelectField);
|
||||
}
|
||||
$this->relationArray[$relationTable] = $relation;
|
||||
$this->selectFields[] = $foreignKey;
|
||||
}catch (Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
throw new TableException($e->getMessage());
|
||||
}
|
||||
return $this;
|
||||
@@ -652,7 +655,6 @@ class BuildCurd
|
||||
if (in_array($key, ['describe', 'content', 'details'])) {
|
||||
$this->editorFields[] = $key;
|
||||
}
|
||||
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
@@ -706,7 +708,7 @@ class BuildCurd
|
||||
}
|
||||
}
|
||||
!empty($formatDefine) && $colum['define'] = $formatDefine;
|
||||
}else {
|
||||
} else {
|
||||
$colum['define'] = $define;
|
||||
}
|
||||
}
|
||||
@@ -730,7 +732,8 @@ class BuildCurd
|
||||
$this->getTemplate("controller{$this->DS}select"),
|
||||
[
|
||||
'name' => $name,
|
||||
]);
|
||||
]
|
||||
);
|
||||
return $selectCode;
|
||||
}
|
||||
|
||||
@@ -754,7 +757,8 @@ class BuildCurd
|
||||
[
|
||||
'name' => $name,
|
||||
'values' => $values,
|
||||
]);
|
||||
]
|
||||
);
|
||||
return $selectCode;
|
||||
}
|
||||
|
||||
@@ -775,7 +779,8 @@ class BuildCurd
|
||||
'name' => "notes['$field']",
|
||||
'relation' => $relation,
|
||||
'values' => $field,
|
||||
]);
|
||||
]
|
||||
);
|
||||
return $selectCode;
|
||||
}
|
||||
|
||||
@@ -794,7 +799,8 @@ class BuildCurd
|
||||
[
|
||||
'name' => "notes['$field']",
|
||||
'select' => $select,
|
||||
]);
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -813,7 +819,8 @@ class BuildCurd
|
||||
'field' => $field,
|
||||
'name' => "notes['$field']",
|
||||
'select' => $select,
|
||||
]);
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -832,7 +839,8 @@ class BuildCurd
|
||||
'field' => $field,
|
||||
'name' => "notes['$field']",
|
||||
'select' => $select,
|
||||
]);
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -945,7 +953,6 @@ class BuildCurd
|
||||
$this->tableColumns[$field]['formType'] = 'select';
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 关联表
|
||||
@@ -1018,7 +1025,6 @@ class BuildCurd
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1027,20 +1033,25 @@ class BuildCurd
|
||||
*/
|
||||
protected function renderController(): static
|
||||
{
|
||||
$controllerFile = "{$this->rootDir}app{$this->DS}admin{$this->DS}controller{$this->DS}{$this->controllerFilename}.php";
|
||||
$controllerFile = "{$this->rootDir}app{$this->DS}admin{$this->DS}controller{$this->DS}{$this->controllerFilename}.php";
|
||||
$constructRelation = '';
|
||||
if (empty($this->relationArray)) {
|
||||
$controllerIndexMethod = '';
|
||||
}else {
|
||||
} else {
|
||||
$relationCode = '';
|
||||
foreach ($this->relationArray as $key => $val) {
|
||||
$relation = CommonTool::lineToHump($key);
|
||||
$relationCode = "->withJoin('{$relation}', 'LEFT')\r";
|
||||
$relationCode = "withJoin('{$relation}', 'LEFT')";
|
||||
if (!empty($val['bindSelectField']) && !empty($val['primaryKey'])) {
|
||||
$constructRelation = '$notes["' . lcfirst($val['foreignKey']) . '"] = \app\admin\model\\' . $val['modelFilename'] . '::column("' . $val['bindSelectField'] . '", "' . $val['primaryKey'] . '");';
|
||||
}
|
||||
}
|
||||
$controllerIndexMethod = CommonTool::replaceTemplate(
|
||||
$this->getTemplate("controller{$this->DS}indexMethod"),
|
||||
[
|
||||
'relationIndexMethod' => $relationCode,
|
||||
]);
|
||||
]
|
||||
);
|
||||
}
|
||||
$selectList = '';
|
||||
// foreach ($this->relationArray as $relation) {
|
||||
@@ -1066,7 +1077,9 @@ class BuildCurd
|
||||
'modelFilename' => "\app\admin\model\\{$modelFilenameExtend}",
|
||||
'indexMethod' => $controllerIndexMethod,
|
||||
'selectList' => $selectList,
|
||||
]);
|
||||
'constructRelation' => $constructRelation,
|
||||
]
|
||||
);
|
||||
$this->fileList[$controllerFile] = $controllerValue;
|
||||
return $this;
|
||||
}
|
||||
@@ -1087,9 +1100,10 @@ class BuildCurd
|
||||
$this->getTemplate("model{$this->DS}relation"),
|
||||
[
|
||||
'relationMethod' => $relation,
|
||||
'relationModel' => "\app\admin\model\\{$val['modelFilename']}",
|
||||
'relationModel' => "{$val['modelFilename']}::class",
|
||||
'foreignKey' => $val['foreignKey'],
|
||||
'primaryKey' => $val['primaryKey'],
|
||||
'relationFields' => empty($val['onlyFields']) ? "" : "->field('{$val['primaryKey']}," . implode(',', $val['onlyFields']) . "')",
|
||||
]);
|
||||
$relationList .= $relationCode;
|
||||
}
|
||||
@@ -1124,7 +1138,9 @@ class BuildCurd
|
||||
'relationList' => $relationList,
|
||||
// 'selectList' => $selectList,
|
||||
'selectArrays' => CommonTool::replaceArrayString(var_export($selectArrays, true)),
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
$this->fileList[$modelFile] = $modelValue;
|
||||
|
||||
@@ -1153,11 +1169,14 @@ class BuildCurd
|
||||
[
|
||||
'modelName' => $val['modelName'],
|
||||
'modelNamespace' => "app\admin\model{$extendNamespace}",
|
||||
'prefix_table' => $this->tablePrefix == config('database.connections.mysql.prefix') ? "" : $this->tablePrefix . $this->table,
|
||||
'table' => $key,
|
||||
'deleteTime' => $val['delete'] ? '"delete_time"' : 'false',
|
||||
'relationList' => '',
|
||||
'selectList' => '',
|
||||
]);
|
||||
'selectArrays' => "[]",
|
||||
]
|
||||
);
|
||||
$this->fileList[$relationModelFile] = $relationModelValue;
|
||||
}
|
||||
return $this;
|
||||
@@ -1176,7 +1195,8 @@ class BuildCurd
|
||||
[
|
||||
'controllerUrl' => $this->controllerUrl,
|
||||
'notesScript' => $this->formatNotesScript(),
|
||||
]);
|
||||
]
|
||||
);
|
||||
$this->fileList[$viewIndexFile] = $viewIndexValue;
|
||||
|
||||
// 添加页面
|
||||
@@ -1194,42 +1214,44 @@ class BuildCurd
|
||||
// 根据formType去获取具体模板
|
||||
if ($val['formType'] == 'image') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}image";
|
||||
}elseif ($val['formType'] == 'images') {
|
||||
} elseif ($val['formType'] == 'images') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}images";
|
||||
$define = $val['define'] ?? '|';
|
||||
}elseif ($val['formType'] == 'file') {
|
||||
} elseif ($val['formType'] == 'file') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}file";
|
||||
}elseif ($val['formType'] == 'files') {
|
||||
} elseif ($val['formType'] == 'files') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}files";
|
||||
$define = $val['define'] ?? '|';
|
||||
}elseif ($val['formType'] == 'editor') {
|
||||
} elseif ($val['formType'] == 'editor') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}editor";
|
||||
$val['default'] = '""';
|
||||
}elseif ($val['formType'] == 'date') {
|
||||
} elseif ($val['formType'] == 'date') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}date";
|
||||
$define = 'date';
|
||||
}elseif ($val['formType'] == 'datetime') {
|
||||
} elseif ($val['formType'] == 'datetime') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}date";
|
||||
$define = 'datetime';
|
||||
}elseif ($val['formType'] == 'radio') {
|
||||
} elseif ($val['formType'] == 'radio') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}radio";
|
||||
if (!empty($val['define'])) {
|
||||
$define = $this->buildRadioView($field, '{in name="k" value="' . $val['default'] . '"}checked=""{/in}');
|
||||
}
|
||||
}elseif ($val['formType'] == 'checkbox') {
|
||||
} elseif ($val['formType'] == 'checkbox') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}checkbox";
|
||||
if (!empty($val['define'])) {
|
||||
$define = $this->buildCheckboxView($field, '{in name="k" value="' . $val['default'] . '"}checked=""{/in}');
|
||||
}
|
||||
}elseif ($val['formType'] == 'select') {
|
||||
} elseif ($val['formType'] == 'select') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}select";
|
||||
if (isset($val['bindRelation'])) {
|
||||
$define = $this->buildOptionView($val['bindRelation']);
|
||||
}elseif (!empty($val['define'])) {
|
||||
$define = $this->buildOptionView($field);
|
||||
} elseif (!empty($val['define'])) {
|
||||
$define = $this->buildOptionView($field);
|
||||
}
|
||||
}elseif ($field == 'remark' || $val['formType'] == 'textarea') {
|
||||
} elseif ($field == 'remark' || $val['formType'] == 'textarea') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}textarea";
|
||||
} elseif ($field == 'sort') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}sort";
|
||||
}
|
||||
$addFormList .= CommonTool::replaceTemplate(
|
||||
$this->getTemplate($templateFile),
|
||||
@@ -1239,13 +1261,15 @@ class BuildCurd
|
||||
'required' => $this->buildRequiredHtml($val['required']),
|
||||
'value' => $val['default'],
|
||||
'define' => $define,
|
||||
]);
|
||||
]
|
||||
);
|
||||
}
|
||||
$viewAddValue = CommonTool::replaceTemplate(
|
||||
$this->getTemplate("view{$this->DS}form"),
|
||||
[
|
||||
'formList' => $addFormList,
|
||||
]);
|
||||
]
|
||||
);
|
||||
$this->fileList[$viewAddFile] = $viewAddValue;
|
||||
|
||||
|
||||
@@ -1266,43 +1290,44 @@ class BuildCurd
|
||||
// 根据formType去获取具体模板
|
||||
if ($val['formType'] == 'image') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}image";
|
||||
}elseif ($val['formType'] == 'images') {
|
||||
} elseif ($val['formType'] == 'images') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}images";
|
||||
}elseif ($val['formType'] == 'file') {
|
||||
} elseif ($val['formType'] == 'file') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}file";
|
||||
}elseif ($val['formType'] == 'files') {
|
||||
} elseif ($val['formType'] == 'files') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}files";
|
||||
}elseif ($val['formType'] == 'editor') {
|
||||
} elseif ($val['formType'] == 'editor') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}editor";
|
||||
$value = '$row["' . $field . '"]';
|
||||
}elseif ($val['formType'] == 'date') {
|
||||
} elseif ($val['formType'] == 'date') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}date";
|
||||
$define = 'date';
|
||||
}elseif ($val['formType'] == 'datetime') {
|
||||
} elseif ($val['formType'] == 'datetime') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}date";
|
||||
$define = 'datetime';
|
||||
}elseif ($val['formType'] == 'radio') {
|
||||
} elseif ($val['formType'] == 'radio') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}radio";
|
||||
if (!empty($val['define'])) {
|
||||
$define = $this->buildRadioView($field, '{in name="k" value="$row.' . $field . '"}checked=""{/in}');
|
||||
}
|
||||
}elseif ($val['formType'] == 'checkbox') {
|
||||
} elseif ($val['formType'] == 'checkbox') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}checkbox";
|
||||
if (!empty($val['define'])) {
|
||||
$define = $this->buildCheckboxView($field, '{in name="k" value="$row.' . $field . '"}checked=""{/in}');
|
||||
}
|
||||
}elseif ($val['formType'] == 'select') {
|
||||
} elseif ($val['formType'] == 'select') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}select";
|
||||
if (isset($val['bindRelation'])) {
|
||||
$define = $this->buildOptionView($val['bindRelation'], '{in name="k" value="$row.' . $field . '"}selected=""{/in}');
|
||||
}elseif (!empty($val['define'])) {
|
||||
$define = $this->buildOptionView($field, '{in name="k" value="$row.' . $field . '"}selected=""{/in}');
|
||||
} elseif (!empty($val['define'])) {
|
||||
$define = $this->buildOptionView($field, '{in name="k" value="$row.' . $field . '"}selected=""{/in}');
|
||||
}
|
||||
}elseif ($field == 'remark' || $val['formType'] == 'textarea') {
|
||||
} elseif ($field == 'remark' || $val['formType'] == 'textarea') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}textarea";
|
||||
$value = '{$row.' . $field . '|raw|default=\'\'}';
|
||||
} elseif ($field == 'sort') {
|
||||
$templateFile = "view{$this->DS}module{$this->DS}sort";
|
||||
}
|
||||
|
||||
$editFormList .= CommonTool::replaceTemplate(
|
||||
$this->getTemplate($templateFile),
|
||||
[
|
||||
@@ -1311,15 +1336,26 @@ class BuildCurd
|
||||
'required' => $this->buildRequiredHtml($val['required']),
|
||||
'value' => $value,
|
||||
'define' => $define,
|
||||
]);
|
||||
]
|
||||
);
|
||||
}
|
||||
$viewEditValue = CommonTool::replaceTemplate(
|
||||
$this->getTemplate("view{$this->DS}form"),
|
||||
[
|
||||
'formList' => $editFormList,
|
||||
]);
|
||||
]
|
||||
);
|
||||
$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;
|
||||
}
|
||||
|
||||
@@ -1338,75 +1374,79 @@ class BuildCurd
|
||||
|
||||
if ($val['formType'] == 'image') {
|
||||
$templateValue = "{field: '{$field}', title: '{$val['comment']}', templet: ea.table.image}";
|
||||
}elseif ($val['formType'] == 'images') {
|
||||
} elseif ($val['formType'] == 'datetime') {
|
||||
$templateValue = "{field: '{$field}', search: 'range', title: '{$val['comment']}'}";
|
||||
} elseif ($val['formType'] == 'images') {
|
||||
continue;
|
||||
}elseif ($val['formType'] == 'file') {
|
||||
} elseif ($val['formType'] == 'file') {
|
||||
$templateValue = "{field: '{$field}', title: '{$val['comment']}', templet: ea.table.url}";
|
||||
}elseif ($val['formType'] == 'files') {
|
||||
} elseif ($val['formType'] == 'files') {
|
||||
continue;
|
||||
}elseif ($val['formType'] == 'editor') {
|
||||
} elseif ($val['formType'] == 'editor') {
|
||||
continue;
|
||||
}elseif (in_array($field, $this->switchFields)) {
|
||||
} elseif (in_array($field, $this->switchFields)) {
|
||||
if (!empty($val['define'])) {
|
||||
$templateValue = "{field: '{$field}', search: 'select', selectList: notes?.{$field} || {}, title: '{$val['comment']}', templet: ea.table.switch}";
|
||||
}else {
|
||||
} else {
|
||||
$templateValue = "{field: '{$field}', title: '{$val['comment']}', templet: ea.table.switch}";
|
||||
}
|
||||
}elseif (in_array($val['formType'], ['select', 'checkbox', 'radio', 'switch'])) {
|
||||
} elseif (in_array($val['formType'], ['select', 'checkbox', 'radio', 'switch'])) {
|
||||
if (!empty($val['define'])) {
|
||||
$templateValue = "{field: '{$field}', search: 'select', selectList: notes?.{$field} || {}, title: '{$val['comment']}'}";
|
||||
}else {
|
||||
} else {
|
||||
$templateValue = "{field: '{$field}', title: '{$val['comment']}'}";
|
||||
}
|
||||
}elseif ($field == 'remark') {
|
||||
} elseif ($field == 'remark') {
|
||||
$templateValue = "{field: '{$field}', title: '{$val['comment']}', templet: ea.table.text}";
|
||||
}elseif (in_array($field, $this->sortFields)) {
|
||||
} elseif (in_array($field, $this->sortFields)) {
|
||||
$templateValue = "{field: '{$field}', title: '{$val['comment']}', edit: 'text'}";
|
||||
}else {
|
||||
} else {
|
||||
$templateValue = "{field: '{$field}', title: '{$val['comment']}'}";
|
||||
}
|
||||
|
||||
$indexCols .= $this->formatColsRow("{$templateValue},\r");
|
||||
}
|
||||
|
||||
// 关联表
|
||||
foreach ($this->relationArray as $table => $tableVal) {
|
||||
$table = CommonTool::lineToHump($table);
|
||||
$table = CommonTool::humpToLine($table);
|
||||
foreach ($tableVal['tableColumns'] as $field => $val) {
|
||||
if ($val['formType'] == 'image') {
|
||||
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}', templet: ea.table.image}";
|
||||
}elseif ($val['formType'] == 'images') {
|
||||
} elseif ($val['formType'] == 'images') {
|
||||
continue;
|
||||
}elseif ($val['formType'] == 'file') {
|
||||
} elseif ($val['formType'] == 'file') {
|
||||
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}', templet: ea.table.url}";
|
||||
}elseif ($val['formType'] == 'files') {
|
||||
} elseif ($val['formType'] == 'files') {
|
||||
continue;
|
||||
}elseif ($val['formType'] == 'editor') {
|
||||
} elseif ($val['formType'] == 'editor') {
|
||||
continue;
|
||||
}elseif ($val['formType'] == 'select') {
|
||||
} elseif ($val['formType'] == 'select') {
|
||||
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}'}";
|
||||
}elseif ($field == 'remark') {
|
||||
} elseif ($field == 'remark') {
|
||||
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}', templet: ea.table.text}";
|
||||
}elseif (in_array($field, $this->switchFields)) {
|
||||
} elseif (in_array($field, $this->switchFields)) {
|
||||
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}', templet: ea.table.switch}";
|
||||
}elseif (in_array($field, $this->sortFields)) {
|
||||
} elseif (in_array($field, $this->sortFields)) {
|
||||
$templateValue = "{field: '{$table}.{$field}', title: '{$val['comment']}', edit: 'text'}";
|
||||
}else {
|
||||
} else {
|
||||
$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(
|
||||
$this->getTemplate("static{$this->DS}js"),
|
||||
[
|
||||
'controllerUrl' => $this->controllerUrl,
|
||||
'indexCols' => $indexCols,
|
||||
]);
|
||||
'recycleCols' => $recycleCols,
|
||||
]
|
||||
);
|
||||
$this->fileList[$jsFile] = $jsValue;
|
||||
return $this;
|
||||
}
|
||||
@@ -1531,4 +1571,4 @@ class BuildCurd
|
||||
{
|
||||
return ' let notes = JSON.parse(\'{$notes|json_encode=256|raw}\');';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace EasyAdmin\curd\exceptions;
|
||||
namespace app\admin\service\curd\exceptions;
|
||||
|
||||
class CurdException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace EasyAdmin\curd\exceptions;
|
||||
namespace app\admin\service\curd\exceptions;
|
||||
|
||||
class FileException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace app\admin\service\curd\exceptions;
|
||||
|
||||
class TableException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -7,9 +7,7 @@ use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
use think\App;
|
||||
|
||||
/**
|
||||
* @ControllerAnnotation(title="{{controllerAnnotation}}")
|
||||
*/
|
||||
#[ControllerAnnotation(title: '{{controllerAnnotation}}')]
|
||||
class {{controllerName}} extends AdminController
|
||||
{
|
||||
|
||||
@@ -18,8 +16,10 @@ class {{controllerName}} extends AdminController
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
$this->model = new {{modelFilename}}();
|
||||
$this->notes = $notes = $this->model->notes;
|
||||
self::$model = {{modelFilename}}::class;
|
||||
$notes = self::$model::$notes;
|
||||
{{constructRelation}}
|
||||
$this->notes =$notes;
|
||||
$this->assign(compact('notes'));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="列表")
|
||||
*/
|
||||
public function index()
|
||||
#[NodeAnnotation(title: '列表', auth: true)]
|
||||
public function index(\app\Request $request): \think\response\Json|string
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
if ($request->isAjax()) {
|
||||
if (input('selectFields')) {
|
||||
return $this->selectList();
|
||||
}
|
||||
list($page, $limit, $where) = $this->buildTableParams();
|
||||
$count = $this->model{{relationIndexMethod}}->where($where)->count();
|
||||
$list = $this->model{{relationIndexMethod}}->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
|
||||
$data = [
|
||||
$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,
|
||||
|
||||
@@ -7,12 +7,17 @@ use app\common\model\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}};
|
||||
|
||||
public array $notes = {{selectArrays}};
|
||||
{{relationList}}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
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',
|
||||
export_url: '{{controllerUrl}}/export',
|
||||
modify_url: '{{controllerUrl}}/modify',
|
||||
recycle_url: '{{controllerUrl}}/recycle',
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -29,5 +30,62 @@ define(["jquery", "easy-admin"], function ($, ea) {
|
||||
edit: function () {
|
||||
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,7 +4,9 @@
|
||||
data-auth-add="{:auth('{{controllerUrl}}/add')}"
|
||||
data-auth-edit="{:auth('{{controllerUrl}}/edit')}"
|
||||
data-auth-delete="{:auth('{{controllerUrl}}/delete')}"
|
||||
data-auth-recycle="{:auth('{{controllerUrl}}/recycle')}"
|
||||
lay-filter="currentTable">
|
||||
<!-- searchTableShow="false" 隐藏搜索框 -->
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
7
app/admin/service/curd/templates/view/module/sort.code
Normal file
7
app/admin/service/curd/templates/view/module/sort.code
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{{comment}}</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="{{field}}" class="layui-input" lay-affix="number" {{required}} placeholder="请输入{{comment}}" value="{{value}}">
|
||||
</div>
|
||||
</div>
|
||||
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(')', ']', $arrayString);
|
||||
$arrayString = str_replace('=>
|
||||
[', '=> [', $arrayString);
|
||||
return $arrayString;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace app\admin\traits;
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
use app\admin\service\tool\CommonTool;
|
||||
use app\Request;
|
||||
use jianyan\excel\Excel;
|
||||
use think\db\exception\PDOException;
|
||||
use think\facade\Db;
|
||||
use think\response\Json;
|
||||
|
||||
@@ -17,9 +17,7 @@ use think\response\Json;
|
||||
trait Curd
|
||||
{
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="列表")
|
||||
*/
|
||||
#[NodeAnnotation(title: '列表', auth: true)]
|
||||
public function index(Request $request): Json|string
|
||||
{
|
||||
if ($request->isAjax()) {
|
||||
@@ -27,8 +25,8 @@ trait Curd
|
||||
return $this->selectList();
|
||||
}
|
||||
list($page, $limit, $where) = $this->buildTableParams();
|
||||
$count = $this->model->where($where)->count();
|
||||
$list = $this->model->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
|
||||
$count = self::$model::where($where)->count();
|
||||
$list = self::$model::where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '',
|
||||
@@ -40,9 +38,7 @@ trait Curd
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="添加")
|
||||
*/
|
||||
#[NodeAnnotation(title: '添加', auth: true)]
|
||||
public function add(Request $request): string
|
||||
{
|
||||
if ($request->isPost()) {
|
||||
@@ -50,8 +46,8 @@ trait Curd
|
||||
$rule = [];
|
||||
$this->validate($post, $rule);
|
||||
try {
|
||||
Db::transaction(function () use ($post, &$save) {
|
||||
$save = $this->model->save($post);
|
||||
Db::transaction(function() use ($post, &$save) {
|
||||
$save = self::$model::create($post);
|
||||
});
|
||||
}catch (\Exception $e) {
|
||||
$this->error('新增失败:' . $e->getMessage());
|
||||
@@ -61,19 +57,17 @@ trait Curd
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="编辑")
|
||||
*/
|
||||
#[NodeAnnotation(title: '编辑', auth: true)]
|
||||
public function edit(Request $request, $id = 0): string
|
||||
{
|
||||
$row = $this->model->find($id);
|
||||
$row = self::$model::find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
if ($request->isPost()) {
|
||||
$post = $request->post();
|
||||
$rule = [];
|
||||
$this->validate($post, $rule);
|
||||
try {
|
||||
Db::transaction(function () use ($post, $row, &$save) {
|
||||
Db::transaction(function() use ($post, $row, &$save) {
|
||||
$save = $row->save($post);
|
||||
});
|
||||
}catch (\Exception $e) {
|
||||
@@ -85,13 +79,13 @@ trait Curd
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="删除")
|
||||
*/
|
||||
public function delete($id): void
|
||||
#[NodeAnnotation(title: '删除', auth: true)]
|
||||
public function delete(Request $request): void
|
||||
{
|
||||
// 如果不是id作为主键 请在对应的控制器中覆盖重写
|
||||
$id = $request->param('id', []);
|
||||
$this->checkPostRequest();
|
||||
$row = $this->model->whereIn('id', $id)->select();
|
||||
$row = self::$model::whereIn('id', $id)->select();
|
||||
$row->isEmpty() && $this->error('数据不存在');
|
||||
try {
|
||||
$save = $row->delete();
|
||||
@@ -101,16 +95,14 @@ trait Curd
|
||||
$save ? $this->success('删除成功') : $this->error('删除失败');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="导出")
|
||||
*/
|
||||
#[NodeAnnotation(title: '导出', auth: true)]
|
||||
public function export()
|
||||
{
|
||||
if (env('EASYADMIN.IS_DEMO', false)) {
|
||||
$this->error('演示环境下不允许操作');
|
||||
}
|
||||
list($page, $limit, $where) = $this->buildTableParams();
|
||||
$tableName = $this->model->getName();
|
||||
$tableName = (new self::$model)->getName();
|
||||
$tableName = CommonTool::humpToLine(lcfirst($tableName));
|
||||
$prefix = config('database.connections.mysql.prefix');
|
||||
$dbList = Db::query("show full columns from {$prefix}{$tableName}");
|
||||
@@ -121,19 +113,19 @@ trait Curd
|
||||
$header[] = [$comment, $vo['Field']];
|
||||
}
|
||||
}
|
||||
$list = $this->model
|
||||
->where($where)
|
||||
$list = self::$model::where($where)
|
||||
->limit(100000)
|
||||
->order('id', 'desc')
|
||||
->order($this->sort)
|
||||
->select()
|
||||
->toArray();
|
||||
$fileName = time();
|
||||
return Excel::exportData($list, $header, $fileName, 'xlsx');
|
||||
try {
|
||||
exportExcel($header, $list);
|
||||
}catch (\Throwable $exception) {
|
||||
$this->error('导出失败: ' . $exception->getMessage() . PHP_EOL . $exception->getFile() . PHP_EOL . $exception->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnnotation(title="属性修改")
|
||||
*/
|
||||
#[NodeAnnotation(title: '属性修改', auth: true)]
|
||||
public function modify(Request $request): void
|
||||
{
|
||||
$this->checkPostRequest();
|
||||
@@ -144,7 +136,7 @@ trait Curd
|
||||
'value|值' => 'require',
|
||||
];
|
||||
$this->validate($post, $rule);
|
||||
$row = $this->model->find($post['id']);
|
||||
$row = self::$model::find($post['id']);
|
||||
if (!$row) {
|
||||
$this->error('数据不存在');
|
||||
}
|
||||
@@ -152,7 +144,7 @@ trait Curd
|
||||
$this->error('该字段不允许修改:' . $post['field']);
|
||||
}
|
||||
try {
|
||||
Db::transaction(function () use ($post, $row) {
|
||||
Db::transaction(function() use ($post, $row) {
|
||||
$row->save([
|
||||
$post['field'] => $post['value'],
|
||||
]);
|
||||
@@ -163,4 +155,49 @@ trait Curd
|
||||
$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">
|
||||
<input name="head_img" class="layui-input layui-col-xs6" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="{$row.head_img|default=''}">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,15 +26,6 @@
|
||||
</ul>
|
||||
|
||||
<ul class="layui-nav layui-layout-right">
|
||||
<!-- <li class="layui-nav-item" lay-unselect>-->
|
||||
<!-- <div class="layui-form ws-header-theme" lay-filter="header-theme">-->
|
||||
<!-- <input type="checkbox" name="theme-mode" id="ID-header-theme-mode" lay-filter="header-theme-mode" lay-skin="switch">-->
|
||||
<!-- <div lay-checkbox>-->
|
||||
<!-- <i class="layui-icon layui-icon-moon"></i> |-->
|
||||
<!-- <i class="layui-icon layui-icon-light"></i>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </li>-->
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a href="http://easyadmin8.top" target="_blank"><i class="fa fa-home"></i></a>
|
||||
</li>
|
||||
@@ -47,6 +38,15 @@
|
||||
<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>
|
||||
</li>
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<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">
|
||||
<div lay-checkbox>
|
||||
<i class="layui-icon layui-icon-moon"></i> |
|
||||
<i class="layui-icon layui-icon-light"></i>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="layui-nav-item layuimini-setting">
|
||||
<a href="javascript:;">
|
||||
<img src="{:session('admin.head_img')}" class="layui-nav-img" width="50" height="50">
|
||||
@@ -91,8 +91,8 @@
|
||||
<div class="layuimini-site-mobile"><i class="layui-icon"></i></div>
|
||||
|
||||
<div class="layui-body">
|
||||
<div class="layuimini-tab layui-tab-rollTool layui-tab" lay-filter="layuiminiTab" lay-allowclose="true">
|
||||
<ul class="layui-tab-title">
|
||||
<div class="layuimini-tab layui-tabs-rollTool layui-tabs" lay-filter="layuiminiTab" id="layuiminiTab">
|
||||
<ul class="layui-tabs-header">
|
||||
<li class="layui-this" id="layuiminiHomeTabId" lay-id=""></li>
|
||||
</ul>
|
||||
<div class="layui-tab-control">
|
||||
@@ -111,8 +111,8 @@
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
<div class="layui-tab-content">
|
||||
<div id="layuiminiHomeTabIframe" class="layui-tab-item layui-show"></div>
|
||||
<div class="layui-tabs-body">
|
||||
<div id="layuiminiHomeTabIframe" class="layui-tab-item layui-tabs-item layui-show"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<span class="layui-badge layui-bg-cyan pull-right ">实时</span>
|
||||
<div class="panel-content">
|
||||
<h5>用户统计</h5>
|
||||
<h1>1234</h1>
|
||||
<h6>当前分类总记录数</h6>
|
||||
<h2>1234</h2>
|
||||
<h6>记录数</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -28,8 +28,8 @@
|
||||
<span class="layui-badge layui-bg-purple pull-right ">实时</span>
|
||||
<div class="panel-content">
|
||||
<h5>商品统计</h5>
|
||||
<h1>1234</h1>
|
||||
<h6>当前分类总记录数</h6>
|
||||
<h2>1234</h2>
|
||||
<h6>记录数</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -40,8 +40,8 @@
|
||||
<span class="layui-badge layui-bg-orange pull-right ">实时</span>
|
||||
<div class="panel-content">
|
||||
<h5>浏览统计</h5>
|
||||
<h1>1234</h1>
|
||||
<h6>当前分类总记录数</h6>
|
||||
<h2>1234</h2>
|
||||
<h6>记录数</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -52,8 +52,8 @@
|
||||
<span class="layui-badge layui-bg-red pull-right ">实时</span>
|
||||
<div class="panel-content">
|
||||
<h5>订单统计</h5>
|
||||
<h1>1234</h1>
|
||||
<h6>当前分类总记录数</h6>
|
||||
<h2>1234</h2>
|
||||
<h6>记录数</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -151,12 +151,18 @@
|
||||
<tr>
|
||||
<td>DEBUG模式</td>
|
||||
<td>
|
||||
<button type="button" class="layui-btn layui-btn-xs {:env('APP_DEBUG')?'layui-btn-warm':'layui-bg-gray'}">
|
||||
<button type="button" class="layui-btn layui-btn-xs {:env('APP_DEBUG')?'layui-bg-cyan':'layui-bg-gray'}">
|
||||
{:env('APP_DEBUG')?'开启中':'已关闭'}
|
||||
</button>
|
||||
<span class="layui-badge layui-bg-gray">建议线上环境关闭 APP_DEBUG</span>
|
||||
</td>
|
||||
</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>
|
||||
<td>主要特色</td>
|
||||
<td>
|
||||
@@ -180,7 +186,7 @@
|
||||
<td>Github</td>
|
||||
<td>
|
||||
<a href="https://github.com/wolf-leo/easyAdmin8" target="_blank">
|
||||
<i class="layui-icon layui-icon-github layui-font-20 layui-font-cyan layui-text"></i>
|
||||
<i class="layui-icon layui-icon-github layui-font-20 layui-font-gray layui-text"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -192,8 +198,8 @@
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"><i class="fa fa-paper-plane-o icon"></i>作者心语</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<p class="layui-font-cyan">
|
||||
本模板基于layui2.9.x以及font-awesome-4.7.0进行实现。
|
||||
<p>
|
||||
本模板基于layui2.x以及font-awesome-4.7.0进行实现。
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" style="vertical-align: baseline;" target="_blank" href="http://layui.dev/docs">layui文档</a>
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="{:sysConfig('site', 'site_ico')}" type="image/x-icon">
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
|
||||
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
|
||||
@@ -26,7 +27,6 @@
|
||||
EDITOR_TYPE: "{$adminEditor|default='wangEditor'}",
|
||||
};
|
||||
</script>
|
||||
<script src="/static/plugs/xmSelect/xm-select.js" charset="utf-8"></script>
|
||||
<script src="/static/plugs/layui-v2.x/layui.js" charset="utf-8"></script>
|
||||
<script src="/static/plugs/require-2.3.6/require.js" charset="utf-8"></script>
|
||||
<script src="/static/config-admin.js?v={$version}" charset="utf-8"></script>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<a href="javascript:" class="forget-password">忘记密码?</a>
|
||||
</div>
|
||||
<div class="layui-form-item" style="text-align:center; width:100%;height:100%;margin:0px;">
|
||||
<button class="login-btn" lay-submit>立即登录</button>
|
||||
<button type="button" class="login-btn" lay-submit>立即登录</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
<div class="layui-input-block layuimini-upload">
|
||||
<input name="image" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
|
||||
<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 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" 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"><i class="fa fa-list"></i> 选择</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,7 +22,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="0">
|
||||
<input type="number" name="sort" class="layui-input" lay-affix="number" placeholder="请输入分类排序" value="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
<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=''}">
|
||||
<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 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" 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"><i class="fa fa-list"></i> 选择</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,7 +22,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="{$row.sort|default=''}">
|
||||
<input type="number" name="sort" class="layui-input" lay-affix="number" placeholder="请输入分类排序" value="{$row.sort|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -26,9 +26,18 @@
|
||||
<!-- </div>-->
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">商品标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="">
|
||||
<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="">
|
||||
</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>
|
||||
|
||||
@@ -37,8 +46,8 @@
|
||||
<div class="layui-input-block layuimini-upload">
|
||||
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="">
|
||||
<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 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" 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"><i class="fa fa-list"></i> 选择</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,8 +57,8 @@
|
||||
<div class="layui-input-block layuimini-upload">
|
||||
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="">
|
||||
<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 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" 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"><i class="fa fa-list"></i> 选择</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,7 +87,15 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="0">
|
||||
<input type="number" name="sort" class="layui-input" lay-affix="number" placeholder="请输入分类排序" value="0">
|
||||
</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>
|
||||
|
||||
|
||||
@@ -26,19 +26,29 @@
|
||||
<!-- </div>-->
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">商品标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入商品标题" value="{$row.title|default=''}">
|
||||
<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">
|
||||
<label class="layui-form-label required">商品LOGO</label>
|
||||
<div class="layui-input-block layuimini-upload">
|
||||
<input name="logo" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传分类图片" value="{$row.logo|default=''}">
|
||||
<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 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" 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"><i class="fa fa-list"></i> 选择</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,8 +58,8 @@
|
||||
<div class="layui-input-block layuimini-upload">
|
||||
<input name="images" class="layui-input layui-col-xs6" lay-verify="required" placeholder="请上传商品图片" value="{$row.images|default=''}">
|
||||
<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 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" 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"><i class="fa fa-list"></i> 选择</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,7 +88,15 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" class="layui-input" placeholder="请输入分类排序" value="{$row.sort|default=''}">
|
||||
<input type="number" name="sort" class="layui-input" lay-affix="number" placeholder="请输入分类排序" value="{$row.sort|default=''}">
|
||||
</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>
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
data-auth-edit="{:auth('mall.goods/edit')}"
|
||||
data-auth-delete="{:auth('mall.goods/delete')}"
|
||||
data-auth-stock="{:auth('mall.goods/stock')}"
|
||||
data-auth-recycle="{:auth('mall.goods/recycle')}"
|
||||
lay-filter="currentTable">
|
||||
</table>
|
||||
</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>
|
||||
@@ -25,7 +25,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">入库数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="stock" class="layui-input" lay-verify="required" placeholder="请输入入库数量" value="0">
|
||||
<input type="number" name="stock" class="layui-input" lay-affix="number" lay-verify="required" placeholder="请输入入库数量" value="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<div class="layui-input-block layuimini-upload">
|
||||
<input name="head_img" class="layui-input layui-col-xs6" lay-verify="required" lay-reqtext="请上传用户头像" placeholder="请上传用户头像" value="">
|
||||
<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 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" 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"><i class="fa fa-list"></i> 选择</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<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=''}">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
<div class="layuimini-container">
|
||||
<div class="layuimini-main" id="app">
|
||||
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="docDemoTabBrief">
|
||||
<ul class="layui-tab-title">
|
||||
<div class="layui-tabs layui-tabs-card layui-panel " id="docDemoTabBrief">
|
||||
<ul class="layui-tabs-header layui-bg-tint">
|
||||
<li class="layui-this" data-group="site">网站设置</li>
|
||||
<li data-group="logo">LOGO配置</li>
|
||||
<li data-group="upload">上传配置</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
{include file="system/config/site" /}
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
{include file="system/config/logo" /}
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
{include file="system/config/upload" /}
|
||||
</div>
|
||||
<div class="layui-tabs-body">
|
||||
<div class="layui-tabs-item layui-show"> {include file="system/config/site" /}</div>
|
||||
<div class="layui-tabs-item"> {include file="system/config/logo" /}</div>
|
||||
<div class="layui-tabs-item">{include file="system/config/upload" /}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<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')}">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<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')}">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@@ -24,7 +24,7 @@
|
||||
<div class="layui-input-block layuimini-upload">
|
||||
<input name="admin_background" class="layui-input layui-col-xs6" placeholder="不填默认#333333" value="{:sysConfig('site','admin_background')}">
|
||||
<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>
|
||||
</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">
|
||||
<table id="currentTable" class="layui-table layui-hide"
|
||||
data-auth-record="{:auth('system.log/record')}"
|
||||
data-auth-deleteMonthLog="{:auth('system.log/deleteMonthLog')}"
|
||||
lay-filter="currentTable">
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">菜单排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="0" class="layui-input">
|
||||
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="0" class="layui-input" lay-affix="number">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">菜单排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="{$row.sort|default=''}" class="layui-input">
|
||||
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="{$row.sort|default=''}" class="layui-input" lay-affix="number">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">菜单排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="0" class="layui-input">
|
||||
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="0" class="layui-input" lay-affix="number">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">菜单排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="{$row.sort|default=''}" class="layui-input">
|
||||
<input type="number" name="sort" lay-reqtext="菜单排序不能为空" placeholder="请输入菜单排序" value="{$row.sort|default=''}" class="layui-input" lay-affix="number">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// 应用公共文件
|
||||
|
||||
use app\common\service\AuthService;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
@@ -19,6 +21,7 @@ if (!function_exists('__url')) {
|
||||
*/
|
||||
function __url(string $url = '', array $vars = [], bool $suffix = true, bool $domain = false): string
|
||||
{
|
||||
if (filter_var($url, FILTER_VALIDATE_URL)) return $url;
|
||||
return url($url, $vars, $suffix, $domain)->build();
|
||||
}
|
||||
}
|
||||
@@ -99,21 +102,63 @@ if (!function_exists('auth')) {
|
||||
$authService = new AuthService(session('admin.id'));
|
||||
return $authService->checkNode($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $detail
|
||||
* @param string $name
|
||||
* @param string $placeholder
|
||||
* @return string
|
||||
*/
|
||||
function editor_textarea(?string $detail, string $name = 'desc', string $placeholder = '请输入'): string
|
||||
{
|
||||
$editor_type = sysConfig('site', 'editor_type');
|
||||
return match ($editor_type) {
|
||||
'ckeditor' => "<textarea name='{$name}' rows='20' class='layui-textarea editor' placeholder='{$placeholder}'>{$detail}</textarea>",
|
||||
'ueditor' => "<script type='text/plain' id='{$name}' name='{$name}' class='editor' data-content='{$detail}'></script>",
|
||||
'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: 300px'></div></div>",
|
||||
};
|
||||
/**
|
||||
* @param string|null $detail
|
||||
* @param string $name
|
||||
* @param string $placeholder
|
||||
* @return string
|
||||
*/
|
||||
function editor_textarea(?string $detail, string $name = 'desc', string $placeholder = '请输入'): string
|
||||
{
|
||||
$editor_type = sysConfig('site', 'editor_type');
|
||||
return match ($editor_type) {
|
||||
'ckeditor' => "<textarea name='{$name}' rows='20' class='layui-textarea editor' placeholder='{$placeholder}'>{$detail}</textarea>",
|
||||
'ueditor' => "<script type='text/plain' id='{$name}' name='{$name}' class='editor' data-content='{$detail}'></script>",
|
||||
'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();
|
||||
}
|
||||
@@ -168,6 +168,12 @@ class Curd extends Command
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PHP_SAPI == 'cli') {
|
||||
$output->info(">>>>>>>>>>>>>>>");
|
||||
$output->info('执行成功');
|
||||
}else {
|
||||
$output->writeln('执行成功');
|
||||
}
|
||||
}catch (\Exception $e) {
|
||||
if (PHP_SAPI == 'cli')
|
||||
CliEcho::error($e->getMessage());
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\command;
|
||||
|
||||
use EasyAdmin\console\CliEcho;
|
||||
use EasyAdmin\tool\CommonTool;
|
||||
use EasyAdmin\upload\driver\alioss\Oss;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
|
||||
class OssStatic extends Command
|
||||
{
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('OssStatic')
|
||||
->setDescription('将静态资源上传到oss上');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$output->writeln("========正在上传静态资源到OSS上:========" . date('Y-m-d H:i:s'));
|
||||
$dir = root_path() . 'public' . DIRECTORY_SEPARATOR . 'static';
|
||||
$list = CommonTool::readDirAllFiles($dir);
|
||||
$uploadConfig = sysConfig('upload');
|
||||
$uploadPrefix = config('app.oss_static_prefix', 'oss_static_prefix');
|
||||
foreach ($list as $key => $val) {
|
||||
list($objectName, $filePath) = [$uploadPrefix . DIRECTORY_SEPARATOR . $key, $val];
|
||||
try {
|
||||
$upload = Oss::instance($uploadConfig)
|
||||
->save($objectName, $filePath);
|
||||
} catch (\Exception $e) {
|
||||
CliEcho::error('文件上传失败:' . $filePath . '。错误信息:' . $e->getMessage());
|
||||
continue;
|
||||
}
|
||||
if ($upload['save'] == true) {
|
||||
CliEcho::success('文件上传成功:' . $filePath . '。上传地址:' . $upload['url']);
|
||||
} else {
|
||||
CliEcho::error('文件上传失败:' . $filePath . '。错误信息:' . $upload['msg']);
|
||||
}
|
||||
}
|
||||
$output->writeln("========已完成静态资源上传到OSS上:========" . date('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,9 +19,9 @@ class AdminController extends BaseController
|
||||
/**
|
||||
* 当前模型
|
||||
* @Model
|
||||
* @var object
|
||||
* @var mixed
|
||||
*/
|
||||
protected object $model;
|
||||
protected static mixed $model;
|
||||
|
||||
/**
|
||||
* 字段排序
|
||||
@@ -44,6 +44,12 @@ class AdminController extends BaseController
|
||||
'title',
|
||||
];
|
||||
|
||||
/**
|
||||
* 过滤节点更新
|
||||
* @var array
|
||||
*/
|
||||
protected array $ignoreNode = [];
|
||||
|
||||
/**
|
||||
* 不导出的字段信息
|
||||
* @var array
|
||||
@@ -166,7 +172,7 @@ class AdminController extends BaseController
|
||||
$where = [];
|
||||
$excludes = [];
|
||||
// 判断是否关联查询
|
||||
$tableName = Str::snake(lcfirst($this->model->getName()));
|
||||
$tableName = Str::snake(lcfirst((new self::$model)->getName()));
|
||||
foreach ($filters as $key => $val) {
|
||||
if (in_array($key, $excludeFields)) {
|
||||
$excludes[$key] = $val;
|
||||
@@ -212,7 +218,7 @@ class AdminController extends BaseController
|
||||
public function selectList(): Json
|
||||
{
|
||||
$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);
|
||||
}
|
||||
|
||||
@@ -243,7 +249,7 @@ class AdminController extends BaseController
|
||||
'version' => env('APP_DEBUG') ? time() : ConfigService::getVersion(),
|
||||
'adminUploadUrl' => url('ajax/upload', [], false),
|
||||
'adminEditor' => sysConfig('site', 'editor_type') ?: 'wangEditor',
|
||||
'iframeOpenTop' => sysConfig('site', 'iframe_open_top') ?: 0,
|
||||
'iframeOpenTop' => sysConfig('site', 'iframe_open_top') ?: 0,
|
||||
];
|
||||
View::assign($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
|
||||
{
|
||||
|
||||
/**
|
||||
* 自动时间戳类型
|
||||
* @var string
|
||||
*/
|
||||
protected $autoWriteTimestamp = true;
|
||||
|
||||
/**
|
||||
* 添加时间
|
||||
* @var string
|
||||
*/
|
||||
protected $createTime = 'create_time';
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
* @var string
|
||||
*/
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
/**
|
||||
* 软删除
|
||||
*/
|
||||
use SoftDelete;
|
||||
protected $deleteTime = false;
|
||||
|
||||
protected function getOptions(): array
|
||||
{
|
||||
return [
|
||||
'autoWriteTimestamp' => true,
|
||||
'createTime' => 'create_time',
|
||||
'updateTime' => 'update_time',
|
||||
'deleteTime' => false,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\service\annotation\NodeAnnotation;
|
||||
use app\common\constants\AdminConstant;
|
||||
use EasyAdmin\tool\CommonTool;
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,7 @@ class AuthService
|
||||
/***
|
||||
* 构造方法
|
||||
* AuthService constructor.
|
||||
* @param null $adminId
|
||||
* @param null $adminId
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
@@ -69,7 +69,7 @@ class AuthService
|
||||
|
||||
/**
|
||||
* 检测检测权限
|
||||
* @param null $node
|
||||
* @param null $node
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
@@ -88,7 +88,7 @@ class AuthService
|
||||
// 判断是否需要获取当前节点
|
||||
if (empty($node)) {
|
||||
$node = $this->getCurrentNode();
|
||||
} else {
|
||||
}else {
|
||||
$node = $this->parseNodeStr($node);
|
||||
}
|
||||
// 判断是否加入节点控制,优先获取缓存信息
|
||||
@@ -107,9 +107,30 @@ class AuthService
|
||||
if (in_array($node, $this->adminNode)) {
|
||||
return true;
|
||||
}
|
||||
if ($this->checkNodeAnnotationAttrAuth($node)) return true;
|
||||
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
|
||||
@@ -131,25 +152,25 @@ class AuthService
|
||||
{
|
||||
$nodeList = [];
|
||||
$adminInfo = Db::name($this->config['system_admin'])
|
||||
->where([
|
||||
'id' => $this->adminId,
|
||||
'status' => 1,
|
||||
])->find();
|
||||
->where([
|
||||
'id' => $this->adminId,
|
||||
'status' => 1,
|
||||
])->find();
|
||||
if (!empty($adminInfo) && !empty($adminInfo['auth_ids'])) {
|
||||
$buildAuthSql = Db::name($this->config['system_auth'])
|
||||
->distinct(true)
|
||||
->whereIn('id', $adminInfo['auth_ids'])
|
||||
->field('id')
|
||||
->buildSql(true);
|
||||
->distinct(true)
|
||||
->whereIn('id', $adminInfo['auth_ids'])
|
||||
->field('id')
|
||||
->buildSql(true);
|
||||
$buildAuthNodeSql = Db::name($this->config['system_auth_node'])
|
||||
->distinct(true)
|
||||
->where("auth_id IN {$buildAuthSql}")
|
||||
->field('node_id')
|
||||
->buildSql(true);
|
||||
->distinct(true)
|
||||
->where("auth_id IN {$buildAuthSql}")
|
||||
->field('node_id')
|
||||
->buildSql(true);
|
||||
$nodeList = Db::name($this->config['system_node'])
|
||||
->distinct(true)
|
||||
->where("id IN {$buildAuthNodeSql}")
|
||||
->column('node');
|
||||
->distinct(true)
|
||||
->where("id IN {$buildAuthNodeSql}")
|
||||
->column('node');
|
||||
}
|
||||
return $nodeList;
|
||||
}
|
||||
@@ -163,7 +184,7 @@ class AuthService
|
||||
public function getNodeList()
|
||||
{
|
||||
return Db::name($this->config['system_node'])
|
||||
->column('id,node,title,type,is_auth', 'node');
|
||||
->column('id,node,title,type,is_auth', 'node');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,13 +199,13 @@ class AuthService
|
||||
public function getAdminInfo()
|
||||
{
|
||||
return Db::name($this->config['system_admin'])
|
||||
->where('id', $this->adminId)
|
||||
->find();
|
||||
->where('id', $this->adminId)
|
||||
->find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰转下划线规则
|
||||
* @param string $node
|
||||
* @param string $node
|
||||
* @return string
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,8 +22,8 @@ class Install extends BaseController
|
||||
// $this->redirect('/');
|
||||
$isInstall = true;
|
||||
$errorInfo = '已安装系统,如需重新安装请删除文件:/config/install/lock/install.lock,或者删除 /install 路由';
|
||||
}elseif (version_compare(phpversion(), '8.0.0', '<')) {
|
||||
$errorInfo = 'PHP版本不能小于8.0.0';
|
||||
}elseif (version_compare(phpversion(), '8.1.0', '<')) {
|
||||
$errorInfo = 'PHP版本不能小于8.1.0';
|
||||
}elseif (!extension_loaded("PDO")) {
|
||||
$errorInfo = '当前未开启PDO,无法进行安装';
|
||||
}
|
||||
@@ -31,9 +31,17 @@ class Install extends BaseController
|
||||
$errorInfo = '.env 文件不存在,请先配置 .env 文件';
|
||||
}
|
||||
if (!$request->isAjax()) {
|
||||
$envInfo = [
|
||||
'DB_HOST' => $isInstall ? '' : env('DB_HOST', '127.0.0.1'),
|
||||
'DB_NAME' => $isInstall ? '' : env('DB_NAME', 'easyadmin8'),
|
||||
'DB_USER' => $isInstall ? '' : env('DB_USER', 'root'),
|
||||
'DB_PASS' => $isInstall ? '' : env('DB_PASS', 'root'),
|
||||
'DB_PORT' => $isInstall ? '' : env('DB_PORT', 3306),
|
||||
'DB_PREFIX' => $isInstall ? '' : env('DB_PREFIX', 'ea8_'),
|
||||
];
|
||||
$currentHost = '://';
|
||||
$result = compact('errorInfo', 'currentHost', 'isInstall');
|
||||
return view('index/install/index', $result);
|
||||
$result = compact('errorInfo', 'currentHost', 'isInstall', 'envInfo');
|
||||
return view('index@install/index', $result);
|
||||
}
|
||||
if ($errorInfo) $this->error($errorInfo);
|
||||
$charset = 'utf8mb4';
|
||||
@@ -91,12 +99,11 @@ class Install extends BaseController
|
||||
$installPath = config_path() . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR;
|
||||
$sqlPath = file_get_contents($installPath . 'sql' . DIRECTORY_SEPARATOR . 'install.sql');
|
||||
$sqlArray = $this->parseSql($sqlPath, $config['prefix'], 'ea_');
|
||||
$conn = mysqli_connect($config['host'], $config['username'], $config['password'], null, $config['port']);
|
||||
$dsn = $this->pdoDsn($config, true);
|
||||
try {
|
||||
mysqli_set_charset($conn, $config['charset']);
|
||||
mysqli_select_db($conn, $config['database']);
|
||||
$pdo = new \PDO($dsn, $config['username'] ?? 'root', $config['password'] ?? '');
|
||||
foreach ($sqlArray as $sql) {
|
||||
mysqli_query($conn, $sql);
|
||||
$pdo->query($sql);
|
||||
}
|
||||
$_password = password($password);
|
||||
$tableName = 'system_admin';
|
||||
@@ -108,9 +115,8 @@ class Install extends BaseController
|
||||
'update_time' => time()
|
||||
];
|
||||
foreach ($update as $_k => $_up) {
|
||||
mysqli_query($conn, "UPDATE {$config['prefix']}{$tableName} SET {$_k} = '{$_up}' WHERE id = 1");
|
||||
$pdo->query("UPDATE {$config['prefix']}{$tableName} SET {$_k} = '{$_up}' WHERE id = 1");
|
||||
}
|
||||
mysqli_close($conn);
|
||||
// 处理安装文件
|
||||
!is_dir($installPath) && @mkdir($installPath);
|
||||
!is_dir($installPath . 'lock' . DIRECTORY_SEPARATOR) && @mkdir($installPath . 'lock' . DIRECTORY_SEPARATOR);
|
||||
@@ -161,11 +167,11 @@ class Install extends BaseController
|
||||
|
||||
protected function createDatabase($database, $config): bool
|
||||
{
|
||||
$dsn = $this->pdoDsn($config);
|
||||
try {
|
||||
$con = mysqli_connect($config['host'] ?? '127.0.0.1', $config['username'] ?? 'root', $config['password'] ?? '', null, $config['port'] ?? '');
|
||||
mysqli_query($con, "CREATE DATABASE IF NOT EXISTS `{$database}` DEFAULT CHARACTER SET {$config['charset']} COLLATE=utf8mb4_general_ci");
|
||||
mysqli_close($con);
|
||||
}catch (\Throwable $e) {
|
||||
$pdo = new \PDO($dsn, $config['username'] ?? 'root', $config['password'] ?? '');
|
||||
$pdo->query("CREATE DATABASE IF NOT EXISTS `{$database}` DEFAULT CHARACTER SET {$config['charset']} COLLATE=utf8mb4_general_ci");
|
||||
}catch (\PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -187,19 +193,32 @@ class Install extends BaseController
|
||||
|
||||
protected function checkConnect(array $config): ?bool
|
||||
{
|
||||
$dsn = $this->pdoDsn($config);
|
||||
try {
|
||||
$con = mysqli_connect($config['host'] ?? '127.0.0.1', $config['username'] ?? 'root', $config['password'] ?? '', null, $config['port'] ?? '');
|
||||
$res = mysqli_query($con, 'select VERSION()');
|
||||
$mysqlVersion = mysqli_fetch_row($res);
|
||||
mysqli_close($con);
|
||||
$_version = $mysqlVersion[0] ?? 0;
|
||||
$pdo = new \PDO($dsn, $config['username'] ?? 'root', $config['password'] ?? '');
|
||||
$res = $pdo->query('select VERSION()');
|
||||
$_version = $res->fetch()[0] ?? 0;
|
||||
if (version_compare($_version, '5.7.0', '<')) {
|
||||
$this->error('mysql版本最低要求 5.7.x');
|
||||
}
|
||||
}catch (\mysqli_sql_exception $e) {
|
||||
}catch (\PDOException $e) {
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param bool $needDatabase
|
||||
* @return string
|
||||
*/
|
||||
protected function pdoDsn(array $config, bool $needDatabase = false): string
|
||||
{
|
||||
$host = $config['host'] ?? '127.0.0.1';
|
||||
$database = $config['database'] ?? '';
|
||||
$port = $config['port'] ?? '3306';
|
||||
$charset = $config['charset'] ?? 'utf8mb4';
|
||||
if ($needDatabase) return "mysql:host=$host;port=$port;dbname=$database;charset=$charset";
|
||||
return "mysql:host=$host;port=$port;charset=$charset";
|
||||
}
|
||||
}
|
||||
@@ -20,25 +20,26 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0.0",
|
||||
"php": ">=8.1.0",
|
||||
"topthink/framework": "^8.0",
|
||||
"topthink/think-orm": "^3.0",
|
||||
"topthink/think-multi-app": "^1.0",
|
||||
"topthink/think-orm": "^4.0",
|
||||
"topthink/think-multi-app": "^1.1.0",
|
||||
"topthink/think-view": "^2.0",
|
||||
"topthink/think-captcha": "^3.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",
|
||||
"jianyan74/php-excel": "^1.0.2",
|
||||
"doctrine/annotations": "^1.13",
|
||||
"phpoffice/phpspreadsheet": "^1.28",
|
||||
"doctrine/annotations": "^2.0.0",
|
||||
"phpoffice/phpspreadsheet": "^4.1.0",
|
||||
"myclabs/php-enum": "^1.8",
|
||||
"ext-json": "*",
|
||||
"qiniu/php-sdk": "v7.11.0",
|
||||
"ext-mysqli": "*",
|
||||
"ext-pdo": "*",
|
||||
"qiniu/php-sdk": "^7.11.0",
|
||||
"wolf-leo/phplogviewer": "^0.11.3",
|
||||
"wolfcode/authenticator": "^0.0.3"
|
||||
"wolfcode/authenticator": "^0.0.6",
|
||||
"wolfcode/rate-limiting": "^0.1.0",
|
||||
"wolfcode/php-ai": "^0.1.2",
|
||||
"ext-json": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-pdo": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/var-dumper": ">=4.2",
|
||||
|
||||
@@ -235,11 +235,11 @@ VALUES ('64', 'oss_domain', 'upload', '填你的', '阿里云oss访问域名', '
|
||||
INSERT INTO `ea_system_config`
|
||||
VALUES ('65', 'logo_title', 'site', 'EasyAdmin', 'LOGO标题', '0', null, null);
|
||||
INSERT INTO `ea_system_config`
|
||||
VALUES ('66', 'logo_image', 'site', '/favicon.ico', 'logo图片', '0', null, null);
|
||||
VALUES ('66', 'logo_image', 'site', '/static/common/images/logo-1.png', 'logo图片', '0', null, null);
|
||||
INSERT INTO `ea_system_config`
|
||||
VALUES ('68', 'site_name', 'site', 'EasyAdmin后台系统', '站点名称', '0', null, null);
|
||||
INSERT INTO `ea_system_config`
|
||||
VALUES ('69', 'site_ico', 'site', '填你的', '浏览器图标', '0', null, null);
|
||||
VALUES ('69', 'site_ico', 'site', '/favicon.ico', '浏览器图标', '0', null, null);
|
||||
INSERT INTO `ea_system_config`
|
||||
VALUES ('70', 'site_copyright', 'site', '填你的', '版权信息', '0', null, null);
|
||||
INSERT INTO `ea_system_config`
|
||||
@@ -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);
|
||||
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);
|
||||
|
||||
-- ----------------------------
|
||||
-- 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';
|
||||
|
||||
@@ -42,4 +42,6 @@ return [
|
||||
'default_jsonp_handler' => 'jsonpReturn',
|
||||
// 默认JSONP处理方法
|
||||
'var_jsonp_handler' => 'callback',
|
||||
// 操作方法的参数绑定方式 route get param
|
||||
'action_bind_param' => 'param',
|
||||
];
|
||||
|
||||
2
extend/.gitignore
vendored
2
extend/.gitignore
vendored
@@ -1,2 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
!.gitignore
|
||||
|
||||
3
log.md
3
log.md
@@ -1,2 +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+`
|
||||
>
|
||||
> 2024年05月 更新 `EasyAdmin8` 重置版,多处语法、写法进行变更
|
||||
59
public/static/admin/css/color.css
Normal file
59
public/static/admin/css/color.css
Normal file
@@ -0,0 +1,59 @@
|
||||
.green {
|
||||
color: #11c26d !important;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: #ff4c52 !important;
|
||||
}
|
||||
|
||||
.cyan {
|
||||
color: #0bb2d4 !important;
|
||||
}
|
||||
|
||||
.purple {
|
||||
color: #9463f7 !important;
|
||||
}
|
||||
|
||||
.blue {
|
||||
color: #3e8ef7 !important;
|
||||
}
|
||||
|
||||
.orange {
|
||||
color: #eb6709 !important;
|
||||
}
|
||||
|
||||
.indigo {
|
||||
color: #6610f2 !important;
|
||||
}
|
||||
|
||||
.pink {
|
||||
color: #e83e8c !important;
|
||||
}
|
||||
|
||||
.teal {
|
||||
color: #20c997 !important;
|
||||
}
|
||||
|
||||
.white {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.gray {
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
.gray-dark {
|
||||
color: #343a40 !important;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
color: rgb(255, 214, 102) !important;
|
||||
}
|
||||
|
||||
.magenta {
|
||||
color: #eb2f96 !important;
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
body {
|
||||
background: #333333;
|
||||
}
|
||||
|
||||
.demo {
|
||||
padding-top: 20px;
|
||||
@@ -170,7 +173,6 @@
|
||||
}
|
||||
|
||||
.container {
|
||||
background: #333333;
|
||||
position: static;
|
||||
font-size: 12px;
|
||||
height: 100%;
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
@import url("../../plugs/layui-v2.x/css/layui.css");
|
||||
@import url("../../plugs/font-awesome-4.7.0/css/font-awesome.min.css");
|
||||
@import url("../css/color.css");
|
||||
@import url("../css/themes/index.css");
|
||||
@import url("../css/iconfont.css");
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
background: #f2f2f2;
|
||||
:root {
|
||||
--ea8-theme-main-color: #16b777;
|
||||
}
|
||||
|
||||
html.dark, body {
|
||||
height: 100%;
|
||||
background: var(--lay-color-bg-1);
|
||||
html,
|
||||
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";
|
||||
}
|
||||
|
||||
.ws-header-theme .layui-form-switch {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.ws-header-theme .layui-form-onswitch {
|
||||
background: #333333;
|
||||
border: 1px solid rgba(255, 255, 255, .7);
|
||||
}
|
||||
|
||||
.layuimini-container {
|
||||
min-height: 250px;
|
||||
padding: 15px;
|
||||
@@ -58,10 +64,8 @@ html.dark, body {
|
||||
}
|
||||
|
||||
.hr-line {
|
||||
color: #fff;
|
||||
height: 1px;
|
||||
margin: 30px 0;
|
||||
background-color: #fff;
|
||||
border-top: 1px dashed #e7eaec;
|
||||
}
|
||||
|
||||
@@ -75,8 +79,8 @@ html.dark, body {
|
||||
|
||||
/**重写layui表格自适应*/
|
||||
.layuimini-container .layui-table-cell {
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
height: 50px;
|
||||
line-height: 42px;
|
||||
}
|
||||
|
||||
/**数据表格-搜索表单样式*/
|
||||
@@ -84,7 +88,6 @@ html.dark, body {
|
||||
margin: 0;
|
||||
border: 1px solid #e6e6e6;
|
||||
padding: 10px 20px 5px 20px;
|
||||
color: #6b6b6b;
|
||||
}
|
||||
|
||||
/**数据表格-搜索表单样式*/
|
||||
@@ -134,10 +137,17 @@ html.dark, body {
|
||||
color: #a29c9c;
|
||||
}
|
||||
|
||||
.layui-form-item xm-select {
|
||||
.tableSearch-xmSelect xm-select {
|
||||
min-height: 30px !important;
|
||||
line-height: 30px !important;
|
||||
margin: 0 !important;
|
||||
background-color: var(--lay-color-fill-2);
|
||||
}
|
||||
|
||||
.elem-style-dark .tableSearch-xmSelect xm-select {
|
||||
background-color: var(--lay-color-fill-2);
|
||||
color: var(--lay-color-text-2);
|
||||
border-color: var(--lay-color-border-1) !important;
|
||||
}
|
||||
|
||||
/** 按钮背景色 */
|
||||
@@ -265,7 +275,6 @@ table样式
|
||||
|
||||
.layuimini-container .layui-table-box .layui-table-header th {
|
||||
font-weight: bold !important;
|
||||
color: #565656 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,9 +308,17 @@ table样式
|
||||
}
|
||||
|
||||
.layui-form-select dl {
|
||||
border: 1px #16b777 solid;
|
||||
border: 1px var(--ea8-theme-main-color) solid;
|
||||
border-top: none;
|
||||
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 {
|
||||
@@ -340,7 +357,7 @@ table样式
|
||||
弹出层样式
|
||||
*/
|
||||
.layui-layer-easy .layui-layer-title {
|
||||
background: #2c3e50 !important;
|
||||
background: var(--lay-color-bg-5);
|
||||
color: #fff !important;
|
||||
border-bottom: none;
|
||||
}
|
||||
@@ -363,7 +380,6 @@ table样式
|
||||
.layui-layer-easy .layui-layer-btn {
|
||||
text-align: center !important;
|
||||
padding: 10px !important;
|
||||
background: #ecf0f1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -512,4 +528,13 @@ table样式
|
||||
|
||||
.wangEditor_div {
|
||||
z-index: 99999;
|
||||
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%;
|
||||
}
|
||||
802
public/static/admin/css/themes/_dark.scss
Normal file
802
public/static/admin/css/themes/_dark.scss
Normal file
@@ -0,0 +1,802 @@
|
||||
// 通常用于背景色
|
||||
$black-color :rgb(2, 17, 20);
|
||||
// 通常用于字体颜色
|
||||
$main-color :rgb(126, 252, 246);
|
||||
// 通常用于边框
|
||||
$less-main-color:rgb(6, 216, 215);
|
||||
|
||||
$plus-main-color:rgb(0, 125, 124);
|
||||
|
||||
// 通常用于激活状态,通常跟背景色搭配
|
||||
$cover-color :rgba(62, 251, 251, 0.05);
|
||||
// 更强的激活状态,适合做选项操作时使用
|
||||
$active-color :rgba(62, 251, 251, 0.5);
|
||||
|
||||
|
||||
$red-color :rgb(255, 0, 0);
|
||||
$yellow-color:rgb(255, 255, 153);
|
||||
$green-color :rgb(0, 255, 0);
|
||||
|
||||
& {
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layuimini-main {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layuimini-container {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-tool {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
$box-shape: polygon(0 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 0);
|
||||
|
||||
.layui-btn {
|
||||
|
||||
&.layui-btn-lg {
|
||||
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
clip-path : $box-shape;
|
||||
padding-right : 10px;
|
||||
position : relative;
|
||||
background-color: transparent;
|
||||
border : 1px solid;
|
||||
color : rgb(126, 252, 246);
|
||||
text-shadow : rgb(126, 252, 246) 0px 0px 1px;
|
||||
background-color: rgb(126, 252, 246);
|
||||
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
clip-path: $box-shape;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: -0.5px;
|
||||
top: -0.5px;
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
&:hover::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
clip-path: $box-shape;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: -0.5px;
|
||||
top: -0.5px;
|
||||
background-color: rgba(126, 252, 246, 0.2);
|
||||
}
|
||||
|
||||
&.layui-btn-disabled {
|
||||
&::after {
|
||||
// todo:实现按钮禁用样式
|
||||
}
|
||||
}
|
||||
|
||||
&.layui-btn-success {
|
||||
text-shadow: rgb(0, 255, 0) 0px 0px 1px;
|
||||
color: rgb(0, 255, 0);
|
||||
background-color: rgba(0, 255, 0);
|
||||
border: unset;
|
||||
|
||||
&:hover::after {
|
||||
background-color: rgba(0, 255, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&.layui-btn-danger {
|
||||
text-shadow: rgb(255, 0, 0) 0px 0px 1px;
|
||||
color: rgb(255, 0, 0);
|
||||
background-color: rgb(255, 0, 0);
|
||||
border: unset;
|
||||
|
||||
&:hover::after {
|
||||
background-color: rgba(255, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&.layuimini-btn-primary {
|
||||
text-shadow: rgb(255, 255, 153) 0px 0px 1px;
|
||||
color: rgb(255, 255, 153);
|
||||
background-color: rgb(255, 255, 153);
|
||||
border: unset;
|
||||
|
||||
&:hover::after {
|
||||
background-color: rgba(255, 255, 153, 0.2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.layui-btn-primary {
|
||||
border: unset;
|
||||
}
|
||||
|
||||
&.layui-btn-normal {
|
||||
color: $black-color;
|
||||
background-color: $main-color;
|
||||
border: unset;
|
||||
|
||||
&::before {
|
||||
background-color: $main-color;
|
||||
}
|
||||
|
||||
&:hover::after {
|
||||
background-color: $main-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layui-table {
|
||||
background: $black-color;
|
||||
color: $main-color;
|
||||
|
||||
|
||||
tr {
|
||||
background-color: $cover-color;
|
||||
}
|
||||
|
||||
td {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layui-table-header {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-box {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-box .layui-table-header th {
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-table-tool .layui-inline[lay-event] {
|
||||
color: $main-color;
|
||||
border: none;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
border-color: $main-color;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
clip-path: $box-shape;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: calc(100% - 1px);
|
||||
height: calc(100% - 1px);
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-table tbody tr:hover {
|
||||
background-color: rgba(126, 252, 246, 0.1);
|
||||
}
|
||||
|
||||
.layuimini-main {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layui-table-header {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.color-content>ul>li>a>div>span:nth-child(2) {
|
||||
background-color: $black-color !important;
|
||||
}
|
||||
|
||||
.layuimini-color .elem-content li {
|
||||
clip-path: $box-shape;
|
||||
}
|
||||
|
||||
.layuimini-color .elem-content li.layui-this {
|
||||
background-color: $main-color;
|
||||
color: $black-color !important;
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layuimini-color .more-menu-item {
|
||||
color: $main-color;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(62, 251, 251, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header {
|
||||
background-color: $cover-color !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title {
|
||||
background-color: $cover-color !important;
|
||||
border-color: $less-main-color;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title span {
|
||||
color: $active-color;
|
||||
}
|
||||
|
||||
.layui-header .layuimini-menu-header-pc.layui-nav .layui-nav-item a:hover,
|
||||
.layui-header .layuimini-header-menu.layuimini-pc-show.layui-nav .layui-this a {
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header .layui-nav .layui-nav-item a {
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header .layui-nav .layui-nav-item {
|
||||
background-color: $active-color;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.layui-layout-admin .layui-header .layuimini-header-content>ul>.layui-nav-item.layui-this,
|
||||
.layuimini-tool i:hover {
|
||||
background-color: $main-color !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-control>li {
|
||||
background-color: $black-color;
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title li {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layui-flow-more a *,
|
||||
.layui-laypage input,
|
||||
.layui-table-view select[lay-ignore] {
|
||||
border-color: $less-main-color;
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-laypage button,
|
||||
.layui-laypage input {
|
||||
border-color: $less-main-color;
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-switch {
|
||||
border-color: $less-main-color !important;
|
||||
background-color: $black-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-onswitch {
|
||||
background-color: $main-color !important;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-switch.layui-form-onswitch i {
|
||||
background-color: $black-color !important;
|
||||
}
|
||||
.layuimini-container .layui-laypage .layui-laypage-curr .layui-laypage-em {
|
||||
background-color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-laypage .layui-laypage-curr em {
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title .layui-this .layuimini-tab-active {
|
||||
background-color: $less-main-color;
|
||||
|
||||
}
|
||||
|
||||
.layui-table-view .layui-form-checkbox.layui-form-checked[lay-skin="primary"] i {
|
||||
border-color: $main-color;
|
||||
background-color: $main-color;
|
||||
color: $black-color;
|
||||
}
|
||||
|
||||
.layui-table-view .layui-form-checkbox[lay-skin="primary"] i {
|
||||
background-color: $cover-color;
|
||||
}
|
||||
|
||||
.layui-table-init {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.box-border-line {
|
||||
position: relative;
|
||||
border: 1px solid $less-main-color;
|
||||
border-width: 1px;
|
||||
$border-offset: 3px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
transition: all 0.2s;
|
||||
border: 1px solid $less-main-color;
|
||||
top: -$border-offset;
|
||||
left: -$border-offset;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
transition: all 0.2s;
|
||||
border: 1px solid $less-main-color;
|
||||
bottom: -$border-offset;
|
||||
right: -$border-offset;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
&::after,
|
||||
&::before {
|
||||
width: calc(100% + $border-offset);
|
||||
height: calc(100% + $border-offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-search-fieldset {
|
||||
.layui-input-inline {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.layui-form-item:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
@extend .box-border-line;
|
||||
}
|
||||
|
||||
.layui-form-label {
|
||||
border: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-form-pane .layui-form-label {
|
||||
background-color: $cover-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layuimini-container .table-search-fieldset {
|
||||
color: $main-color;
|
||||
border-color: $less-main-color;
|
||||
|
||||
}
|
||||
|
||||
.layui-form-select,
|
||||
.layui-form-autocomplete {
|
||||
dl {
|
||||
|
||||
color: $main-color;
|
||||
background-color: $black-color;
|
||||
border-color: $less-main-color;
|
||||
|
||||
dd {
|
||||
&.layui-this {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $less-main-color !important;
|
||||
color: $black-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layui-iconpicker-item,
|
||||
.layui-iconpicker-item:hover {
|
||||
border-color: $less-main-color !important;
|
||||
color: $black-color;
|
||||
|
||||
.layui-iconpicker-icon:hover {
|
||||
border-color: $less-main-color !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layui-nav-child {
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child a {
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-badge,
|
||||
.layui-badge-dot,
|
||||
.layui-badge-rim {
|
||||
background-color: $main-color;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-child a:hover {
|
||||
background-color: $active-color;
|
||||
}
|
||||
|
||||
.layui-table-tool-panel {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-form-checkbox[lay-skin="primary"] span {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-table-tool-panel li:hover {
|
||||
background-color: $active-color;
|
||||
}
|
||||
|
||||
.layui-side.layui-bg-black,
|
||||
.layui-side.layui-bg-black>.layuimini-menu-left>ul,
|
||||
.layuimini-menu-left-zoom>ul {
|
||||
background-color: $black-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layui-side {
|
||||
border-right: 1px solid $main-color;
|
||||
}
|
||||
|
||||
.layui-bg-blue {
|
||||
background-color: #0000ff !important;
|
||||
}
|
||||
|
||||
.layui-bg-orange {
|
||||
background-color: $yellow-color !important;
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
.layui-bg-green {
|
||||
background-color: $green-color !important;
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
.layui-table-hover {
|
||||
background-color: $cover-color;
|
||||
}
|
||||
|
||||
.layui-table-grid-down {
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
border-color: unset;
|
||||
}
|
||||
|
||||
.layui-table-tips-main {
|
||||
background-color: $main-color;
|
||||
color: $black-color;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header .layuimini-tool i {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.color-red {
|
||||
color: $red-color !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title .layui-this span {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-card {
|
||||
|
||||
background-color: $cover-color;
|
||||
border-radius: 0;
|
||||
|
||||
@extend .box-border-line;
|
||||
|
||||
.layui-card-header {
|
||||
color: $main-color;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-text {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
|
||||
.layuimini-qiuck-module {
|
||||
cursor: pointer;
|
||||
|
||||
a i {
|
||||
background-color: $cover-color;
|
||||
color: $active-color;
|
||||
}
|
||||
|
||||
a cite {
|
||||
color: $active-color;
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
a i {
|
||||
background-color: $active-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
a cite {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.layui-bg-number {
|
||||
background-color: $cover-color;
|
||||
}
|
||||
|
||||
.layui-input,
|
||||
.layui-select,
|
||||
.layui-textarea,
|
||||
.city-picker-span,
|
||||
.main-input {
|
||||
background-color: $cover-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.city-picker-span>.title>span {
|
||||
color: $main-color;
|
||||
|
||||
&:hover {
|
||||
background-color: $main-color;
|
||||
color: $black-color;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-form-radio:hover *,
|
||||
.layui-form-radioed,
|
||||
.layui-form-radioed>i {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-form-checked[lay-skin="primary"] i {
|
||||
border-color: $main-color !important;
|
||||
background-color: $main-color;
|
||||
color: $black-color;
|
||||
}
|
||||
|
||||
.layui-input:focus,
|
||||
.layui-textarea:focus {
|
||||
border-color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-input:hover,
|
||||
.layui-textarea:hover {
|
||||
border-color: $main-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layui-badge-rim,
|
||||
.layui-border,
|
||||
.layui-colla-content,
|
||||
.layui-colla-item,
|
||||
.layui-collapse,
|
||||
.layui-elem-field,
|
||||
.layui-form-pane .layui-form-item[pane],
|
||||
.layui-form-pane .layui-form-label,
|
||||
.layui-input,
|
||||
.layui-layedit,
|
||||
.layui-layedit-tool,
|
||||
.layui-panel,
|
||||
.layui-quote-nm,
|
||||
.layui-select,
|
||||
.layui-tab-bar,
|
||||
.layui-tab-card,
|
||||
.layui-tab-title,
|
||||
.layui-tab-title .layui-this::after,
|
||||
.layui-textarea {
|
||||
border-color: $main-color !important;
|
||||
}
|
||||
|
||||
.form-search .layui-input-inline input,
|
||||
.form-search .layui-input-inline select {
|
||||
border-width: 0 0 0 1px;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-tool .layui-nav-child {
|
||||
border-color: $main-color;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-child a {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-form-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.layuimini-upload .layuimini-upload-btn {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-layer {
|
||||
border: 1px solid $main-color;
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-title {
|
||||
background-color: $plus-main-color !important;
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.layui-table td,
|
||||
.layui-table th,
|
||||
.layui-table-col-set,
|
||||
.layui-table-fixed-r,
|
||||
.layui-table-grid-down,
|
||||
.layui-table-header,
|
||||
.layui-table-page,
|
||||
.layui-table-tips-main,
|
||||
.layui-table-tool,
|
||||
.layui-table-total,
|
||||
.layui-table-view,
|
||||
.layui-table[lay-skin="line"],
|
||||
.layui-table[lay-skin="row"] {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layui-table tbody tr:hover,
|
||||
.layui-table thead tr,
|
||||
.layui-table-click,
|
||||
.layui-table-header,
|
||||
.layui-table-hover,
|
||||
.layui-table-mend,
|
||||
.layui-table-patch,
|
||||
.layui-table-tool,
|
||||
.layui-table-total,
|
||||
.layui-table-total tr {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.hr-line {
|
||||
color: $main-color;
|
||||
border-color: $less-main-color;
|
||||
background-color: $main-color;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn {
|
||||
background-color: $black-color;
|
||||
border-top: 1px solid $less-main-color;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn .layui-layer-btn0 {
|
||||
background-color: $main-color;
|
||||
border-color: $less-main-color;
|
||||
color: $main-color !important;
|
||||
clip-path: $box-shape;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn a {
|
||||
@extend .layui-btn
|
||||
}
|
||||
|
||||
.layui-layer-shade {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
.layuimini-menu-left {
|
||||
.layui-nav-tree .layui-nav-item {
|
||||
|
||||
margin: 5px;
|
||||
width: calc(100% - 10px);
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-item {
|
||||
clip-path: $box-shape;
|
||||
color: $main-color;
|
||||
background-color: $active-color;
|
||||
|
||||
&.layui-this a {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
&.layui-this {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color !important;
|
||||
|
||||
span {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color !important;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-item a:hover {
|
||||
background-color: $active-color !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav .layui-nav-item a,
|
||||
.layuimini-menu-left-zoom.layui-nav .layui-nav-item a {
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-item a span {
|
||||
color: $main-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-item:hover a span {
|
||||
color: $black-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layui-layout-admin .layuimini-logo {
|
||||
background-color: $black-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-itemed>.layui-nav-child {
|
||||
background-color: $black-color !important;
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-tree .layui-this,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-this>a,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this a,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-this,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-this>a,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this a {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color !important;
|
||||
|
||||
.layui-left-nav {
|
||||
color: $black-color !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layui-iconpicker-icon {
|
||||
border-color: $less-main-color !important;
|
||||
background-color: $less-main-color !important;
|
||||
}
|
||||
|
||||
.layui-iconpicker .layui-anim {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-iconpicker .layui-iconpicker-list {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-header .layui-nav .layui-nav-child dd.layui-this a,
|
||||
.layui-header .layui-nav-child dd.layui-this,
|
||||
.layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child .layui-this a {
|
||||
background-color: $active-color !important;
|
||||
}
|
||||
81
public/static/admin/css/themes/_demo.scss
Normal file
81
public/static/admin/css/themes/_demo.scss
Normal file
@@ -0,0 +1,81 @@
|
||||
.layui-btn {
|
||||
color : #808185 !important;
|
||||
background-color: #cde7ff !important;
|
||||
border : 1px solid #d3dde6 !important;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-title {
|
||||
background-color: rgb(215, 215, 215) !important;
|
||||
color : #6C6E71 !important;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin>a::after {
|
||||
color: #6C6E71 !important;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn .layui-layer-btn0 {
|
||||
color : #808185 !important;
|
||||
background-color: #cde7ff !important;
|
||||
border : 1px solid #d3dde6 !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title .layuimini-tab-active {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title li {
|
||||
padding : 0 5px !important;
|
||||
font-size : 12px;
|
||||
border-width: 1px 1px 1px 0 !important;
|
||||
border-style: solid !important;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title li.layui-this {
|
||||
color : #fff !important;
|
||||
border-color: rgba(0, 0, 255, 1) !important;
|
||||
background : rgba(90, 173, 255, 1) !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title .layui-this span {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.layuimini-tab>.layui-tab-title li,
|
||||
.layuimini-tab>.close-box li {
|
||||
line-height: 27px !important;
|
||||
}
|
||||
|
||||
.layuimini-tab>.layui-tab-title,
|
||||
.layuimini-tab>.close-box {
|
||||
height: 28px !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-control>li {
|
||||
height : 28px !important;
|
||||
line-height: 28px !important;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-laypage .layui-laypage-curr .layui-laypage-em {
|
||||
background-color: #6C6E71 !important;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-onswitch {
|
||||
background-color: #cde7ff !important;
|
||||
border-color : #cde7ff !important;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-switch {
|
||||
|
||||
background-color: #6C6E71;
|
||||
border-color : #6C6E71;
|
||||
}
|
||||
|
||||
.layui-table-tool .layui-inline[lay-event] {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.layui-form-checked[lay-skin="primary"] i {
|
||||
border-color : #cde7ff !important;
|
||||
background-color: #cde7ff !important;
|
||||
}
|
||||
708
public/static/admin/css/themes/_gtk.scss
Normal file
708
public/static/admin/css/themes/_gtk.scss
Normal file
@@ -0,0 +1,708 @@
|
||||
& {
|
||||
background-color: #f6f5f4;
|
||||
color : #2e3436;
|
||||
}
|
||||
|
||||
.layuimini-container {}
|
||||
|
||||
.layuimini-main {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-box .layui-table-header th {
|
||||
color : #979a9b !important;
|
||||
font-weight : 700 !important;
|
||||
font-weight : bold;
|
||||
text-shadow : none;
|
||||
border-color : #d7d2ce;
|
||||
border-bottom: 1px solid;
|
||||
|
||||
&:not(:last-child) {
|
||||
|
||||
border-right: 1px solid #d7d2ce;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-table-view .layui-table td {
|
||||
|
||||
border-bottom: unset;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-right: 1px solid #d7d2ce;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.layui-table {
|
||||
color : #2e3436;
|
||||
background: #f6f5f4;
|
||||
}
|
||||
|
||||
.layui-table-view .layui-table[lay-size="sm"] .layui-table-cell {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.layui-table tbody tr:hover,
|
||||
.layui-table thead tr,
|
||||
.layui-table-click,
|
||||
.layui-table-header,
|
||||
.layui-table-hover,
|
||||
.layui-table-mend,
|
||||
.layui-table-patch,
|
||||
.layui-table-tool,
|
||||
.layui-table-total,
|
||||
.layui-table-total tr {
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
.layui-table-cell {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.layui-table img {
|
||||
height: 25px !important;
|
||||
width : auto !important;
|
||||
}
|
||||
|
||||
.layui-btn {
|
||||
position : relative;
|
||||
outline : none;
|
||||
overflow : visible;
|
||||
line-height : 28px;
|
||||
border-radius : 5px;
|
||||
transition : all .15s cubic-bezier(.25, .46, .45, .94);
|
||||
padding : 4px 9px;
|
||||
user-select : none;
|
||||
color : #2e3436;
|
||||
outline-color : rgba(53, 132, 228, .5);
|
||||
border : 1px solid #cdc7c2;
|
||||
border-bottom-color: rgb(205, 199, 194);
|
||||
border-bottom-color: #bfb8b1;
|
||||
background-color : #f6f5f4;
|
||||
box-shadow : inset 0 1px #fff, 0 1px 2px rgba(0, 0, 0, .07);
|
||||
|
||||
&::before {
|
||||
content : ' ';
|
||||
position : absolute;
|
||||
pointer-events: none;
|
||||
width : 100%;
|
||||
height : 100%;
|
||||
top : 0px;
|
||||
left : 0px;
|
||||
background : linear-gradient(to top, rgba(0, 0, 0, 0.03), transparent);
|
||||
transition : all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content : '';
|
||||
position : absolute;
|
||||
pointer-events: none;
|
||||
z-index : 2;
|
||||
display : inline-block;
|
||||
border : 2px solid transparent;
|
||||
border-radius : inherit;
|
||||
transition : all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
top : -4px;
|
||||
left : -4px;
|
||||
width : calc(100% - -4px);
|
||||
height : calc(100% - -4px);
|
||||
}
|
||||
|
||||
&.layui-btn-normal {
|
||||
color : #fff;
|
||||
border-color : #1b6acb #1b6acb #15539e;
|
||||
background-color: #3c88e5;
|
||||
box-shadow : inset 0 1px #3181e3, 0 1px 2px rgba(0, 0, 0, .07);
|
||||
}
|
||||
|
||||
&.layui-btn-danger {
|
||||
color : #fff;
|
||||
border-color : #b2161d #b2161d #851015;
|
||||
background-color: #e41f28;
|
||||
box-shadow : inset 0 1px #db1a23, 0 1px 2px rgba(0, 0, 0, .07);
|
||||
}
|
||||
|
||||
&.layui-btn-sm {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
&.layui-btn-xs {
|
||||
line-height: 12px
|
||||
}
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-tool .layui-inline[lay-event] {
|
||||
@extend .layui-btn;
|
||||
|
||||
line-height : 32px;
|
||||
min-width : 32px;
|
||||
min-height : 32px;
|
||||
padding : 0;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.layui-laydate .layui-this {
|
||||
background-color: #3584e4 !important;
|
||||
|
||||
}
|
||||
|
||||
.layui-laydate-content td,
|
||||
.layui-laydate-content th {
|
||||
|
||||
width : 36px;
|
||||
height : 36px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.laydate-footer-btns span {
|
||||
@extend .layui-btn;
|
||||
|
||||
line-height: 16px;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-right-style : none;
|
||||
border-top-right-radius : 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top-left-radius : 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-laydate-footer span {
|
||||
@extend .layui-btn;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.layui-laydate-footer span.layui-laydate-preview {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.layui-form-checked[lay-skin="primary"] i {
|
||||
border-color : #185fb4 !important;
|
||||
background-color: #5094e8;
|
||||
background-image: linear-gradient(0deg, #3987e5, #5094e8);
|
||||
}
|
||||
|
||||
.layui-form-checkbox[lay-skin="primary"]:hover i {
|
||||
border-color : #185fb4;
|
||||
background-image: linear-gradient(0deg, #5094e8, #6ba5eb);
|
||||
}
|
||||
|
||||
.layui-table-view .layui-form-checkbox[lay-skin="primary"] i {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.layui-table-view .layui-form-checkbox i {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.layui-layer-title {
|
||||
padding : 0 6px;
|
||||
min-height : 46px;
|
||||
border : 1px solid #bfb8b1;
|
||||
border-top-left-radius : 8px;
|
||||
border-top-right-radius: 8px;
|
||||
background : #f1f0ee linear-gradient(0deg, #dfdcd8, #f4f2f1) !important;
|
||||
color : #2e3436 !important;
|
||||
padding-left : 12px;
|
||||
padding-right : 12px;
|
||||
font-weight : bold;
|
||||
}
|
||||
|
||||
.layui-layer {
|
||||
background-color: #f6f5f4;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-title~.layui-layer-setwin>a {
|
||||
position : relative;
|
||||
outline : none;
|
||||
overflow : visible;
|
||||
border-radius: 5px;
|
||||
transition : all .15s cubic-bezier(.25, .46, .45, .94);
|
||||
user-select : none;
|
||||
|
||||
outline-color : rgba(53, 132, 228, .5);
|
||||
border : 1px solid #cdc7c2;
|
||||
border-bottom-color: rgb(205, 199, 194);
|
||||
border-bottom-color: #bfb8b1;
|
||||
background-color : #f6f5f4;
|
||||
box-shadow : inset 0 1px #fff, 0 1px 2px rgba(0, 0, 0, .07);
|
||||
height : 20px;
|
||||
line-height : 20px;
|
||||
width : 20px;
|
||||
text-align : center;
|
||||
display : inline-flex;
|
||||
align-items : center;
|
||||
justify-content : center;
|
||||
|
||||
&::after {
|
||||
color: #2e3436 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-layer-setwin {
|
||||
display : flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-switch.layui-form-onswitch {
|
||||
color : #ffffff;
|
||||
border-color : #185fb4;
|
||||
background-color: #3584e4;
|
||||
text-shadow : 0 1px rgba(53, 132, 228, 0.5), 0 0 2px rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-switch {
|
||||
|
||||
border : 1px solid #cdc7c2;
|
||||
border-radius : 20px;
|
||||
color : rgba(46, 52, 54, 0.2);
|
||||
background-color: #e1dedb;
|
||||
text-shadow : 0 1px rgba(0, 0, 0, 0.1);
|
||||
transition : all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
}
|
||||
|
||||
.layui-form-switch {
|
||||
height: 20px;
|
||||
width : 40px;
|
||||
}
|
||||
|
||||
.layui-form-switch {
|
||||
|
||||
padding : 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.layui-form-switch.layui-form-onswitch i {
|
||||
top : 0;
|
||||
height : 20px;
|
||||
width : 20px;
|
||||
margin-left: -20px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.layui-form-switch i {
|
||||
top : 0;
|
||||
height : 20px;
|
||||
width : 20px;
|
||||
margin-left : -5px;
|
||||
border-radius : 50%;
|
||||
transition : all 150ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
color : #2e3436;
|
||||
outline-color : rgba(53, 132, 228, 0.5);
|
||||
border-color : #cdc7c2;
|
||||
border-bottom-color: #bfb8b1;
|
||||
background-color : #f6f5f4;
|
||||
box-shadow : inset 0 1px white, 0 1px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
|
||||
.layuimini-main {
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
.layui-tab-title li {
|
||||
transition : none;
|
||||
padding : 3px 12px;
|
||||
min-height : 30px;
|
||||
min-width : 65px;
|
||||
display : flex;
|
||||
justify-content : center;
|
||||
align-items : center;
|
||||
white-space : nowrap;
|
||||
color : #2e3436;
|
||||
font-weight : normal;
|
||||
user-select : none;
|
||||
border : 0;
|
||||
border-top-style : none;
|
||||
border-right-style : none;
|
||||
border-bottom-style: none;
|
||||
border-left-style : none;
|
||||
|
||||
|
||||
|
||||
&:hover {
|
||||
box-shadow : inset 0 -3px #c8c2bc;
|
||||
background-color: #edebe9;
|
||||
}
|
||||
|
||||
&.layui-this {
|
||||
box-shadow : inset 0 -3px #3584e4;
|
||||
background-color: #f1f0ee;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-tab-title {
|
||||
display : flex;
|
||||
align-items : center;
|
||||
flex-direction: row;
|
||||
padding-left : 4px;
|
||||
padding-right : 4px;
|
||||
}
|
||||
|
||||
.layuimini-tab>.layui-tab-title li,
|
||||
.layuimini-tab>.close-box li {
|
||||
line-height: 20px !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title .layui-this .layuimini-tab-active {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title .layui-this span {
|
||||
color: #2e3436 !important
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title span {
|
||||
color: #2e3436 !important
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title .layuimini-tab-active {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title {
|
||||
background-color: #e1dedb;
|
||||
border-color : #cdc7c2;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
.layui-layer-dialog .layui-layer-content {
|
||||
background-color: #f2f2f2;
|
||||
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn a {
|
||||
position : relative;
|
||||
outline : none;
|
||||
overflow : visible;
|
||||
line-height : 22px;
|
||||
height : 22px;
|
||||
border-radius : 5px;
|
||||
transition : all .15s cubic-bezier(.25, .46, .45, .94);
|
||||
padding : 4px 9px;
|
||||
user-select : none;
|
||||
color : #2e3436 !important;
|
||||
outline-color : rgba(53, 132, 228, .5);
|
||||
border : 1px solid #cdc7c2;
|
||||
border-bottom-color: rgb(205, 199, 194);
|
||||
border-bottom-color: #bfb8b1;
|
||||
background-color : #f6f5f4;
|
||||
box-shadow : inset 0 1px #fff, 0 1px 2px rgba(0, 0, 0, .07);
|
||||
|
||||
&::before {
|
||||
content : ' ';
|
||||
position : absolute;
|
||||
pointer-events: none;
|
||||
width : 100%;
|
||||
height : 100%;
|
||||
top : 0px;
|
||||
left : 0px;
|
||||
background : linear-gradient(to top, rgba(0, 0, 0, 0.03), transparent);
|
||||
transition : all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content : '';
|
||||
position : absolute;
|
||||
pointer-events: none;
|
||||
z-index : 2;
|
||||
display : inline-block;
|
||||
border : 2px solid transparent;
|
||||
border-radius : inherit;
|
||||
transition : all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
top : -4px;
|
||||
left : -4px;
|
||||
width : calc(100% - -4px);
|
||||
height : calc(100% - -4px);
|
||||
}
|
||||
|
||||
|
||||
&.layui-layer-btn0 {
|
||||
color : #fff !important;
|
||||
border-color : #1b6acb #1b6acb #15539e;
|
||||
background-color: #3c88e5;
|
||||
box-shadow : inset 0 1px #3181e3, 0 1px 2px rgba(0, 0, 0, .07);
|
||||
}
|
||||
}
|
||||
|
||||
.layui-tab-brief {
|
||||
|
||||
&>.layui-tab-title {
|
||||
|
||||
li {
|
||||
@extend .layui-btn;
|
||||
|
||||
|
||||
&:not(:last-child) {
|
||||
border-right-style : none;
|
||||
border-top-right-radius : 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top-left-radius : 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
&.layui-this {
|
||||
color : unset;
|
||||
color : #2e3436;
|
||||
border-color : #cdc7c2;
|
||||
background-color: #d6d1cd;
|
||||
box-shadow : inset 0 1px rgba(255, 255, 255, 0);
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow : unset;
|
||||
background-color: #edebe9;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layui-form-radio:hover *,
|
||||
.layui-form-radioed,
|
||||
.layui-form-radioed>i {
|
||||
color: #5094e8;
|
||||
}
|
||||
|
||||
.layui-card {
|
||||
.layui-card-header {
|
||||
padding : 0 6px;
|
||||
min-height : 46px;
|
||||
border-width : 1px;
|
||||
border-style : solid;
|
||||
border-color : #bfb8b1;
|
||||
border-top-left-radius : 8px;
|
||||
border-top-right-radius: 8px;
|
||||
background : #f1f0ee linear-gradient(to top, #dfdcd8, #f4f2f1);
|
||||
box-shadow : inset 0 1px rgba(255, 255, 255, 0.8), inset 0 -2px 2px rgba(0, 0, 0, 0.02);
|
||||
|
||||
.icon {
|
||||
color: #979a9b !important;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-card-body {
|
||||
background-color: #f6f5f4;
|
||||
border : 1px solid #cdc7c2;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-btn,
|
||||
.layui-input,
|
||||
.layui-select,
|
||||
.layui-textarea,
|
||||
.layui-upload-button,
|
||||
.city-picker-span {
|
||||
border-radius: 5px;
|
||||
border : 1px solid #cdc7c2;
|
||||
}
|
||||
|
||||
.layui-side.layui-bg-black,
|
||||
.layui-side.layui-bg-black>.layuimini-menu-left>ul,
|
||||
.layuimini-menu-left-zoom>ul {
|
||||
background-color: #f6f5f4 !important;
|
||||
}
|
||||
|
||||
.layuimini-menu-left {
|
||||
background-color: #fbfafa;
|
||||
border-right : 1px solid #cdc7c2;
|
||||
|
||||
.layui-nav {
|
||||
|
||||
li {
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid #cdc7c2;
|
||||
}
|
||||
|
||||
|
||||
&.layui-this {
|
||||
a {
|
||||
background-color: #347cd3 !important;
|
||||
color : #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layuimini-menu-left .layui-nav .layui-this a,
|
||||
|
||||
.layuimini-menu-left-zoom.layui-nav .layui-this a {
|
||||
color: #2e3436 !important;
|
||||
}
|
||||
|
||||
|
||||
.layuimini-menu-left .layui-nav .layui-nav-item.layui-this a:hover,
|
||||
.layuimini-menu-left-zoom.layui-nav .layui-nav-item.layui-this a:hover {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav .layui-nav-item a,
|
||||
.layuimini-menu-left-zoom.layui-nav .layui-nav-item a {
|
||||
color: #2e3436 !important;
|
||||
|
||||
&:hover {
|
||||
color: #2e3436 !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav .layui-nav-item a {
|
||||
height : 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-itemed>.layui-nav-child {
|
||||
background-color: rgba(46, 52, 54, 0.05) !important;
|
||||
border-top : 1px solid #d7d2ce;
|
||||
|
||||
dd {
|
||||
border-bottom: 1px solid #d7d2ce;
|
||||
}
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-tree .layui-this,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-this>a,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this a,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-this,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-this>a,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this a {
|
||||
background-color: #347cd3 !important;
|
||||
color : #fff !important;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layuimini-logo {
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
|
||||
.layuimini-header-menu>li.layui-nav-item {
|
||||
@extend .layui-btn;
|
||||
margin-top : 10px;
|
||||
height : 30px !important;
|
||||
line-height: 30px !important;
|
||||
|
||||
|
||||
&::after {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-right-style : none;
|
||||
border-top-right-radius : 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top-left-radius : 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
&:nth-last-child(2) {
|
||||
border-right-style : solid;
|
||||
border-radius : 5px;
|
||||
border-top-left-radius : 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header {
|
||||
background-color: #f6f5f4 !important;
|
||||
}
|
||||
|
||||
.layui-layer-dialog {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.layui-layer-iframe {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-control>li {
|
||||
background-color: #e1dedb;
|
||||
border-style : solid;
|
||||
border-color : #cdc7c2;
|
||||
}
|
||||
|
||||
.form-search .layui-btn {
|
||||
height : 32px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.form-search .layui-form-select dl {
|
||||
transition : all 80ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
background-color : #ffffff;
|
||||
background-clip : padding-box;
|
||||
border : 1px solid rgba(0, 0, 0, 0.23);
|
||||
border-top-left-radius : 0;
|
||||
border-top-right-radius: 0;
|
||||
border-radius : 9px;
|
||||
border-top-left-radius : 0px;
|
||||
border-top-right-radius: 0px;
|
||||
box-shadow : 0 1px 3px 2px rgba(0, 0, 0, 0.08);
|
||||
top : 28px;
|
||||
}
|
||||
|
||||
.layui-form-select dl dd,
|
||||
.layui-form-select dl dt {
|
||||
height : 30px;
|
||||
line-height: 30px;
|
||||
padding : 0 10px;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-select dl dd.layui-this {
|
||||
background-color: #3c88e5 !important;
|
||||
}
|
||||
|
||||
.layui-table-header .layui-table {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.layui-header .layui-nav .layui-nav-child dd.layui-this a,
|
||||
.layui-header .layui-nav-child dd.layui-this,
|
||||
.layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child .layui-this a {
|
||||
background-color: #3c88e5 !important;
|
||||
}
|
||||
|
||||
.layuimini-mobile-show {
|
||||
.layui-nav-more {
|
||||
top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin>span {
|
||||
color: #2e3436;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin>span:after {
|
||||
|
||||
color: #2e3436;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin .layui-layer-max::after,
|
||||
.layui-layer-easy .layui-layer-setwin .layui-layer-max::before {
|
||||
border-color: #2e3436;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin .layui-layer-min::before {
|
||||
background-color: #2e3436;
|
||||
}
|
||||
284
public/static/admin/css/themes/_neomorphic.scss
Normal file
284
public/static/admin/css/themes/_neomorphic.scss
Normal file
@@ -0,0 +1,284 @@
|
||||
$main-color:#61677C;
|
||||
|
||||
& {
|
||||
background-color: #EBECF0;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header {
|
||||
background-color: #EBECF0 !important;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-container .layui-btn-success {
|
||||
|
||||
color: #4bb368;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-btn-danger {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.layuimini-container .layuimini-btn-primary {
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-btn-primary {
|
||||
color: #5f5f5f;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-btn-normal {
|
||||
color: #1e9fff;
|
||||
}
|
||||
|
||||
.layui-btn {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
border-radius: 10px;
|
||||
background-color: #EBECF0;
|
||||
text-shadow: 1px 1px 0 #FFF;
|
||||
color: $main-color;
|
||||
box-shadow: -5px -5px 20px #FFF, 5px 5px 20px #BABECC;
|
||||
transition: all 0.2s ease-in-out;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
|
||||
&:hover {
|
||||
box-shadow: -2px -2px 5px #FFF, 2px 2px 5px #BABECC;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layui-table-tool .layui-inline[lay-event] {
|
||||
@extend .layui-btn;
|
||||
}
|
||||
|
||||
.layuimini-main {
|
||||
@extend .layui-btn;
|
||||
text-shadow: 0.5px 0.5px 0 #fff;
|
||||
}
|
||||
|
||||
.layui-layer {
|
||||
@extend .layui-btn;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-title {
|
||||
background-color: transparent !important;
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin>span {
|
||||
color: $main-color !important;
|
||||
|
||||
&::before {
|
||||
border-color: $main-color !important;
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-color: $main-color !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin .layui-layer-min::before {
|
||||
background-color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-card {
|
||||
@extend .layui-btn;
|
||||
text-shadow: 0.5px 0.5px 0 #fff;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-tool {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.layui-table {
|
||||
background-color: #EBECF0;
|
||||
}
|
||||
|
||||
.panel {
|
||||
@extend .layui-btn;
|
||||
text-shadow: 0.5px 0.5px 0 #fff;
|
||||
}
|
||||
|
||||
.layuimini-qiuck-module {
|
||||
@extend .layui-btn;
|
||||
|
||||
i {
|
||||
background-color: transparent
|
||||
}
|
||||
}
|
||||
|
||||
.layui-side.layui-bg-black,
|
||||
.layui-side.layui-bg-black>.layuimini-menu-left>ul,
|
||||
.layuimini-menu-left-zoom>ul {
|
||||
@extend .layui-btn;
|
||||
background-color: #EBECF0 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
|
||||
.layuimini-menu-left .layui-nav .layui-nav-item a,
|
||||
.layuimini-menu-left-zoom.layui-nav .layui-nav-item a {
|
||||
@extend .layui-btn;
|
||||
|
||||
&:hover {
|
||||
box-shadow: -2px -2px 5px #FFF, 2px 2px 5px #BABECC;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item {
|
||||
margin: 10px;
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-itemed>.layui-nav-child {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-child dd {
|
||||
margin: 10px;
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-tree .layui-this,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-this>a,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this a,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-this,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-this>a,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this a {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav .layui-nav-item a:hover,
|
||||
.layuimini-menu-left .layui-nav .layui-this a,
|
||||
.layuimini-menu-left-zoom.layui-nav .layui-nav-item a:hover,
|
||||
.layuimini-menu-left-zoom.layui-nav .layui-this a {
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layuimini-logo {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.layui-header {
|
||||
.layuimini-header-menu>.layui-nav-item {
|
||||
@extend .layui-btn;
|
||||
margin: 10px;
|
||||
line-height: 40px !important;
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-item {
|
||||
@extend .layui-btn;
|
||||
margin: 10px;
|
||||
line-height: 40px !important;
|
||||
height: 40px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layui-btn-xs {
|
||||
padding: 0 9px;
|
||||
}
|
||||
|
||||
.layui-input,
|
||||
.layui-textarea {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
font-size: 16px;
|
||||
border-radius: 320px;
|
||||
padding: 16px;
|
||||
background-color: #EBECF0;
|
||||
text-shadow: 1px 1px 0 #FFF;
|
||||
margin-right: 8px;
|
||||
box-shadow: inset 2px 2px 5px #BABECC, inset -5px -5px 10px #FFF;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.2s ease-in-out;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.layuimini-upload .layuimini-upload-btn {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.layui-form-pane .layui-form-label {
|
||||
background-color: transparent;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-select dl dd.layui-this {
|
||||
background-color: transparent !important;
|
||||
color: #2c3e50
|
||||
}
|
||||
|
||||
.layuimini-color .elem-content li.layui-this {
|
||||
text-shadow: 0.5px 0.5px 0 #FFF;
|
||||
}
|
||||
|
||||
.layui-form-select dl {
|
||||
@extend .layui-btn;
|
||||
}
|
||||
|
||||
.layui-form-checkbox {
|
||||
|
||||
@extend .layui-btn;
|
||||
padding: 10px 10px 10px 24px;
|
||||
}
|
||||
|
||||
.layui-form-checkbox>i {
|
||||
left: 6px;
|
||||
top: 10px;
|
||||
text-shadow: 0.5px 0.5px 0 #fff;
|
||||
}
|
||||
|
||||
.layui-form-checked:hover>div,
|
||||
.layui-form-checked>div {
|
||||
|
||||
color: #16b777;
|
||||
}
|
||||
|
||||
.layui-tree,
|
||||
.laytable-cell-checkbox {
|
||||
|
||||
.layui-form-checkbox[lay-skin="primary"] {
|
||||
padding: 13px;
|
||||
}
|
||||
|
||||
.layui-form-checkbox[lay-skin="primary"]>i {
|
||||
left: 5px;
|
||||
top: 5px
|
||||
}
|
||||
}
|
||||
|
||||
.layui-tree-txt {
|
||||
margin-left: 10px
|
||||
}
|
||||
|
||||
.layui-form-radio {
|
||||
@extend .layui-btn;
|
||||
|
||||
}
|
||||
|
||||
.layui-form-radio:hover>*,
|
||||
.layui-form-radioed,
|
||||
.layui-form-radioed>i {
|
||||
color: #16b777;
|
||||
}
|
||||
|
||||
.layui-table-tips-c {
|
||||
text-shadow: 0.5px 0.5px 0 #fff;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title {
|
||||
background-color: #EBECF0;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-control>li {
|
||||
background-color: #EBECF0;
|
||||
}
|
||||
344
public/static/admin/css/themes/_nes.scss
Normal file
344
public/static/admin/css/themes/_nes.scss
Normal file
@@ -0,0 +1,344 @@
|
||||
a,
|
||||
button {
|
||||
cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAzElEQVRYR+2X0Q6AIAhF5f8/2jYXZkwEjNSVvVUjDpcrGgT7FUkI2D9xRfQETwNIiWO85wfINfQUEyxBG2ArsLwC0jioGt5zFcwF4OYDPi/mBYKm4t0U8ATgRm3ThFoAqkhNgWkA0jJLvaOVSs7j3qMnSgXWBMiWPXe94QqMBMBc1VZIvaTu5u5pQewq0EqNZvIEMCmxAawK0DNkay9QmfFNAJUXfgGgUkLaE7j/h8fnASkxHTz0DGIBMCnBeeM7AArpUd3mz2x3C7wADglA8BcWMZhZAAAAAElFTkSuQmCC) 14 0, pointer
|
||||
}
|
||||
|
||||
& {
|
||||
cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABFklEQVRYR9WXURLDIAhE6/0PbSdOtUpcd1Gnpv1KGpTHBpCE1/cXq+vrMph7dGvXZTtpfW10DCA5jrH1H0Jhs5E0hnZdCR+vb5S8Nn8mQCeS9BdSalYJqMBjAGzq59xAESN7VFVUgV8AZB/dZBR7QTFDCqGquvUBVVoEtgIwpQRzmANSFHgWQKExHdIrPeuMvQNDarXe6nC/AutgV3JW+6bgqQLeV8FekRtgV+ToDKEKnACYKsfZjjkam7a0ZpYTytwmgainpC3HvwBocgKOxqRjehoR9DFKNFYtOwCGYCszobeCbl26N6yyQ6g8X/Wex/rBPsNEV6qAMaJPMynIHQCoSqS9JSMmwef51LflTgCRszU7DvAGiV6mHWfsaVUAAAAASUVORK5CYII=), auto;
|
||||
font-family: "ark-pixel";
|
||||
}
|
||||
|
||||
$border-line-width:3px;
|
||||
|
||||
.public-border {
|
||||
border-style: solid;
|
||||
border-width: $border-line-width;
|
||||
border-image-slice: 2;
|
||||
border-image-width: 2;
|
||||
border-image-repeat: stretch;
|
||||
border-image-source: url('data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8" ?><svg version="1.1" width="5" height="5" xmlns="http://www.w3.org/2000/svg"><path d="M2 1 h1 v1 h-1 z M1 2 h1 v1 h-1 z M3 2 h1 v1 h-1 z M2 3 h1 v1 h-1 z" fill="rgb(33,37,41)" /></svg>');
|
||||
border-image-outset: 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.layui-btn {
|
||||
|
||||
@extend .public-border;
|
||||
line-height: 32px;
|
||||
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAzElEQVRYR+2X0Q6AIAhF5f8/2jYXZkwEjNSVvVUjDpcrGgT7FUkI2D9xRfQETwNIiWO85wfINfQUEyxBG2ArsLwC0jioGt5zFcwF4OYDPi/mBYKm4t0U8ATgRm3ThFoAqkhNgWkA0jJLvaOVSs7j3qMnSgXWBMiWPXe94QqMBMBc1VZIvaTu5u5pQewq0EqNZvIEMCmxAawK0DNkay9QmfFNAJUXfgGgUkLaE7j/h8fnASkxHTz0DGIBMCnBeeM7AArpUd3mz2x3C7wADglA8BcWMZhZAAAAAElFTkSuQmCC) 14 0, pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
color: #212529;
|
||||
background-color: #fff;
|
||||
border-image-repeat: stretch;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: -$border-line-width;
|
||||
right: -$border-line-width;
|
||||
bottom: -$border-line-width;
|
||||
left: -$border-line-width;
|
||||
content: "";
|
||||
box-shadow: inset (-$border-line-width) (-$border-line-width) #adafbc;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #212529;
|
||||
text-decoration: none;
|
||||
background-color: #e7e7e7;
|
||||
}
|
||||
|
||||
&.layui-btn-sm {
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
&.layui-btn-xs {
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
&.layui-btn-normal {
|
||||
color: #fff;
|
||||
background-color: #209cee;
|
||||
|
||||
&::after {
|
||||
box-shadow: inset (-$border-line-width) (-$border-line-width) #006bb3;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #108de0;
|
||||
}
|
||||
}
|
||||
|
||||
&.layui-btn-success {
|
||||
color: #fff;
|
||||
background-color: #92cc41;
|
||||
|
||||
&::after {
|
||||
box-shadow: inset (-$border-line-width) (-$border-line-width) #4aa52e;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #92cc41;
|
||||
}
|
||||
}
|
||||
|
||||
&.layui-btn-danger {
|
||||
color: #fff;
|
||||
background-color: #e76e55;
|
||||
|
||||
&::after {
|
||||
box-shadow: inset (-$border-line-width) (-$border-line-width) #8c2022;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #ce372b;
|
||||
}
|
||||
}
|
||||
|
||||
&.layui-btn-warm {
|
||||
color: #212529;
|
||||
background-color: #f7d51d;
|
||||
|
||||
&::after {
|
||||
box-shadow: inset (-$border-line-width) (-$border-line-width) #e59400;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #212529;
|
||||
background-color: #f2c409;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-search .layui-btn {
|
||||
line-height: 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.layuimini-container .layui-table-tool .layui-inline[lay-event] {
|
||||
@extend .layui-btn;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.layui-table img {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.layui-form-checkbox[lay-skin="primary"] i {
|
||||
@extend .public-border;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layui-form-checked[lay-skin="primary"] i {
|
||||
background-color: unset;
|
||||
color: #212529;
|
||||
font-weight: bold;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.layui-btn {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.layui-btn-sm {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.layui-btn-xs {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.layui-nav * {
|
||||
font-size: 16px;
|
||||
|
||||
}
|
||||
|
||||
.layui-tab-title li {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item {
|
||||
border-bottom: 3px solid #212529;
|
||||
}
|
||||
|
||||
.layuimini-header-menu>.layui-nav-item {
|
||||
|
||||
@extend .public-border;
|
||||
|
||||
border-image-outset: 0;
|
||||
}
|
||||
|
||||
.layui-table td,
|
||||
.layui-table th {
|
||||
font-size: 16px;
|
||||
border-width: 0 2px 2px 0;
|
||||
border-style: solid;
|
||||
border-color: #212529
|
||||
}
|
||||
|
||||
.layui-input,
|
||||
.layui-select,
|
||||
.layui-textarea {
|
||||
@extend .public-border;
|
||||
}
|
||||
|
||||
.layui-form-label {
|
||||
background-color: unset;
|
||||
border: unset;
|
||||
text-align: right;
|
||||
color: #212529;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.layuimini-form>.layui-form-item>.layui-input-block tip,
|
||||
.layuimini-form>.layui-form-item>.layui-inline tip {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-title {
|
||||
background: unset !important;
|
||||
color: #212529 !important;
|
||||
font-size: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn {
|
||||
background: unset !important;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn a {
|
||||
@extend .layui-btn;
|
||||
color: #212529 !important;
|
||||
|
||||
&.layui-layer-btn0 {
|
||||
color: #fff !important;
|
||||
background-color: #209cee;
|
||||
|
||||
&::after {
|
||||
box-shadow: inset (-$border-line-width) (-$border-line-width) #006bb3;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #108de0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layui-layer-dialog .layui-layer-content {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin>span {
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin>span:after {
|
||||
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin .layui-layer-max::after,
|
||||
.layui-layer-easy .layui-layer-setwin .layui-layer-max::before {
|
||||
border-color: #212529;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-setwin .layui-layer-min::before {
|
||||
background-color: #212529;
|
||||
}
|
||||
|
||||
|
||||
.layui-layer {
|
||||
@extend .public-border;
|
||||
|
||||
}
|
||||
|
||||
.layui-card {
|
||||
@extend .public-border;
|
||||
|
||||
.layui-card-header {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layuimini-main {
|
||||
@extend .public-border;
|
||||
}
|
||||
|
||||
.layui-table-box {
|
||||
@extend .public-border;
|
||||
border-image-outset: 1;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-box .layui-table-header th {
|
||||
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
.layui-table tbody tr:hover,
|
||||
.layui-table thead tr,
|
||||
.layui-table-click,
|
||||
.layui-table-header,
|
||||
.layui-table-hover,
|
||||
.layui-table-mend,
|
||||
.layui-table-patch,
|
||||
.layui-table-tool,
|
||||
.layui-table-total,
|
||||
.layui-table-total tr {
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
.layui-table-header .layui-table {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.layui-badge,
|
||||
.layui-badge-rim {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 4px #209cee, 0 -4px #209cee, 4px 0 #209cee, -4px 0 #209cee;
|
||||
}
|
||||
|
||||
&.layui-bg-blue {
|
||||
background-color: #209cee;
|
||||
|
||||
&::after {
|
||||
box-shadow: 0 4px #209cee, 0 -4px #209cee, 4px 0 #209cee, -4px 0 #209cee;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
&.layui-bg-gray {
|
||||
background-color: #92cc41;
|
||||
|
||||
&::after {
|
||||
box-shadow: 0 4px #92cc41, 0 -4px #92cc41, 4px 0 #92cc41, -4px 0 #92cc41;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layuimini-color .elem-content li {
|
||||
cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAzElEQVRYR+2X0Q6AIAhF5f8/2jYXZkwEjNSVvVUjDpcrGgT7FUkI2D9xRfQETwNIiWO85wfINfQUEyxBG2ArsLwC0jioGt5zFcwF4OYDPi/mBYKm4t0U8ATgRm3ThFoAqkhNgWkA0jJLvaOVSs7j3qMnSgXWBMiWPXe94QqMBMBc1VZIvaTu5u5pQewq0EqNZvIEMCmxAawK0DNkay9QmfFNAJUXfgGgUkLaE7j/h8fnASkxHTz0DGIBMCnBeeM7AArpUd3mz2x3C7wADglA8BcWMZhZAAAAAElFTkSuQmCC) 14 0, pointer;
|
||||
}
|
||||
0
public/static/admin/css/themes/_normal.scss
Normal file
0
public/static/admin/css/themes/_normal.scss
Normal file
802
public/static/admin/css/themes/_sicfi.scss
Normal file
802
public/static/admin/css/themes/_sicfi.scss
Normal file
@@ -0,0 +1,802 @@
|
||||
// 通常用于背景色
|
||||
$black-color :rgb(2, 17, 20);
|
||||
// 通常用于字体颜色
|
||||
$main-color :rgb(126, 252, 246);
|
||||
// 通常用于边框
|
||||
$less-main-color:rgb(6, 216, 215);
|
||||
|
||||
$plus-main-color:rgb(0, 125, 124);
|
||||
|
||||
// 通常用于激活状态,通常跟背景色搭配
|
||||
$cover-color :rgba(62, 251, 251, 0.05);
|
||||
// 更强的激活状态,适合做选项操作时使用
|
||||
$active-color :rgba(62, 251, 251, 0.5);
|
||||
|
||||
|
||||
$red-color :rgb(255, 0, 0);
|
||||
$yellow-color:rgb(255, 255, 153);
|
||||
$green-color :rgb(0, 255, 0);
|
||||
|
||||
& {
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layuimini-main {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layuimini-container {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-tool {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
$box-shape: polygon(0 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 0);
|
||||
|
||||
.layui-btn {
|
||||
|
||||
&.layui-btn-lg {
|
||||
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
clip-path : $box-shape;
|
||||
padding-right : 10px;
|
||||
position : relative;
|
||||
background-color: transparent;
|
||||
border : 1px solid;
|
||||
color : rgb(126, 252, 246);
|
||||
text-shadow : rgb(126, 252, 246) 0px 0px 1px;
|
||||
background-color: rgb(126, 252, 246);
|
||||
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
clip-path: $box-shape;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: -0.5px;
|
||||
top: -0.5px;
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
&:hover::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
clip-path: $box-shape;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: -0.5px;
|
||||
top: -0.5px;
|
||||
background-color: rgba(126, 252, 246, 0.2);
|
||||
}
|
||||
|
||||
&.layui-btn-disabled {
|
||||
&::after {
|
||||
// todo:实现按钮禁用样式
|
||||
}
|
||||
}
|
||||
|
||||
&.layui-btn-success {
|
||||
text-shadow: rgb(0, 255, 0) 0px 0px 1px;
|
||||
color: rgb(0, 255, 0);
|
||||
background-color: rgba(0, 255, 0);
|
||||
border: unset;
|
||||
|
||||
&:hover::after {
|
||||
background-color: rgba(0, 255, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&.layui-btn-danger {
|
||||
text-shadow: rgb(255, 0, 0) 0px 0px 1px;
|
||||
color: rgb(255, 0, 0);
|
||||
background-color: rgb(255, 0, 0);
|
||||
border: unset;
|
||||
|
||||
&:hover::after {
|
||||
background-color: rgba(255, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&.layuimini-btn-primary {
|
||||
text-shadow: rgb(255, 255, 153) 0px 0px 1px;
|
||||
color: rgb(255, 255, 153);
|
||||
background-color: rgb(255, 255, 153);
|
||||
border: unset;
|
||||
|
||||
&:hover::after {
|
||||
background-color: rgba(255, 255, 153, 0.2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.layui-btn-primary {
|
||||
border: unset;
|
||||
}
|
||||
|
||||
&.layui-btn-normal {
|
||||
color: $black-color;
|
||||
background-color: $main-color;
|
||||
border: unset;
|
||||
|
||||
&::before {
|
||||
background-color: $main-color;
|
||||
}
|
||||
|
||||
&:hover::after {
|
||||
background-color: $main-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layui-table {
|
||||
background: $black-color;
|
||||
color: $main-color;
|
||||
|
||||
|
||||
tr {
|
||||
background-color: $cover-color;
|
||||
}
|
||||
|
||||
td {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layui-table-header {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-box {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-table-box .layui-table-header th {
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-table-tool .layui-inline[lay-event] {
|
||||
color: $main-color;
|
||||
border: none;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
border-color: $main-color;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
clip-path: $box-shape;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: calc(100% - 1px);
|
||||
height: calc(100% - 1px);
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-table tbody tr:hover {
|
||||
background-color: rgba(126, 252, 246, 0.1);
|
||||
}
|
||||
|
||||
.layuimini-main {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layui-table-header {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.color-content>ul>li>a>div>span:nth-child(2) {
|
||||
background-color: $black-color !important;
|
||||
}
|
||||
|
||||
.layuimini-color .elem-content li {
|
||||
clip-path: $box-shape;
|
||||
}
|
||||
|
||||
.layuimini-color .elem-content li.layui-this {
|
||||
background-color: $main-color;
|
||||
color: $black-color !important;
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layuimini-color .more-menu-item {
|
||||
color: $main-color;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(62, 251, 251, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header {
|
||||
background-color: $cover-color !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title {
|
||||
background-color: $cover-color !important;
|
||||
border-color: $less-main-color;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title span {
|
||||
color: $active-color;
|
||||
}
|
||||
|
||||
.layui-header .layuimini-menu-header-pc.layui-nav .layui-nav-item a:hover,
|
||||
.layui-header .layuimini-header-menu.layuimini-pc-show.layui-nav .layui-this a {
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header .layui-nav .layui-nav-item a {
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header .layui-nav .layui-nav-item {
|
||||
background-color: $active-color;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.layui-layout-admin .layui-header .layuimini-header-content>ul>.layui-nav-item.layui-this,
|
||||
.layuimini-tool i:hover {
|
||||
background-color: $main-color !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-control>li {
|
||||
background-color: $black-color;
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title li {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layui-flow-more a *,
|
||||
.layui-laypage input,
|
||||
.layui-table-view select[lay-ignore] {
|
||||
border-color: $less-main-color;
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-laypage button,
|
||||
.layui-laypage input {
|
||||
border-color: $less-main-color;
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-switch {
|
||||
border-color: $less-main-color !important;
|
||||
background-color: $black-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-onswitch {
|
||||
background-color: $main-color !important;
|
||||
}
|
||||
|
||||
.layuimini-container .layui-form-switch.layui-form-onswitch i {
|
||||
background-color: $black-color !important;
|
||||
}
|
||||
.layuimini-container .layui-laypage .layui-laypage-curr .layui-laypage-em {
|
||||
background-color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-laypage .layui-laypage-curr em {
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title .layui-this .layuimini-tab-active {
|
||||
background-color: $less-main-color;
|
||||
|
||||
}
|
||||
|
||||
.layui-table-view .layui-form-checkbox.layui-form-checked[lay-skin="primary"] i {
|
||||
border-color: $main-color;
|
||||
background-color: $main-color;
|
||||
color: $black-color;
|
||||
}
|
||||
|
||||
.layui-table-view .layui-form-checkbox[lay-skin="primary"] i {
|
||||
background-color: $cover-color;
|
||||
}
|
||||
|
||||
.layui-table-init {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.box-border-line {
|
||||
position: relative;
|
||||
border: 1px solid $less-main-color;
|
||||
border-width: 1px;
|
||||
$border-offset: 3px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
transition: all 0.2s;
|
||||
border: 1px solid $less-main-color;
|
||||
top: -$border-offset;
|
||||
left: -$border-offset;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
transition: all 0.2s;
|
||||
border: 1px solid $less-main-color;
|
||||
bottom: -$border-offset;
|
||||
right: -$border-offset;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
&::after,
|
||||
&::before {
|
||||
width: calc(100% + $border-offset);
|
||||
height: calc(100% + $border-offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-search-fieldset {
|
||||
.layui-input-inline {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.layui-form-item:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
@extend .box-border-line;
|
||||
}
|
||||
|
||||
.layui-form-label {
|
||||
border: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-form-pane .layui-form-label {
|
||||
background-color: $cover-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layuimini-container .table-search-fieldset {
|
||||
color: $main-color;
|
||||
border-color: $less-main-color;
|
||||
|
||||
}
|
||||
|
||||
.layui-form-select,
|
||||
.layui-form-autocomplete {
|
||||
dl {
|
||||
|
||||
color: $main-color;
|
||||
background-color: $black-color;
|
||||
border-color: $less-main-color;
|
||||
|
||||
dd {
|
||||
&.layui-this {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $less-main-color !important;
|
||||
color: $black-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layui-iconpicker-item,
|
||||
.layui-iconpicker-item:hover {
|
||||
border-color: $less-main-color !important;
|
||||
color: $black-color;
|
||||
|
||||
.layui-iconpicker-icon:hover {
|
||||
border-color: $less-main-color !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layui-nav-child {
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child a {
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-badge,
|
||||
.layui-badge-dot,
|
||||
.layui-badge-rim {
|
||||
background-color: $main-color;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-child a:hover {
|
||||
background-color: $active-color;
|
||||
}
|
||||
|
||||
.layui-table-tool-panel {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-form-checkbox[lay-skin="primary"] span {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-table-tool-panel li:hover {
|
||||
background-color: $active-color;
|
||||
}
|
||||
|
||||
.layui-side.layui-bg-black,
|
||||
.layui-side.layui-bg-black>.layuimini-menu-left>ul,
|
||||
.layuimini-menu-left-zoom>ul {
|
||||
background-color: $black-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layui-side {
|
||||
border-right: 1px solid $main-color;
|
||||
}
|
||||
|
||||
.layui-bg-blue {
|
||||
background-color: #0000ff !important;
|
||||
}
|
||||
|
||||
.layui-bg-orange {
|
||||
background-color: $yellow-color !important;
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
.layui-bg-green {
|
||||
background-color: $green-color !important;
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
.layui-table-hover {
|
||||
background-color: $cover-color;
|
||||
}
|
||||
|
||||
.layui-table-grid-down {
|
||||
background-color: $black-color;
|
||||
color: $main-color;
|
||||
border-color: unset;
|
||||
}
|
||||
|
||||
.layui-table-tips-main {
|
||||
background-color: $main-color;
|
||||
color: $black-color;
|
||||
}
|
||||
|
||||
.layui-layout-admin .layui-header .layuimini-tool i {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.color-red {
|
||||
color: $red-color !important;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-title .layui-this span {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-card {
|
||||
|
||||
background-color: $cover-color;
|
||||
border-radius: 0;
|
||||
|
||||
@extend .box-border-line;
|
||||
|
||||
.layui-card-header {
|
||||
color: $main-color;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-text {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
|
||||
.layuimini-qiuck-module {
|
||||
cursor: pointer;
|
||||
|
||||
a i {
|
||||
background-color: $cover-color;
|
||||
color: $active-color;
|
||||
}
|
||||
|
||||
a cite {
|
||||
color: $active-color;
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
a i {
|
||||
background-color: $active-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
a cite {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.layui-bg-number {
|
||||
background-color: $cover-color;
|
||||
}
|
||||
|
||||
.layui-input,
|
||||
.layui-select,
|
||||
.layui-textarea,
|
||||
.city-picker-span,
|
||||
.main-input {
|
||||
background-color: $cover-color;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.city-picker-span>.title>span {
|
||||
color: $main-color;
|
||||
|
||||
&:hover {
|
||||
background-color: $main-color;
|
||||
color: $black-color;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-form-radio:hover *,
|
||||
.layui-form-radioed,
|
||||
.layui-form-radioed>i {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-form-checked[lay-skin="primary"] i {
|
||||
border-color: $main-color !important;
|
||||
background-color: $main-color;
|
||||
color: $black-color;
|
||||
}
|
||||
|
||||
.layui-input:focus,
|
||||
.layui-textarea:focus {
|
||||
border-color: $main-color !important;
|
||||
}
|
||||
|
||||
.layui-input:hover,
|
||||
.layui-textarea:hover {
|
||||
border-color: $main-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layui-badge-rim,
|
||||
.layui-border,
|
||||
.layui-colla-content,
|
||||
.layui-colla-item,
|
||||
.layui-collapse,
|
||||
.layui-elem-field,
|
||||
.layui-form-pane .layui-form-item[pane],
|
||||
.layui-form-pane .layui-form-label,
|
||||
.layui-input,
|
||||
.layui-layedit,
|
||||
.layui-layedit-tool,
|
||||
.layui-panel,
|
||||
.layui-quote-nm,
|
||||
.layui-select,
|
||||
.layui-tab-bar,
|
||||
.layui-tab-card,
|
||||
.layui-tab-title,
|
||||
.layui-tab-title .layui-this::after,
|
||||
.layui-textarea {
|
||||
border-color: $main-color !important;
|
||||
}
|
||||
|
||||
.form-search .layui-input-inline input,
|
||||
.form-search .layui-input-inline select {
|
||||
border-width: 0 0 0 1px;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-tool .layui-nav-child {
|
||||
border-color: $main-color;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-child a {
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.layui-form-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.layuimini-upload .layuimini-upload-btn {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-layer {
|
||||
border: 1px solid $main-color;
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-title {
|
||||
background-color: $plus-main-color !important;
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.layui-table td,
|
||||
.layui-table th,
|
||||
.layui-table-col-set,
|
||||
.layui-table-fixed-r,
|
||||
.layui-table-grid-down,
|
||||
.layui-table-header,
|
||||
.layui-table-page,
|
||||
.layui-table-tips-main,
|
||||
.layui-table-tool,
|
||||
.layui-table-total,
|
||||
.layui-table-view,
|
||||
.layui-table[lay-skin="line"],
|
||||
.layui-table[lay-skin="row"] {
|
||||
border-color: $less-main-color;
|
||||
}
|
||||
|
||||
.layui-table tbody tr:hover,
|
||||
.layui-table thead tr,
|
||||
.layui-table-click,
|
||||
.layui-table-header,
|
||||
.layui-table-hover,
|
||||
.layui-table-mend,
|
||||
.layui-table-patch,
|
||||
.layui-table-tool,
|
||||
.layui-table-total,
|
||||
.layui-table-total tr {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.hr-line {
|
||||
color: $main-color;
|
||||
border-color: $less-main-color;
|
||||
background-color: $main-color;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn {
|
||||
background-color: $black-color;
|
||||
border-top: 1px solid $less-main-color;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn .layui-layer-btn0 {
|
||||
background-color: $main-color;
|
||||
border-color: $less-main-color;
|
||||
color: $main-color !important;
|
||||
clip-path: $box-shape;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn a {
|
||||
@extend .layui-btn
|
||||
}
|
||||
|
||||
.layui-layer-shade {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
.layuimini-menu-left {
|
||||
.layui-nav-tree .layui-nav-item {
|
||||
|
||||
margin: 5px;
|
||||
width: calc(100% - 10px);
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-item {
|
||||
clip-path: $box-shape;
|
||||
color: $main-color;
|
||||
background-color: $active-color;
|
||||
|
||||
&.layui-this a {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color !important;
|
||||
}
|
||||
|
||||
&.layui-this {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color !important;
|
||||
|
||||
span {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color !important;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-item a:hover {
|
||||
background-color: $active-color !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav .layui-nav-item a,
|
||||
.layuimini-menu-left-zoom.layui-nav .layui-nav-item a {
|
||||
color: $main-color !important;
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-item a span {
|
||||
color: $main-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-item:hover a span {
|
||||
color: $black-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layui-layout-admin .layuimini-logo {
|
||||
background-color: $black-color !important;
|
||||
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-itemed>.layui-nav-child {
|
||||
background-color: $black-color !important;
|
||||
}
|
||||
|
||||
.layuimini-menu-left .layui-nav-tree .layui-this,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-this>a,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this,
|
||||
.layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this a,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-this,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-this>a,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this,
|
||||
.layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this a {
|
||||
background-color: $main-color !important;
|
||||
color: $black-color !important;
|
||||
|
||||
.layui-left-nav {
|
||||
color: $black-color !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layui-iconpicker-icon {
|
||||
border-color: $less-main-color !important;
|
||||
background-color: $less-main-color !important;
|
||||
}
|
||||
|
||||
.layui-iconpicker .layui-anim {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-iconpicker .layui-iconpicker-list {
|
||||
background-color: $black-color;
|
||||
}
|
||||
|
||||
.layui-header .layui-nav .layui-nav-child dd.layui-this a,
|
||||
.layui-header .layui-nav-child dd.layui-this,
|
||||
.layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child .layui-this a {
|
||||
background-color: $active-color !important;
|
||||
}
|
||||
288
public/static/admin/css/themes/_win7.scss
Normal file
288
public/static/admin/css/themes/_win7.scss
Normal file
@@ -0,0 +1,288 @@
|
||||
& {
|
||||
color: #222;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.layui-btn {
|
||||
background: linear-gradient(180deg, #eee 45%, #ddd 0, #bbb);
|
||||
border: 1.5px solid #888;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 1px hsla(0, 0%, 100%, .8), inset 0 1px 1px #fff;
|
||||
box-sizing: border-box;
|
||||
color: #222;
|
||||
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(180deg, #e5f4fd 45%, #b3e0f9 0);
|
||||
border-color: #72a2c5;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn a {
|
||||
@extend .layui-btn;
|
||||
color: #222 !important;
|
||||
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.layui-layer-title {
|
||||
background: linear-gradient(90deg, hsla(0, 0%, 100%, .4), rgba(0, 0, 0, .1), hsla(0, 0%, 100%, .2)), linear-gradient(55deg, transparent, rgba(0, 0, 0, .1) 20%, rgba(0, 0, 0, .1) 50%, transparent 53%), #4580c4 !important;
|
||||
border: 1px solid rgba(0, 0, 0, .6);
|
||||
border-radius: 6px 6px 0 0;
|
||||
// box-shadow : inset 0 0 .5px .5px #fff;
|
||||
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
|
||||
color: #000 !important;
|
||||
letter-spacing: 0;
|
||||
font-size: 12px;
|
||||
text-shadow: 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff;
|
||||
|
||||
padding: 0 80px 0 8px;
|
||||
|
||||
border: 0;
|
||||
box-shadow: inset 0 .5px #fff;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-title~.layui-layer-setwin {
|
||||
height: 27px !important;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-title~.layui-layer-setwin>span {
|
||||
height: 20px !important;
|
||||
line-height: 20px !important;
|
||||
|
||||
background: linear-gradient(hsla(0, 0%, 100%, .3), hsla(0, 0%, 100%, .3) 45%, rgba(0, 0, 0, .1) 50%, rgba(0, 0, 0, .1) 75%, hsla(0, 0%, 100%, .5)) !important;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
border-bottom-right-radius: 0px;
|
||||
border-right: 1px solid rgba(0, 0, 0, .6);
|
||||
box-shadow: inset 0 0 0 .5px #eee;
|
||||
box-sizing: border-box;
|
||||
|
||||
padding: 0;
|
||||
position: relative;
|
||||
|
||||
margin-left: 0;
|
||||
|
||||
min-width: 26px;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
background: radial-gradient(circle at 50% 100%, #2aceda, transparent 60%), linear-gradient(#a9d2e8 50%, #196c9b 0) !important;
|
||||
}
|
||||
|
||||
|
||||
&:last-child {
|
||||
border: 0;
|
||||
border-bottom-right-radius: 5px;
|
||||
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
&.layui-layer-close1 {
|
||||
background-color: #d04a37 !important;
|
||||
min-width: 45px !important;
|
||||
|
||||
|
||||
&:hover {
|
||||
filter: contrast(1.3);
|
||||
background-image: linear-gradient(hsla(0, 0%, 100%, .3), hsla(0, 0%, 100%, .3) 45%, rgba(0, 0, 0, .1) 50%, rgba(0, 0, 0, .1) 75%, hsla(0, 0%, 100%, .5)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layui-layer-dialog {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.layui-layer-iframe {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.layui-layer:not(.layui-layer-loading) {
|
||||
|
||||
.layui-layer-content {
|
||||
background: #f0f0f0;
|
||||
border: 1px solid rgba(0, 0, 0, .6);
|
||||
box-shadow: 0 -1px 1px .5px #fff;
|
||||
margin: 0 6px 0 6px;
|
||||
padding: 6px;
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background: linear-gradient(transparent 20%, hsla(0, 0%, 100%, .7) 40%, transparent 41%), linear-gradient(90deg, hsla(0, 0%, 100%, .4), rgba(0, 0, 0, .1), hsla(0, 0%, 100%, .2)), linear-gradient(55deg, transparent, rgba(0, 0, 0, .1) 20%, rgba(0, 0, 0, .1) 50%, transparent 53%), #4580c4;
|
||||
border-radius: 6px;
|
||||
content: "";
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: -1;
|
||||
|
||||
}
|
||||
|
||||
&.layui-layer-iframe {
|
||||
|
||||
&::before {
|
||||
height: calc(100% + 20px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-btn {
|
||||
background: #f0f0f0;
|
||||
border: 1px solid rgba(0, 0, 0, .6);
|
||||
box-shadow: 0 0 1px .5px #fff;
|
||||
margin: 0 6px 6px;
|
||||
padding: 6px;
|
||||
border-top: 0;
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
.layui-card {
|
||||
|
||||
border: 1px solid rgba(0, 0, 0, .6);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 0 5px 1px rgba(0, 0, 0, .6);
|
||||
font: 9pt Segoe UI, sans-serif;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
|
||||
&::before {
|
||||
background: linear-gradient(transparent 20%, hsla(0, 0%, 100%, .7) 40%, transparent 41%), linear-gradient(90deg, hsla(0, 0%, 100%, .4), rgba(0, 0, 0, .1), hsla(0, 0%, 100%, .2)), linear-gradient(55deg, transparent, rgba(0, 0, 0, .1) 20%, rgba(0, 0, 0, .1) 50%, transparent 53%), #4580c4;
|
||||
border-radius: 6px;
|
||||
content: "";
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
|
||||
.layui-card-header {
|
||||
align-items: center;
|
||||
background: linear-gradient(90deg, hsla(0, 0%, 100%, .4), rgba(0, 0, 0, .1), hsla(0, 0%, 100%, .2)), linear-gradient(55deg, transparent, rgba(0, 0, 0, .1) 20%, rgba(0, 0, 0, .1) 50%, transparent 53%), #4580c4;
|
||||
border-radius: 6px 6px 0 0;
|
||||
font: 9pt Segoe UI, sans-serif;
|
||||
justify-content: space-between;
|
||||
padding: 6px;
|
||||
border: 0;
|
||||
box-shadow: inset 0 .5px #fff;
|
||||
height: 15px;
|
||||
|
||||
color: #000;
|
||||
letter-spacing: 0;
|
||||
line-height: 15px;
|
||||
text-shadow: 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff, 0 0 10px #fff;
|
||||
|
||||
}
|
||||
|
||||
.layui-card-body {
|
||||
background: #f0f0f0;
|
||||
border: 1px solid rgba(0, 0, 0, .6);
|
||||
box-shadow: 0 0 1px .5px #fff;
|
||||
margin: 0 6px 6px;
|
||||
padding: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.layui-tab-brief>.layui-tab-title .layui-this {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.layuimini-tab .layui-tab-control>li {
|
||||
height: 27px !important;
|
||||
line-height: 27px !important;
|
||||
}
|
||||
|
||||
.layui-form-checkbox[lay-skin="primary"] i {
|
||||
background: #ddd;
|
||||
border: 1px solid #888;
|
||||
box-shadow: inset 0 0 0 1.5px #eee, inset 0 2px 4px #888, inset -2px -3px 4px #fff;
|
||||
box-sizing: border-box;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 13px;
|
||||
margin-right: 6px;
|
||||
width: 13px;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.layui-form-checked[lay-skin="primary"] i {
|
||||
color: #16638f;
|
||||
border-color: #888;
|
||||
display: block;
|
||||
font-weight: 700;
|
||||
position: absolute;
|
||||
|
||||
&::before {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layui-form-radio:hover *,
|
||||
.layui-form-radioed,
|
||||
.layui-form-radioed>i {
|
||||
color: #16638f;
|
||||
}
|
||||
|
||||
.layui-input {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-top-color: rgb(204, 204, 204);
|
||||
border-radius: 2px;
|
||||
border-top-color: #888;
|
||||
box-sizing: border-box;
|
||||
font: 9pt Segoe UI, sans-serif;
|
||||
padding: 3px 4px 5px;
|
||||
}
|
||||
|
||||
.layui-input,
|
||||
.layui-select,
|
||||
.layui-textarea {
|
||||
height: unset
|
||||
}
|
||||
|
||||
.layui-form-label {
|
||||
padding: 3px 15px;
|
||||
font: 9pt Segoe UI, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
.layuimini-form>.layui-form-item .required::after {
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.form-search .layui-input-inline input,
|
||||
.form-search .layui-input-inline select {
|
||||
height: unset;
|
||||
line-height: unset;
|
||||
}
|
||||
|
||||
.form-search .layui-form-label {
|
||||
height: unset;
|
||||
background: unset;
|
||||
text-align: right;
|
||||
border: unset;
|
||||
}
|
||||
|
||||
.layuimini-upload-btn {
|
||||
.layui-btn {
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user