27 Commits

Author SHA1 Message Date
wolfcode
88bc6441e5 Update README.md 2025-01-01 11:37:24 +08:00
wolfcode
0efb70b3b7 build: update minimum PHP version to8.1
- Update composer.json to require PHP >= 8.1.0
- Add log entry for PHP version update in log.md

Signed-off-by: wolfcode <37436228+wolf-leo@users.noreply.github.com>
2025-01-01 11:31:43 +08:00
wolfcode
c22be8ac76 Merge pull request #17 from 1rmb/main
隐藏搜索框提示
2024-12-31 11:06:00 +08:00
淘青松
ebce7f3b0e 隐藏搜索框提示
将注释属性添加到table标签上即可
2024-12-31 10:56:13 +08:00
wolfcode
f8b6d847d5 fix(admin): 阿里云对象存储签名版本 V4, upgrade OSS SDK and implement signature version 4
- Upgrade aliyuncs/oss-sdk-php to v2.7.2 or above
- Implement signature version 4 for OSS client
- Add region and environment variable credentials provider
- Update error handling and code formatting
2024-12-27 11:25:02 +08:00
wolfcode
55a9b13e69 refactor(curd): optimize relation binding and code generation
- Move relation binding logic from model constructor to controller
- Generate controller code for binding select fields-Remove unnecessary code and templates
- Improve code readability and maintainability
2024-12-20 17:09:04 +08:00
wolfcode
5d58248cf4 feat(curd): add relation data binding and optimize model construction
- Add relation data binding in model construction
- Update model template to include new relation construction logic
- Remove unused index method template
2024-12-20 16:26:56 +08:00
wolfcode
bbd0320a35 Update README.md 2024-12-19 10:40:01 +08:00
wolfcode
d62a67aafe refactor(admin): use param instead of post to get request parameters
- In both Admin and Menu controllers, change $request->post('id') to $request->param('id')
- This change improves code consistency and allows for more flexible parameter retrieval
2024-12-17 11:22:01 +08:00
wolfcode
c6cc9d4164 feat(common): add support for absolute URLs in __url function
- Implement a check for absolute URLs using filter_var with FILTER_VALIDATE_URL
- If the provided URL is an absolute URL, it is returned as is
- This enhancement allows the __url function to handle both relative and absolute URLs
2024-12-16 13:51:27 +08:00
wolfcode
add8c5144c fix(easymde): update font-awesome css link
- Replace external font-awesome link with local static resource
- Update font-awesome CSS path to local version
2024-12-13 10:44:24 +08:00
wolfcode
62f591045e refactor(admin): enhance delete method to support custom primary keys
- Update delete method in Curd trait to accept Request parameter
- Add support for deleting multiple records using 'id' parameter
- Improve error handling for non-existent data
2024-12-11 17:00:34 +08:00
wolfcode
7470790657 refactor(admin): optimize system log middleware
- Adjust class name construction logic in SystemLog middleware
- Simplify condition for checking controller and action existence
2024-12-09 13:55:24 +08:00
wolfcode
11fa69afaf Merge pull request #13 from Rodots/main
路由配置新增操作方法的参数绑定方式
2024-12-02 16:04:23 +08:00
Rodots
8983705ce4 feat: Parameter Binding Method of New Operation Method for Routing Configuration 2024-12-02 16:01:49 +08:00
wolfcode
95ccd4071b feat(easy-admin): add support for custom template functions in operat column-Implement the ability to use custom template functions in the operat column of easy-admin tables
- Add a new button in the goods list page to demonstrate the usage of custom templates
2024-12-02 11:03:26 +08:00
wolfcode
09f3ea7e54 feat(search): add date type search support
- Implement search functionality for date type fields
- Add new case for 'date' in the search HTML generation logic
- Include date-specific input field with appropriate attributes
2024-11-29 18:50:02 +08:00
wolfcode
9cadb27c9e 🚀Layui v2.9.20 2024-11-29 16:38:46 +08:00
wolfcode
2772034a93 fix(admin): add type attribute to login button
- Add 'type="button"' attribute to the login button in admin login page
- This change prevents the button from being submitted as a form Reset button
2024-11-28 18:19:12 +08:00
wolfcode
08ea79033c feat(admin): add ignoreNode property to skip unnecessary node generation
- Add $ignoreNode property to Goods controller to specify methods to ignore
- Update Node service to check and skip ignored methods during node generation
- This change helps to filter out unnecessary nodes, improving system performance and readability
2024-11-28 10:54:15 +08:00
wolfcode
e7f09d9c68 refactor(install):使用PDO初始化安装 use PDO instead of mysqli for database operations
- Replace mysqli with PDO for database connection and queries
- Create a separate method for generating PDO DSN
- Update error handling to use PDOException
- Remove unnecessary mysqli_set_charset and mysqli_select_db calls
2024-11-27 12:33:04 +08:00
wolfcode
e2effb762c build(deps): update dependency wolfcode/authenticator to v0.0.6
- Updated wolfcode/authenticator from version 0.0.5 to 0.0.6 in composer.json
2024-11-22 16:59:07 +08:00
wolfcode
0e18825808 fix(authenticator): update dependency and adjust QR code generation
- Update wolfcode/authenticator from 0.0.3 to 0.0.5
- Modify QR code generation method in Index controller
2024-11-22 16:51:36 +08:00
wolfcode
c031b09422 build(deps): update topthink/think-multi-app to ^1.1.0
- Replace dev-master with stable version ^1.1.0 for topthink/think-multi-app- This change ensures compatibility and stability in dependency management
2024-11-22 15:16:44 +08:00
wolfcode
231fd48e2f build(deps): update topthink/think-multi-app to dev-master
- Change the version of topthink/think-multi-app from ^1.0 to dev-master in composer.json
2024-11-22 09:32:06 +08:00
wolfcode
53772badd4 Merge pull request #12 from Rodots/main
fix: 修正命名空间,移除无用类的引用
2024-11-14 16:45:09 +08:00
Rodots
34354837d5 fix: 修正命名空间,移除无用类的引用 2024-11-06 14:51:15 +08:00
30 changed files with 147 additions and 137 deletions

