This commit is contained in:
你的名字
2025-10-15 14:53:54 +08:00
commit ac0f12b21a
864 changed files with 200931 additions and 0 deletions

View File

@ -0,0 +1,20 @@
<?php
namespace app\admin\service;
use think\facade\Cache;
class ConfigService
{
public static function getVersion()
{
$version = cache('site_version');
if (empty($version)) {
$version = sysConfig('site', 'site_version');
cache('site_version', $version);
}
return $version;
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace app\admin\service;
use app\admin\service\auth\Node;
class NodeService
{
/**
* 获取节点服务
* @return array
* @throws \Doctrine\Common\Annotations\AnnotationException
* @throws \ReflectionException
*/
public function getNodeList()
{
$basePath = base_path() . 'admin' . DIRECTORY_SEPARATOR . 'controller';
$baseNamespace = "app\admin\controller";
$nodeList = (new Node($basePath, $baseNamespace))->getNodeList();
return $nodeList;
}
}

View File

@ -0,0 +1,128 @@
<?php
namespace app\admin\service;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Config;
use think\facade\Env;
/**
* 系统日志表
* Class SystemLogService
* @package app\admin\service
*/
class SystemLogService
{
protected static ?SystemLogService $instance = null;
/**
* 表前缀
* @var string
*/
protected string $tablePrefix;
/**
* 表后缀
* @var string
*/
protected string $tableSuffix;
/**
* 表名
* @var string
*/
protected string $tableName;
/**
* 构造方法
* SystemLogService constructor.
*/
protected function __construct()
{
$this->tablePrefix = Config::get('database.connections.mysql.prefix');
$this->tableSuffix = date('Ym', time());
$this->tableName = "{$this->tablePrefix}system_log_{$this->tableSuffix}";
}
/**
* 获取实例对象
* @return SystemLogService
*/
public static function instance(): SystemLogService
{
if (is_null(self::$instance)) {
self::$instance = new static();
}
return self::$instance;
}
/**
* 保存数据
* @param $data
* @return bool|string
*/
public function save($data): bool|string
{
Db::startTrans();
try {
$this->detectTable();
Db::table($this->tableName)->strict(false)->insert($data);
Db::commit();
}catch (\Exception $e) {
Db::rollback();
return $e->getMessage();
}
return true;
}
/**
* 检测数据表
* @return bool
*/
public function detectTable(): bool
{
$_key = "system_log_{$this->tableName}_table";
// 手动删除日志表时候 记得清除缓存
$isset = Cache::get($_key);
if ($isset) return true;
$check = Db::query("show tables like '{$this->tableName}'");
if (empty($check)) {
$sql = $this->getCreateSql();
Db::execute($sql);
}
Cache::set($_key, !empty($check));
return true;
}
public function getAllTableList()
{
}
/**
* 根据后缀获取创建表的sql
* @return string
*/
protected function getCreateSql(): string
{
return <<<EOT
CREATE TABLE `{$this->tableName}` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`admin_id` int(10) unsigned DEFAULT '0' COMMENT '管理员ID',
`url` varchar(1500) NOT NULL DEFAULT '' COMMENT '操作页面',
`method` varchar(50) NOT NULL COMMENT '请求方法',
`title` varchar(100) DEFAULT '' COMMENT '日志标题',
`content` json NOT NULL COMMENT '请求数据',
`response` json DEFAULT NULL COMMENT '回调数据',
`ip` varchar(50) NOT NULL DEFAULT '' COMMENT 'IP',
`useragent` varchar(255) DEFAULT '' COMMENT 'User-Agent',
`create_time` int(10) DEFAULT NULL COMMENT '操作时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='后台操作日志表 - {$this->tableSuffix}';
EOT;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace app\admin\service;
use think\facade\Cache;
class TriggerService
{
/**
* 更新菜单缓存
* @param null $adminId
* @return bool
*/
public static function updateMenu($adminId = null)
{
if(empty($adminId)){
Cache::tag('initAdmin')->clear();
}else{
Cache::delete('initAdmin_' . $adminId);
}
return true;
}
/**
* 更新节点缓存
* @param null $adminId
* @return bool
*/
public static function updateNode($adminId = null)
{
if(empty($adminId)){
Cache::tag('authNode')->clear();
}else{
Cache::delete('allAuthNode_' . $adminId);
}
return true;
}
/**
* 更新系统设置缓存
* @return bool
*/
public static function updateSysConfig(): bool
{
Cache::tag('sysConfig')->clear();
return true;
}
}

View File

@ -0,0 +1,226 @@
<?php
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;
use think\helper\Str;
use Qcloud\Cos\Client;
use Exception;
use Qiniu\Storage\UploadManager;
use Qiniu\Auth;
class UploadService
{
public static ?UploadService $_instance = null;
protected array $options = [];
private array $saveData;
public static function instance(): ?UploadService
{
if (!static::$_instance) static::$_instance = new static();
return static::$_instance;
}
/**
* @param array $options
* @return $this
*/
public function setConfig(array $options = []): UploadService
{
$this->options = $options;
return $this;
}
/**
* @return array
*/
public function getConfig(): array
{
return $this->options;
}
/**
* @param UploadedFile $file
* @param string $base_path
* @return string
*/
protected function setFilePath(UploadedFile $file, string $base_path = ''): string
{
$path = date('Ymd') . '/' . Str::random(3) . time() . Str::random() . '.' . $file->extension();
return $base_path . $path;
}
/**
* @param UploadedFile $file
* @return UploadService
*/
protected function setSaveData(UploadedFile $file): static
{
$options = $this->options;
$data = [
'upload_type' => $options['upload_type'],
'original_name' => $file->getOriginalName(),
'mime_type' => $file->getMime(),
'file_size' => $file->getSize(),
'file_ext' => strtolower($file->extension()),
'create_time' => time(),
];
$this->saveData = $data;
return $this;
}
/**
* 本地存储
*
* @param UploadedFile $file
* @param string $type
* @return array
*/
public function local(UploadedFile $file, string $type = ''): array
{
if ($file->isValid()) {
$base_path = '/storage/' . date('Ymd') . '/';
// 上传文件的目标文件夹
$destinationPath = public_path() . $base_path;
$this->setSaveData($file);
// 将文件移动到目标文件夹中
$move = $file->move($destinationPath, Str::random(3) . time() . Str::random() . session('admin.id') . '.' . $file->extension());
$url = $base_path . $move->getFilename();
$data = ['url' => $url];
$this->save($url);
return ['code' => 1, 'data' => $data];
}
$data = '上传失败';
return ['code' => 0, 'data' => $data];
}
/**
* 阿里云OSS
*
* @param UploadedFile $file
* @param string $type
* @return array
*/
public function oss(UploadedFile $file, string $type = ''): array
{
$config = $this->getConfig();
$accessKeyId = $config['oss_access_key_id'];
$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($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失败'];
$oss_request_url = str_replace('http://', 'https://', $oss_request_url);
$this->setSaveData($file);
} catch (OssException $e) {
return ['code' => 0, 'data' => $e->getMessage()];
}
$data = ['url' => $oss_request_url];
$this->save($oss_request_url);
return ['code' => 1, 'data' => $data];
}
$data = '上传失败';
return ['code' => 0, 'data' => $data];
}
/**
* 腾讯云cos
*
* @param UploadedFile $file
* @param string $type
* @return array
*/
public function cos(UploadedFile $file, string $type = ''): array
{
$config = $this->getConfig();
$secretId = $config['cos_secret_id']; //替换为用户的 secretId请登录访问管理控制台进行查看和管理https://console.cloud.tencent.com/cam/capi
$secretKey = $config['cos_secret_key']; //替换为用户的 secretKey请登录访问管理控制台进行查看和管理https://console.cloud.tencent.com/cam/capi
$region = $config['cos_region']; //替换为用户的 region已创建桶归属的region可以在控制台查看https://console.cloud.tencent.com/cos5/bucket
if ($file->isValid()) {
$cosClient = new Client(
[
'region' => $region,
'schema' => 'http',
'credentials' => ['secretId' => $secretId, 'secretKey' => $secretKey,
],
]);
try {
$object = $this->setFilePath($file, Env::get('EASYADMIN.OSS_STATIC_PREFIX', 'easyadmin8') . '/');
$result = $cosClient->upload(
$config['cos_bucket'], //存储桶名称由BucketName-Appid 组成可以在COS控制台查看 https://console.cloud.tencent.com/cos5/bucket
$object, //此处的 key 为对象键
file_get_contents($file->getRealPath())
);
$location = $result['Location'] ?? '';
if (empty($location)) return ['code' => 0, 'data' => '上传至COS失败'];
$location = 'https://' . $location;
$this->setSaveData($file);
}catch (Exception $e) {
return ['code' => 0, 'data' => $e->getMessage()];
}
$data = ['url' => $location];
$this->save($location);
return ['code' => 1, 'data' => $data];
}
$data = '上传失败';
return ['code' => 0, 'data' => $data];
}
/**
* 七牛云
*
* @param UploadedFile $file
* @param string $type
* @return array
* @throws Exception
*/
public function qnoss(UploadedFile $file, string $type = ''): array
{
if (!$file->isValid()) return ['code' => 1, 'data' => '上传验证失败'];
$uploadMgr = new UploadManager();
$config = $this->getConfig();
$accessKey = $config['qnoss_access_key'];
$secretKey = $config['qnoss_secret_key'];
$bucket = $config['qnoss_bucket'];
$domain = $config['qnoss_domain'];
$auth = new Auth($accessKey, $secretKey);
$token = $auth->uploadToken($bucket);
$object = $this->setFilePath($file, Env::get('EASYADMIN.OSS_STATIC_PREFIX', 'easyadmin8') . '/');
list($ret, $error) = $uploadMgr->putFile($token, $object, $file->getRealPath());
if (empty($ret)) return ['code' => 0, 'data' => $error->getResponse()->error ?? '上传失败,请检查七牛云相关参数配置'];
$url = $domain . "/" . $ret['key'];
$data = ['url' => $url];
$this->setSaveData($file);
$this->save($url);
return ['code' => 1, 'data' => $data];
}
protected function save(string $url = ''): bool
{
$data = $this->saveData;
$data['url'] = $url;
$data['upload_time'] = time();
return (new SystemUploadfile())->save($data);
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace app\admin\service\annotation;
use Attribute;
/**
* controller 节点注解类
*/
#[Attribute]
final class ControllerAnnotation
{
/**
* @param string $title
* @param bool $auth 是否需要权限
* @param string|array $ignore
*/
public function __construct(public string $title = '', public bool $auth = true, public string|array $ignore = '')
{
}
}

View 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 = '')
{
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace app\admin\service\annotation;
use Attribute;
/**
* action 节点注解类
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD| Attribute::TARGET_PROPERTY)]
final class NodeAnnotation
{
/** 过滤节点 */
const IGNORE_NODE = 'NODE';
/**
* @param string $title
* @param bool $auth 是否需要权限
* @param string|array $ignore
*/
public function __construct(public string $title = '', public bool $auth = true, public string|array $ignore = '')
{
}
}

View File

@ -0,0 +1,155 @@
<?php
namespace app\admin\service\auth;
use Doctrine\Common\Annotations\AnnotationException;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\Annotations\DocParser;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\admin\service\tool\CommonTool;
use ReflectionException;
/**
* 节点处理类
* Class Node
* @package EasyAdmin\auth
*/
class Node
{
/**
* @var string 当前文件夹
*/
protected string $basePath;
/**
* @var string 命名空间前缀
*/
protected string $baseNamespace;
/**
* 构造方法
* Node constructor.
* @param string $basePath 读取的文件夹
* @param string $baseNamespace 读取的命名空间前缀
*/
public function __construct(string $basePath, string $baseNamespace)
{
$this->basePath = $basePath;
$this->baseNamespace = $baseNamespace;
return $this;
}
/**
* 获取所有节点
* @return array
* @throws AnnotationException
* @throws ReflectionException
*/
public function getNodeList(): array
{
list($nodeList, $controllerList) = [[], $this->getControllerList()];
if (!empty($controllerList)) {
AnnotationRegistry::loadAnnotationClass('class_exists');
$parser = new DocParser();
$parser->setIgnoreNotImportedAnnotations(true);
$reader = new AnnotationReader($parser);
foreach ($controllerList as $controllerFormat => $controller) {
// 获取类和方法的注释信息
$reflectionClass = new \ReflectionClass($controller);
$methods = $reflectionClass->getMethods();
$actionList = [];
// 遍历读取所有方法的注释的参数信息
foreach ($methods as $method) {
// 忽略掉不需要的节点
$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' => $annotation->title ?? null,
'is_auth' => $annotation->auth ?? false,
'type' => 2,
];
}
}
// 方法非空才读取控制器注解
if (!empty($actionList)) {
// 读取Controller的注解
$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);
}
}
}
return $nodeList;
}
/**
* 获取所有控制器
* @return array
*/
public function getControllerList(): array
{
return $this->readControllerFiles($this->basePath);
}
/**
* 遍历读取控制器文件
* @param $path
* @return array
*/
protected function readControllerFiles($path): array
{
list($list, $temp_list, $dirExplode) = [[], scandir($path), explode($this->basePath, $path)];
$middleDir = !empty($dirExplode[1]) ? str_replace('/', '\\', substr($dirExplode[1], 1)) . "\\" : '';
foreach ($temp_list as $file) {
// 排除根目录和没有开启注解的模块
if ($file == ".." || $file == ".") {
continue;
}
if (is_dir($path . DIRECTORY_SEPARATOR . $file)) {
// 子文件夹,进行递归
$childFiles = $this->readControllerFiles($path . DIRECTORY_SEPARATOR . $file);
$list = array_merge($childFiles, $list);
}else {
// 判断是不是控制器
$fileExplodeArray = explode('.', $file);
if (count($fileExplodeArray) != 2 || end($fileExplodeArray) != 'php') {
continue;
}
// 根目录下的文件
$className = str_replace('.php', '', $file);
$controllerFormat = str_replace('\\', '.', $middleDir) . CommonTool::humpToLine(lcfirst($className));
$list[$controllerFormat] = "{$this->baseNamespace}\\{$middleDir}" . $className;
}
}
return $list;
}
}

View File

@ -0,0 +1,166 @@
<?php
namespace app\admin\service\console;
class CliEcho
{
private array $foreground_colors = [];
private array $background_colors = [];
private static array $foregroundColors = [
'black' => '0;30',
'dark_gray' => '1;30',
'blue' => '0;34',
'light_blue' => '1;34',
'green' => '0;32',
'light_green' => '1;32',
'cyan' => '0;36',
'light_cyan' => '1;36',
'red' => '0;31',
'light_red' => '1;31',
'purple' => '0;35',
'light_purple' => '1;35',
'brown' => '0;33',
'yellow' => '1;33',
'light_gray' => '0;37',
'white' => '1;37',
];
private static $backgroundColors = [
'black' => '40',
'red' => '41',
'green' => '42',
'yellow' => '43',
'blue' => '44',
'magenta' => '45',
'cyan' => '46',
'light_gray' => '47',
];
public function __construct()
{
// Set up shell colors
$this->foreground_colors['black'] = '0;30';
$this->foreground_colors['dark_gray'] = '1;30';
$this->foreground_colors['blue'] = '0;34';
$this->foreground_colors['light_blue'] = '1;34';
$this->foreground_colors['green'] = '0;32';
$this->foreground_colors['light_green'] = '1;32';
$this->foreground_colors['cyan'] = '0;36';
$this->foreground_colors['light_cyan'] = '1;36';
$this->foreground_colors['red'] = '0;31';
$this->foreground_colors['light_red'] = '1;31';
$this->foreground_colors['purple'] = '0;35';
$this->foreground_colors['light_purple'] = '1;35';
$this->foreground_colors['brown'] = '0;33';
$this->foreground_colors['yellow'] = '1;33';
$this->foreground_colors['light_gray'] = '0;37';
$this->foreground_colors['white'] = '1;37';
$this->background_colors['black'] = '40';
$this->background_colors['red'] = '41';
$this->background_colors['green'] = '42';
$this->background_colors['yellow'] = '43';
$this->background_colors['blue'] = '44';
$this->background_colors['magenta'] = '45';
$this->background_colors['cyan'] = '46';
$this->background_colors['light_gray'] = '47';
}
// Returns colored string
public function getColoredString($string, $foreground_color = null, $background_color = null, $new_line = false): string
{
$colored_string = '';
// Check if given foreground color found
if (isset($this->foreground_colors[$foreground_color])) {
$colored_string .= "\033[" . $this->foreground_colors[$foreground_color] . 'm';
}
// Check if given background color found
if (isset($this->background_colors[$background_color])) {
$colored_string .= "\033[" . $this->background_colors[$background_color] . 'm';
}
// Add string and end coloring
$colored_string .= $string . "\033[0m";
return $new_line ? $colored_string . PHP_EOL : $colored_string;
}
// Returns all foreground color names
public function getForegroundColors(): array
{
return array_keys($this->foreground_colors);
}
// Returns all background color names
public function getBackgroundColors(): array
{
return array_keys($this->background_colors);
}
/**
* 获取带颜色的文字.
*
* @param string $string black|dark_gray|blue|light_blue|green|light_green|cyan|light_cyan|red|light_red|purple|brown|yellow|light_gray|white
* @param string|null $foregroundColor 前景颜色 black|red|green|yellow|blue|magenta|cyan|light_gray
* @param string|null $backgroundColor 背景颜色 同$foregroundColor
*
* @return string
*/
public static function initColoredString(
string $string,
?string $foregroundColor = null,
?string $backgroundColor = null
): string
{
$coloredString = '';
if (isset(static::$foregroundColors[$foregroundColor])) {
$coloredString .= "\033[" . static::$foregroundColors[$foregroundColor] . 'm';
}
if (isset(static::$backgroundColors[$backgroundColor])) {
$coloredString .= "\033[" . static::$backgroundColors[$backgroundColor] . 'm';
}
$coloredString .= $string . "\033[0m";
return $coloredString;
}
/**
* 输出提示信息.
*
* @param $msg
*/
public static function notice($msg): void
{
fwrite(STDOUT, self::initColoredString($msg, 'light_gray') . PHP_EOL);
}
/**
* 输出错误信息.
*
* @param $msg
*/
public static function error($msg): void
{
fwrite(STDERR, self::initColoredString($msg, 'white', 'red') . PHP_EOL);
}
/**
* 输出警告信息.
*
* @param $msg
*/
public static function warn($msg): void
{
fwrite(STDOUT, self::initColoredString($msg, 'red', 'yellow') . PHP_EOL);
}
/**
* 输出成功信息.
*
* @param $msg
*/
public static function success($msg): void
{
fwrite(STDOUT, self::initColoredString($msg, 'light_cyan') . PHP_EOL);
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -0,0 +1,28 @@
<?php
namespace {{controllerNamespace}};
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use think\App;
#[ControllerAnnotation(title: '{{controllerAnnotation}}')]
class {{controllerName}} extends AdminController
{
private array $notes;
public function __construct(App $app)
{
parent::__construct($app);
self::$model = new {{modelFilename}}();
$notes = self::$model::$notes;
{{constructRelation}}
$this->notes =$notes;
$this->assign(compact('notes'));
}
{{indexMethod}}
}

View File

@ -0,0 +1,21 @@
#[NodeAnnotation(title: '列表', auth: true)]
public function index(\app\Request $request): \think\response\Json|string
{
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
list($page, $limit, $where) = $this->buildTableParams();
$count = self::$model::where($where)->{{relationIndexMethod}}->count();
$list = self::$model::where($where)->{{relationIndexMethod}}->page($page, $limit)->order($this->sort)->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}

View File

@ -0,0 +1,2 @@
$this->assign('{{name}}', $this->model->{{name}}());

View File

@ -0,0 +1,23 @@
<?php
namespace {{modelNamespace}};
use app\common\model\TimeModel;
class {{modelName}} extends TimeModel
{
protected function getOptions(): array
{
return [
'name' => "{{table}}",
'table' => "{{prefix_table}}",
'deleteTime' => {{deleteTime}},
];
}
public static array $notes = {{selectArrays}};
{{relationList}}
}

View File

@ -0,0 +1,5 @@
public function {{relationMethod}}()
{
return $this->belongsTo({{relationModel}}, '{{foreignKey}}', '{{primaryKey}}'){{relationFields}};
}

View File

@ -0,0 +1,5 @@
public function {{name}}()
{
return \app\admin\model\{{relation}}::column('{{values}}', 'id');
}

View File

@ -0,0 +1,5 @@
public function {{name}}()
{
return {{values}};
}

View File

@ -0,0 +1,91 @@
define(["jquery", "easy-admin"], function ($, ea) {
var init = {
table_elem: '#currentTable',
table_render_id: 'currentTableRenderId',
index_url: '{{controllerUrl}}/index',
add_url: '{{controllerUrl}}/add',
edit_url: '{{controllerUrl}}/edit',
delete_url: '{{controllerUrl}}/delete',
export_url: '{{controllerUrl}}/export',
modify_url: '{{controllerUrl}}/modify',
recycle_url: '{{controllerUrl}}/recycle',
};
return {
index: function () {
ea.table.render({
init: init,
cols: [[
{{indexCols}}
]],
});
ea.listen();
},
add: function () {
ea.listen();
},
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();
},
};
});

View File

@ -0,0 +1,10 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
{{formList}}
<div class="hr-line"></div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

View File

@ -0,0 +1,16 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
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>
<script>
{{notesScript}}
</script>

View File

@ -0,0 +1,7 @@
<div class="layui-form-item">
<label class="layui-form-label">{{comment}}</label>
<div class="layui-input-block">
{{define}}
</div>
</div>

View File

@ -0,0 +1,3 @@
{foreach ${{name}} as $k=>$v}
<input type="checkbox" name="{{field}}[]" value="{$k}" lay-skin="primary" title="{$v}" {{select}}>
{/foreach}

View File

@ -0,0 +1,7 @@
<div class="layui-form-item">
<label class="layui-form-label">{{comment}}</label>
<div class="layui-input-block">
<input type="text" name="{{field}}" data-date="" data-date-type="{{define}}" class="layui-input" {{required}} placeholder="请输入{{comment}}" value="{{value}}">
</div>
</div>

View File

@ -0,0 +1,8 @@
<div class="layui-form-item">
<label class="layui-form-label">{{comment}}</label>
<div class="layui-input-block">
{:editor_textarea({{value}},"{{field}}","{{comment}}")}
</div>
</div>

View File

@ -0,0 +1,11 @@
<div class="layui-form-item">
<label class="layui-form-label required">{{comment}}</label>
<div class="layui-input-block layuimini-upload">
<input name="{{field}}" class="layui-input layui-col-xs6" {{required}} placeholder="请上传{{comment}}" value="{{value}}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="{{field}}" data-upload-number="one" data-upload-exts="*" data-upload-icon="file"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_{{field}}" data-upload-select="{{field}}" data-upload-number="one" data-upload-mimetype="*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>

View File

@ -0,0 +1,11 @@
<div class="layui-form-item">
<label class="layui-form-label required">{{comment}}</label>
<div class="layui-input-block layuimini-upload">
<input name="{{field}}" class="layui-input layui-col-xs6" {{required}} placeholder="请上传{{comment}}" value="{{value}}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="{{field}}" data-upload-number="more" data-upload-exts="*" data-upload-icon="file"><i class="fa fa-upload" data-upload-sign="{{define}}"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_{{field}}" data-upload-select="{{field}}" data-upload-number="more" data-upload-mimetype="*" data-upload-sign="{{define}}"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>

View File

@ -0,0 +1,11 @@
<div class="layui-form-item">
<label class="layui-form-label required">{{comment}}</label>
<div class="layui-input-block layuimini-upload">
<input name="{{field}}" class="layui-input layui-col-xs6" {{required}} placeholder="请上传{{comment}}" value="{{value}}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="{{field}}" 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_{{field}}" data-upload-select="{{field}}" data-upload-number="one" data-upload-mimetype="image/*"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>

View File

@ -0,0 +1,11 @@
<div class="layui-form-item">
<label class="layui-form-label required">{{comment}}</label>
<div class="layui-input-block layuimini-upload">
<input name="{{field}}" class="layui-input layui-col-xs6" {{required}} placeholder="请上传{{comment}}" value="{{value}}">
<div class="layuimini-upload-btn">
<span><a class="layui-btn" data-upload="{{field}}" data-upload-number="more" data-upload-exts="png|jpg|ico|jpeg" data-upload-icon="image" data-upload-sign="{{define}}"><i class="fa fa-upload"></i> 上传</a></span>
<span><a class="layui-btn layui-btn-normal" id="select_{{field}}" data-upload-select="{{field}}" data-upload-number="more" data-upload-mimetype="image/*" data-upload-sign="{{define}}"><i class="fa fa-list"></i> 选择</a></span>
</div>
</div>
</div>

View File

@ -0,0 +1,7 @@
<div class="layui-form-item">
<label class="layui-form-label">{{comment}}</label>
<div class="layui-input-block">
<input type="text" name="{{field}}" class="layui-input" {{required}} placeholder="请输入{{comment}}" value="{{value}}">
</div>
</div>

View File

@ -0,0 +1,4 @@
<option value=''></option>
{foreach ${{name}} as $k=>$v}
<option value='{$k}' {{select}}>{$v}</option>
{/foreach}

View File

@ -0,0 +1,7 @@
<div class="layui-form-item">
<label class="layui-form-label">{{comment}}</label>
<div class="layui-input-block">
{{define}}
</div>
</div>

View File

@ -0,0 +1,3 @@
{foreach ${{name}} as $k=>$v}
<input type="radio" name="{{field}}" value="{$k}" title="{$v}" {{select}}>
{/foreach}

View File

@ -0,0 +1,9 @@
<div class="layui-form-item">
<label class="layui-form-label">{{comment}}</label>
<div class="layui-input-block">
<select name="{{field}}" {{required}}>
{{define}}
</select>
</div>
</div>

View 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>

View File

@ -0,0 +1,7 @@
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">{{comment}}</label>
<div class="layui-input-block">
<textarea name="{{field}}" class="layui-textarea" {{required}} placeholder="请输入{{comment}}">{{value}}</textarea>
</div>
</div>

View 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>

View File

@ -0,0 +1,108 @@
<?php
namespace app\admin\service\tool;
class CommonTool
{
/**
* 下划线转驼峰
* @param $str
* @return null|string|string[]
*/
public static function lineToHump($str)
{
$str = preg_replace_callback('/([-_]+([a-z]{1}))/i', function ($matches) {
return strtoupper($matches[2]);
}, $str);
return $str;
}
/**
* 驼峰转下划线
* @param $str
* @return null|string|string[]
*/
public static function humpToLine($str)
{
$str = preg_replace_callback('/([A-Z]{1})/', function ($matches) {
return '_' . strtolower($matches[0]);
}, $str);
return $str;
}
/**
* 获取真实IP
* @return mixed
*/
public static function getRealIp()
{
$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach ($matches[0] as $xip) {
if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
}elseif (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}elseif (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) {
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
}elseif (isset($_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) {
$ip = $_SERVER['HTTP_X_REAL_IP'];
}
return $ip;
}
/**
* 读取文件夹下的所有文件
* @param $path
* @param $basePath
* @return array|mixed
*/
public static function readDirAllFiles($path, $basePath = '')
{
list($list, $temp_list) = [[], scandir($path)];
empty($basePath) && $basePath = $path;
foreach ($temp_list as $file) {
if ($file != ".." && $file != ".") {
if (is_dir($path . DIRECTORY_SEPARATOR . $file)) {
$childFiles = self::readDirAllFiles($path . DIRECTORY_SEPARATOR . $file, $basePath);
$list = array_merge($childFiles, $list);
}else {
$filePath = $path . DIRECTORY_SEPARATOR . $file;
$fileName = str_replace($basePath . DIRECTORY_SEPARATOR, '', $filePath);
$list[$fileName] = $filePath;
}
}
}
return $list;
}
/**
* 模板值替换
* @param $string
* @param $array
* @return mixed
*/
public static function replaceTemplate($string, $array)
{
foreach ($array as $key => $val) {
if (is_null($val)) $val = '';
$string = str_replace("{{" . $key . "}}", $val, $string);
}
return $string;
}
public static function replaceArrayString(?string $arrayString): string
{
$arrayString = str_replace('array (', '[', $arrayString);
$arrayString = str_replace(')', ']', $arrayString);
$arrayString = str_replace('=>
[', '=> [', $arrayString);
return $arrayString;
}
}