View File

@@ -1,27 +1,31 @@
<div align="center" dir="auto"> <div align="center" dir="auto">
<img alt="log" src="/public/static/common/images/logo-8.png" /> <img alt="log" src="/public/static/common/images/logo-8.png" />
<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> <p>
<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> <img src="https://img.shields.io/badge/php-%3E=8.1.0-brightgreen.svg?style=for-the-badge&logo=php&colorB=ff69b4" alt="php">
<span><img src="https://img.shields.io/badge/thinkphp-%3E=8.0.0-brightgreen.svg?style=for-the-badge&logo=thinkphp" alt="ThinkPHP"></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><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> <img src="https://img.shields.io/badge/thinkphp-%3E=8.0.0-brightgreen.svg?style=for-the-badge&logo=thinkphp" alt="ThinkPHP">
<span><img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge&logo=license&colorB=purple" alt="License"></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">
<img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge&logo=license&colorB=purple" alt="License">
</p>
</div> </div>
## `EasyAdmin8`所有版本 (当前项目为`ThinkPHP`版本) ## `EasyAdmin8`所有版本 (当前项目为`ThinkPHP`版本)
| | Github | Gitee | | | Github | Gitee |
|----------|:--------------------------------------------------------------------:|:-----------------------------------------------------------------:| |----------|:----------------------------------------------------------------------:|:---------------------------------------------------------------------:|
| ThinkPHP | [EasyAdmin8](https://github.com/wolf-leo/EasyAdmin8) | [EasyAdmin8](https://gitee.com/wolf18/EasyAdmin8) | | ThinkPHP | [EasyAdmin8](https://github.com/EasyAdmin8/EasyAdmin8) | [EasyAdmin8](https://gitee.com/EasyAdmin8/EasyAdmin8) |
| Laravel | [EasyAdmin8-Laravel](https://github.com/wolf-leo/EasyAdmin8-Laravel) | [EasyAdmin8-Laravel](https://gitee.com/wolf18/EasyAdmin8-Laravel) | | Laravel | [EasyAdmin8-Laravel](https://github.com/EasyAdmin8/EasyAdmin8-Laravel) | [EasyAdmin8-Laravel](https://gitee.com/EasyAdmin8/EasyAdmin8-Laravel) |
| webman | [EasyAdmin8-webman](https://github.com/wolf-leo/EasyAdmin8-webman) | [EasyAdmin8-webman](https://gitee.com/wolf18/EasyAdmin8-webman) | | 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.0+ PHP 最低版本要求不低于 8.1
>
> 2025年起 `PHP` 版本要求提升到 `8.1+`, 如果需要 `8.0` 到分支 `v8.0` 中下载
> >
> ThinkPHP v8.0 和 Layui v2.9.x 的快速开发的后台管理系统。 > ThinkPHP v8.0+ 和 Layui v2.9.x 的快速开发的后台管理系统。
> >
> 项目地址:[http://easyadmin8.top](http://easyadmin8.top) > 项目地址:[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.下载安装包 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 在根目录下 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命令大全](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) * [EasyAdmin](http://easyadmin.99php.cn/docs)

View File

@@ -141,7 +141,7 @@ class Index extends AdminController
$old_secret = $row->ga_secret; $old_secret = $row->ga_secret;
$secret = $ga->createSecret(32); $secret = $ga->createSecret(32);
$ga_title = $this->isDemo ? 'EasyAdmin8演示环境' : '可自定义修改显示标题'; $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')); $this->assign(compact('row', 'dataUri', 'old_secret', 'secret'));
return $this->fetch(); return $this->fetch();
} }

View File

@@ -20,6 +20,12 @@ use think\response\Json;
class Goods extends AdminController class Goods extends AdminController
{ {
/**
* 过滤不需要生成的权限节点 默认 CURD 中会自动生成部分节点 可以在此处过滤
* @var array[]
*/
protected array $ignoreNode = ['export'];
public function __construct(App $app) public function __construct(App $app)
{ {
parent::__construct($app); parent::__construct($app);

View File

@@ -150,9 +150,10 @@ class Admin extends AdminController
/** /**
* @NodeAnnotation(title="删除") * @NodeAnnotation(title="删除")
*/ */
public function delete($id): void public function delete(Request $request): void
{ {
$this->checkPostRequest(); $this->checkPostRequest();
$id = $request->param('id');
$row = $this->model->whereIn('id', $id)->select(); $row = $this->model->whereIn('id', $id)->select();
$row->isEmpty() && $this->error('数据不存在'); $row->isEmpty() && $this->error('数据不存在');
$id == AdminConstant::SUPER_ADMIN_ID && $this->error('超级管理员不允许修改'); $id == AdminConstant::SUPER_ADMIN_ID && $this->error('超级管理员不允许修改');

View File

@@ -132,9 +132,10 @@ class Menu extends AdminController
/** /**
* @NodeAnnotation(title="删除") * @NodeAnnotation(title="删除")
*/ */
public function delete($id): void public function delete(Request $request): void
{ {
$this->checkPostRequest(); $this->checkPostRequest();
$id = $request->param('id');
$row = $this->model->whereIn('id', $id)->select(); $row = $this->model->whereIn('id', $id)->select();
empty($row) && $this->error('数据不存在'); empty($row) && $this->error('数据不存在');
try { try {

View File

@@ -56,8 +56,8 @@ class SystemLog
$pathInfoExp = explode('.', $pathInfoExp[0] ?? ''); $pathInfoExp = explode('.', $pathInfoExp[0] ?? '');
$_name = $pathInfoExp[0] ?? ''; $_name = $pathInfoExp[0] ?? '';
$_controller = ucfirst($pathInfoExp[1] ?? ''); $_controller = ucfirst($pathInfoExp[1] ?? '');
if ($_name && $_controller && $_action) { $className = $_controller ? "app\admin\controller\\{$_name}\\{$_controller}" : "app\admin\controller\\{$_name}";
$className = "app\admin\controller\\{$_name}\\{$_controller}"; if ($_name && $_action) {
$reflectionClass = new \ReflectionClass($className); $reflectionClass = new \ReflectionClass($className);
$properties = $reflectionClass->getDefaultProperties(); $properties = $reflectionClass->getDefaultProperties();
$ignoreLog = $properties['ignoreLog'] ?? []; $ignoreLog = $properties['ignoreLog'] ?? [];

View File

@@ -4,6 +4,7 @@ namespace app\admin\service;
use app\admin\model\SystemUploadfile; use app\admin\model\SystemUploadfile;
use OSS\Core\OssException; use OSS\Core\OssException;
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient; use OSS\OssClient;
use think\facade\Env; use think\facade\Env;
use think\file\UploadedFile; use think\file\UploadedFile;
@@ -112,10 +113,21 @@ class UploadService
$accessKeySecret = $config['oss_access_key_secret']; $accessKeySecret = $config['oss_access_key_secret'];
$endpoint = $config['oss_endpoint']; $endpoint = $config['oss_endpoint'];
$bucket = $config['oss_bucket']; $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()) { if ($file->isValid()) {
$object = $this->setFilePath($file, Env::get('EASYADMIN.OSS_STATIC_PREFIX', 'easyadmin8') . '/'); $object = $this->setFilePath($file, Env::get('EASYADMIN.OSS_STATIC_PREFIX', 'easyadmin8') . '/');
try { try {
$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint); $ossClient = new OssClient($args);
$_rs = $ossClient->putObject($bucket, $object, file_get_contents($file->getRealPath())); $_rs = $ossClient->putObject($bucket, $object, file_get_contents($file->getRealPath()));
$oss_request_url = $_rs['oss-request-url'] ?? ''; $oss_request_url = $_rs['oss-request-url'] ?? '';
if (empty($oss_request_url)) return ['code' => 0, 'data' => '上传至OSS失败']; if (empty($oss_request_url)) return ['code' => 0, 'data' => '上传至OSS失败'];
@@ -164,7 +176,7 @@ class UploadService
if (empty($location)) return ['code' => 0, 'data' => '上传至COS失败']; if (empty($location)) return ['code' => 0, 'data' => '上传至COS失败'];
$location = 'https://' . $location; $location = 'https://' . $location;
$this->setSaveData($file); $this->setSaveData($file);
} catch (Exception $e) { }catch (Exception $e) {
return ['code' => 0, 'data' => $e->getMessage()]; return ['code' => 0, 'data' => $e->getMessage()];
} }
$data = ['url' => $location]; $data = ['url' => $location];

View File

@@ -67,6 +67,12 @@ class Node
// 遍历读取所有方法的注释的参数信息 // 遍历读取所有方法的注释的参数信息
foreach ($methods as $method) { foreach ($methods as $method) {
// 忽略的节点
$properties = $reflectionClass->getDefaultProperties();
$ignoreNode = $properties['ignoreNode'] ?? [];
if (!empty($ignoreNode)) if (in_array($method->name, $ignoreNode)) continue;
// 读取NodeAnnotation的注解 // 读取NodeAnnotation的注解
$nodeAnnotation = $reader->getMethodAnnotation($method, NodeAnnotation::class); $nodeAnnotation = $reader->getMethodAnnotation($method, NodeAnnotation::class);
if (!empty($nodeAnnotation)) { if (!empty($nodeAnnotation)) {

View File

@@ -392,7 +392,7 @@ class BuildCurd
if (!empty($bindSelectField)) { if (!empty($bindSelectField)) {
$relationArray = explode('\\', $modelFilename); $relationArray = explode('\\', $modelFilename);
$this->tableColumns[$foreignKey]['bindSelectField'] = $bindSelectField; $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->relationArray[$relationTable] = $relation;
$this->selectFields[] = $foreignKey; $this->selectFields[] = $foreignKey;
@@ -1027,7 +1027,8 @@ class BuildCurd
*/ */
protected function renderController(): static 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)) { if (empty($this->relationArray)) {
$controllerIndexMethod = ''; $controllerIndexMethod = '';
}else { }else {
@@ -1035,6 +1036,9 @@ class BuildCurd
foreach ($this->relationArray as $key => $val) { foreach ($this->relationArray as $key => $val) {
$relation = CommonTool::lineToHump($key); $relation = CommonTool::lineToHump($key);
$relationCode = "->withJoin('{$relation}', 'LEFT')\r"; $relationCode = "->withJoin('{$relation}', 'LEFT')\r";
if (!empty($val['bindSelectField']) && !empty($val['primaryKey'])) {
$constructRelation = '$notes["' . lcfirst($val['modelFilename']) . ucfirst($val['bindSelectField']) . '"] = \app\admin\model\\' . $val['modelFilename'] . '::column("' . $val['bindSelectField'] . '", "' . $val['primaryKey'] . '");';
}
} }
$controllerIndexMethod = CommonTool::replaceTemplate( $controllerIndexMethod = CommonTool::replaceTemplate(
$this->getTemplate("controller{$this->DS}indexMethod"), $this->getTemplate("controller{$this->DS}indexMethod"),
@@ -1066,6 +1070,7 @@ class BuildCurd
'modelFilename' => "\app\admin\model\\{$modelFilenameExtend}", 'modelFilename' => "\app\admin\model\\{$modelFilenameExtend}",
'indexMethod' => $controllerIndexMethod, 'indexMethod' => $controllerIndexMethod,
'selectList' => $selectList, 'selectList' => $selectList,
'constructRelation' => $constructRelation,
]); ]);
$this->fileList[$controllerFile] = $controllerValue; $this->fileList[$controllerFile] = $controllerValue;
return $this; return $this;
@@ -1082,16 +1087,16 @@ class BuildCurd
$relationList = ''; $relationList = '';
if (!empty($this->relationArray)) { if (!empty($this->relationArray)) {
foreach ($this->relationArray as $key => $val) { foreach ($this->relationArray as $key => $val) {
$relation = CommonTool::lineToHump($key); $relation = CommonTool::lineToHump($key);
$relationCode = CommonTool::replaceTemplate( // $relationCode = CommonTool::replaceTemplate(
$this->getTemplate("model{$this->DS}relation"), // $this->getTemplate("model{$this->DS}relation"),
[ // [
'relationMethod' => $relation, // 'relationMethod' => $relation,
'relationModel' => "\app\admin\model\\{$val['modelFilename']}", // 'relationModel' => "\app\admin\model\\{$val['modelFilename']}",
'foreignKey' => $val['foreignKey'], // 'foreignKey' => $val['foreignKey'],
'primaryKey' => $val['primaryKey'], // 'primaryKey' => $val['primaryKey'],
]); // ]);
$relationList .= $relationCode; // $relationList .= $relationCode;
} }
} }
@@ -1126,6 +1131,7 @@ class BuildCurd
'selectArrays' => CommonTool::replaceArrayString(var_export($selectArrays, true)), 'selectArrays' => CommonTool::replaceArrayString(var_export($selectArrays, true)),
]); ]);
$this->fileList[$modelFile] = $modelValue; $this->fileList[$modelFile] = $modelValue;
// 关联模型 // 关联模型
@@ -1153,10 +1159,12 @@ class BuildCurd
[ [
'modelName' => $val['modelName'], 'modelName' => $val['modelName'],
'modelNamespace' => "app\admin\model{$extendNamespace}", 'modelNamespace' => "app\admin\model{$extendNamespace}",
'prefix_table' => $this->tablePrefix == config('database.connections.mysql.prefix') ? "" : $this->tablePrefix . $this->table,
'table' => $key, 'table' => $key,
'deleteTime' => $val['delete'] ? '"delete_time"' : 'false', 'deleteTime' => $val['delete'] ? '"delete_time"' : 'false',
'relationList' => '', 'relationList' => '',
'selectList' => '', 'selectList' => '',
'selectArrays' => "[]",
]); ]);
$this->fileList[$relationModelFile] = $relationModelValue; $this->fileList[$relationModelFile] = $relationModelValue;
} }
@@ -1302,7 +1310,6 @@ class BuildCurd
$templateFile = "view{$this->DS}module{$this->DS}textarea"; $templateFile = "view{$this->DS}module{$this->DS}textarea";
$value = '{$row.' . $field . '|raw|default=\'\'}'; $value = '{$row.' . $field . '|raw|default=\'\'}';
} }
$editFormList .= CommonTool::replaceTemplate( $editFormList .= CommonTool::replaceTemplate(
$this->getTemplate($templateFile), $this->getTemplate($templateFile),
[ [

View File

@@ -1,8 +1,8 @@
<?php <?php
declare(strict_types = 1);
namespace EasyAdmin\curd\exceptions; namespace app\admin\service\curd\exceptions;
class CurdException extends \Exception class CurdException extends \Exception
{ {
} }

View File

@@ -1,8 +1,8 @@
<?php <?php
declare(strict_types = 1);
namespace EasyAdmin\curd\exceptions; namespace app\admin\service\curd\exceptions;
class FileException extends \Exception class FileException extends \Exception
{ {
} }

View File

@@ -1,8 +1,8 @@
<?php <?php
declare(strict_types = 1);
namespace app\admin\service\curd\exceptions; namespace app\admin\service\curd\exceptions;
class TableException extends \Exception class TableException extends \Exception
{ {
} }

View File

@@ -20,6 +20,7 @@ class {{controllerName}} extends AdminController
parent::__construct($app); parent::__construct($app);
$this->model = new {{modelFilename}}(); $this->model = new {{modelFilename}}();
$this->notes = $notes = $this->model->notes; $this->notes = $notes = $this->model->notes;
{{constructRelation}}
$this->assign(compact('notes')); $this->assign(compact('notes'));
} }

View File

@@ -1,23 +0,0 @@
/**
* @NodeAnnotation(title="列表")
*/
public function index()
{
if ($this->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 = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}

View File

@@ -5,6 +5,7 @@
data-auth-edit="{:auth('{{controllerUrl}}/edit')}" data-auth-edit="{:auth('{{controllerUrl}}/edit')}"
data-auth-delete="{:auth('{{controllerUrl}}/delete')}" data-auth-delete="{:auth('{{controllerUrl}}/delete')}"
lay-filter="currentTable"> lay-filter="currentTable">
<!-- searchTableShow="false" 隐藏搜索框 -->
</table> </table>
</div> </div>
</div> </div>

View File

@@ -88,8 +88,10 @@ trait Curd
/** /**
* @NodeAnnotation(title="删除") * @NodeAnnotation(title="删除")
*/ */
public function delete($id): void public function delete(Request $request): void
{ {
// 如果不是id作为主键 请在对应的控制器中覆盖重写
$id = $request->param('id', []);
$this->checkPostRequest(); $this->checkPostRequest();
$row = $this->model->whereIn('id', $id)->select(); $row = $this->model->whereIn('id', $id)->select();
$row->isEmpty() && $this->error('数据不存在'); $row->isEmpty() && $this->error('数据不存在');

View File

@@ -41,7 +41,7 @@
<a href="javascript:" class="forget-password">忘记密码?</a> <a href="javascript:" class="forget-password">忘记密码?</a>
</div> </div>
<div class="layui-form-item" style="text-align:center; width:100%;height:100%;margin:0px;"> <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> </div>
</form> </form>
</div> </div>

View File

@@ -19,6 +19,7 @@ if (!function_exists('__url')) {
*/ */
function __url(string $url = '', array $vars = [], bool $suffix = true, bool $domain = false): string 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(); return url($url, $vars, $suffix, $domain)->build();
} }
} }

View File

@@ -168,6 +168,12 @@ class Curd extends Command
} }
} }
} }
if (PHP_SAPI == 'cli') {
$output->info(">>>>>>>>>>>>>>>");
$output->info('执行成功');
}else {
$output->writeln('执行成功');
}
}catch (\Exception $e) { }catch (\Exception $e) {
if (PHP_SAPI == 'cli') if (PHP_SAPI == 'cli')
CliEcho::error($e->getMessage()); CliEcho::error($e->getMessage());

View File

@@ -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'));
}
}

View File

@@ -3,7 +3,6 @@
namespace app\common\service; namespace app\common\service;
use app\common\constants\AdminConstant; use app\common\constants\AdminConstant;
use EasyAdmin\tool\CommonTool;
use think\facade\Db; use think\facade\Db;
/** /**

View File

@@ -91,12 +91,11 @@ class Install extends BaseController
$installPath = config_path() . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR; $installPath = config_path() . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR;
$sqlPath = file_get_contents($installPath . 'sql' . DIRECTORY_SEPARATOR . 'install.sql'); $sqlPath = file_get_contents($installPath . 'sql' . DIRECTORY_SEPARATOR . 'install.sql');
$sqlArray = $this->parseSql($sqlPath, $config['prefix'], 'ea_'); $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 { try {
mysqli_set_charset($conn, $config['charset']); $pdo = new \PDO($dsn, $config['username'] ?? 'root', $config['password'] ?? '');
mysqli_select_db($conn, $config['database']);
foreach ($sqlArray as $sql) { foreach ($sqlArray as $sql) {
mysqli_query($conn, $sql); $pdo->query($sql);
} }
$_password = password($password); $_password = password($password);
$tableName = 'system_admin'; $tableName = 'system_admin';
@@ -108,9 +107,8 @@ class Install extends BaseController
'update_time' => time() 'update_time' => time()
]; ];
foreach ($update as $_k => $_up) { 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) && @mkdir($installPath);
!is_dir($installPath . 'lock' . DIRECTORY_SEPARATOR) && @mkdir($installPath . 'lock' . DIRECTORY_SEPARATOR); !is_dir($installPath . 'lock' . DIRECTORY_SEPARATOR) && @mkdir($installPath . 'lock' . DIRECTORY_SEPARATOR);
@@ -161,11 +159,11 @@ class Install extends BaseController
protected function createDatabase($database, $config): bool protected function createDatabase($database, $config): bool
{ {
$dsn = $this->pdoDsn($config);
try { try {
$con = mysqli_connect($config['host'] ?? '127.0.0.1', $config['username'] ?? 'root', $config['password'] ?? '', null, $config['port'] ?? ''); $pdo = new \PDO($dsn, $config['username'] ?? 'root', $config['password'] ?? '');
mysqli_query($con, "CREATE DATABASE IF NOT EXISTS `{$database}` DEFAULT CHARACTER SET {$config['charset']} COLLATE=utf8mb4_general_ci"); $pdo->query("CREATE DATABASE IF NOT EXISTS `{$database}` DEFAULT CHARACTER SET {$config['charset']} COLLATE=utf8mb4_general_ci");
mysqli_close($con); }catch (\PDOException $e) {
}catch (\Throwable $e) {
return false; return false;
} }
return true; return true;
@@ -187,19 +185,32 @@ class Install extends BaseController
protected function checkConnect(array $config): ?bool protected function checkConnect(array $config): ?bool
{ {
$dsn = $this->pdoDsn($config);
try { try {
$con = mysqli_connect($config['host'] ?? '127.0.0.1', $config['username'] ?? 'root', $config['password'] ?? '', null, $config['port'] ?? ''); $pdo = new \PDO($dsn, $config['username'] ?? 'root', $config['password'] ?? '');
$res = mysqli_query($con, 'select VERSION()'); $res = $pdo->query('select VERSION()');
$mysqlVersion = mysqli_fetch_row($res); $_version = $res->fetch()[0] ?? 0;
mysqli_close($con);
$_version = $mysqlVersion[0] ?? 0;
if (version_compare($_version, '5.7.0', '<')) { if (version_compare($_version, '5.7.0', '<')) {
$this->error('mysql版本最低要求 5.7.x'); $this->error('mysql版本最低要求 5.7.x');
} }
}catch (\mysqli_sql_exception $e) { }catch (\PDOException $e) {
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
return true; 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";
}
} }

View File

@@ -20,10 +20,10 @@
} }
], ],
"require": { "require": {
"php": ">=8.0.0", "php": ">=8.1.0",
"topthink/framework": "^8.0", "topthink/framework": "^8.0",
"topthink/think-orm": "^3.0", "topthink/think-orm": "^3.0",
"topthink/think-multi-app": "^1.0", "topthink/think-multi-app": "^1.1.0",
"topthink/think-view": "^2.0", "topthink/think-view": "^2.0",
"topthink/think-captcha": "^3.0", "topthink/think-captcha": "^3.0",
"topthink/think-filesystem": "^2.0", "topthink/think-filesystem": "^2.0",
@@ -38,7 +38,7 @@
"ext-mysqli": "*", "ext-mysqli": "*",
"ext-pdo": "*", "ext-pdo": "*",
"wolf-leo/phplogviewer": "^0.11.3", "wolf-leo/phplogviewer": "^0.11.3",
"wolfcode/authenticator": "^0.0.3" "wolfcode/authenticator": "^0.0.6"
}, },
"require-dev": { "require-dev": {
"symfony/var-dumper": ">=4.2", "symfony/var-dumper": ">=4.2",

View File

@@ -42,4 +42,6 @@ return [
'default_jsonp_handler' => 'jsonpReturn', 'default_jsonp_handler' => 'jsonpReturn',
// 默认JSONP处理方法 // 默认JSONP处理方法
'var_jsonp_handler' => 'callback', 'var_jsonp_handler' => 'callback',
// 操作方法的参数绑定方式 route get param
'action_bind_param' => 'param',
]; ];

1
log.md
View File

@@ -1,2 +1,3 @@
> 2025年01月01日 `PHP` 要求升级到 `8.1+`
> >
> 2024年05月 更新 `EasyAdmin8` 重置版,多处语法、写法进行变更 > 2024年05月 更新 `EasyAdmin8` 重置版,多处语法、写法进行变更

View File

@@ -57,6 +57,10 @@ define(["jquery", "easy-admin"], function ($, ea) {
templet: ea.table.tool, templet: ea.table.tool,
operat: [ operat: [
[{ [{
templet: function (d) {
return `<button type="button" class="layui-btn layui-btn-xs">自定义 ${d.id}</button>`
}
}, {
text: '编辑', text: '编辑',
url: init.edit_url, url: init.edit_url,
method: 'open', method: 'open',

View File

@@ -399,6 +399,15 @@ define(["jquery", "tableSelect"], function ($, tableSelect) {
'</div>\n' + '</div>\n' +
'</div>'; '</div>';
break; break;
case 'date':
d.searchOp = '=';
formHtml += `<div class="layui-form-item layui-inline">
<label class="layui-form-label">${d.title}</label>
<div class="layui-input-inline">
<input data-date data-date-type="date" id="c-${d.fieldAlias}" name="${d.fieldAlias}" data-search-op="${d.searchOp}" value="${d.searchValue}" placeholder="${d.searchTip}" class="layui-input">
</div>
</div>`
break;
} }
newCols.push(d); newCols.push(d);
} }
@@ -663,6 +672,12 @@ define(["jquery", "tableSelect"], function ($, tableSelect) {
$.each(item, function (i, operat) { $.each(item, function (i, operat) {
if (typeof operat !== 'object') return if (typeof operat !== 'object') return
if ('function' === typeof operat.templet) {
html += operat.templet(data);
return true;
}
operat.class = operat.class || ''; operat.class = operat.class || '';
operat.icon = operat.icon || ''; operat.icon = operat.icon || '';
operat.auth = operat.auth || ''; operat.auth = operat.auth || '';

View File

@@ -8184,7 +8184,7 @@
if (!1 === e.autoDownloadFontAwesome && (t = !1), !0 !== e.autoDownloadFontAwesome) for (var n = document.styleSheets, i = 0; i < n.length; i++) n[i].href && n[i].href.indexOf("//maxcdn.bootstrapcdn.com/font-awesome/") > -1 && (t = !1); if (!1 === e.autoDownloadFontAwesome && (t = !1), !0 !== e.autoDownloadFontAwesome) for (var n = document.styleSheets, i = 0; i < n.length; i++) n[i].href && n[i].href.indexOf("//maxcdn.bootstrapcdn.com/font-awesome/") > -1 && (t = !1);
if (t) { if (t) {
var r = document.createElement("link"); var r = document.createElement("link");
r.rel = "stylesheet", r.href = "https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css", document.getElementsByTagName("head")[0].appendChild(r) r.rel = "stylesheet", r.href = "/static/plugs/font-awesome-4.7.0/css/font-awesome.min.css", document.getElementsByTagName("head")[0].appendChild(r)
} }
if (e.element) this.element = e.element; else if (null === e.element) return void console.log("EasyMDE: Error. No element was found."); if (e.element) this.element = e.element; else if (null === e.element) return void console.log("EasyMDE: Error. No element was found.");
if (void 0 === e.toolbar) for (var o in e.toolbar = [], te) Object.prototype.hasOwnProperty.call(te, o) && (-1 != o.indexOf("separator-") && e.toolbar.push("|"), (!0 === te[o].default || e.showIcons && e.showIcons.constructor === Array && -1 != e.showIcons.indexOf(o)) && e.toolbar.push(o)); if (void 0 === e.toolbar) for (var o in e.toolbar = [], te) Object.prototype.hasOwnProperty.call(te, o) && (-1 != o.indexOf("separator-") && e.toolbar.push("|"), (!0 === te[o].default || e.showIcons && e.showIcons.constructor === Array && -1 != e.showIcons.indexOf(o)) && e.toolbar.push(o));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long