优化更新

This commit is contained in:
2026-02-11 17:13:18 +08:00
parent ada5e027fa
commit e265bcc28d
28 changed files with 1661 additions and 155 deletions
+9 -3
View File
@@ -53,15 +53,21 @@ public function headings(): array
*/
public function map($department): array
{
$parentName = '';
if ($department->parent_id) {
$parent = Department::find($department->parent_id);
$parentName = $parent ? $parent->name : '';
}
return [
$department->id,
$department->name,
$department->parent_id ? Department::find($department->parent_id)?->name : '',
$parentName,
$department->leader,
$department->phone,
$department->sort,
(int)$department->sort,
$department->status == 1 ? '启用' : '禁用',
$department->created_at ? $department->created_at->toDateTimeString() : '',
$department->created_at ? (string)$department->created_at : '',
];
}
}
+85
View File
@@ -0,0 +1,85 @@
<?php
namespace App\Exports;
use App\Models\Auth\Permission;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
class PermissionExport implements FromCollection, WithHeadings, WithMapping, ShouldAutoSize
{
protected $permissionIds;
public function __construct(array $permissionIds = [])
{
$this->permissionIds = $permissionIds;
}
/**
* 获取数据集合
*/
public function collection()
{
$query = Permission::query();
if (!empty($this->permissionIds)) {
$query->whereIn('id', $this->permissionIds);
}
return $query->orderBy('sort')->get();
}
/**
* 设置表头
*/
public function headings(): array
{
return [
'ID',
'权限标题',
'权限编码',
'权限类型',
'父级ID',
'路由路径',
'前端组件',
'排序',
'状态',
'创建时间',
];
}
/**
* 映射数据
*/
public function map($permission): array
{
return [
$permission->id,
$permission->title,
$permission->name,
$this->getTypeName($permission->type),
$permission->parent_id ?: 0,
$permission->path,
$permission->component,
(int)$permission->sort,
$permission->status == 1 ? '启用' : '禁用',
$permission->created_at ? (string)$permission->created_at : '',
];
}
/**
* 获取类型名称
*/
protected function getTypeName($type): string
{
$types = [
'menu' => '菜单',
'api' => 'API接口',
'button' => '按钮',
'url' => '链接',
];
return $types[$type] ?? $type;
}
}
+67
View File
@@ -0,0 +1,67 @@
<?php
namespace App\Exports;
use App\Models\Auth\Role;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
class RoleExport implements FromCollection, WithHeadings, WithMapping, ShouldAutoSize
{
protected $roleIds;
public function __construct(array $roleIds = [])
{
$this->roleIds = $roleIds;
}
/**
* 获取数据集合
*/
public function collection()
{
$query = Role::with(['permissions']);
if (!empty($this->roleIds)) {
$query->whereIn('id', $this->roleIds);
}
return $query->get();
}
/**
* 设置表头
*/
public function headings(): array
{
return [
'ID',
'角色名称',
'角色编码',
'描述',
'权限',
'排序',
'状态',
'创建时间',
];
}
/**
* 映射数据
*/
public function map($role): array
{
return [
$role->id,
$role->name,
$role->code,
$role->description,
$role->permissions->pluck('title')->implode(','),
(int)$role->sort,
$role->status == 1 ? '启用' : '禁用',
$role->created_at ? (string)$role->created_at : '',
];
}
}
+2 -2
View File
@@ -64,8 +64,8 @@ public function map($user): array
$user->department ? $user->department->name : '',
$user->roles->pluck('name')->implode(','),
$user->status == 1 ? '启用' : '禁用',
$user->last_login_at ? $user->last_login_at->toDateTimeString() : '',
$user->created_at ? $user->created_at->toDateTimeString() : '',
$user->last_login_at ? (string)$user->last_login_at : '',
$user->created_at ? (string)$user->created_at : '',
];
}
}
+57 -2
View File
@@ -4,15 +4,20 @@
use App\Http\Controllers\Controller;
use App\Services\Auth\PermissionService;
use App\Services\Auth\ImportExportService;
use Illuminate\Http\Request;
class Permission extends Controller
{
protected $permissionService;
protected $importExportService;
public function __construct(PermissionService $permissionService)
{
public function __construct(
PermissionService $permissionService,
ImportExportService $importExportService
) {
$this->permissionService = $permissionService;
$this->importExportService = $importExportService;
}
/**
@@ -177,4 +182,54 @@ public function batchUpdateStatus(Request $request)
'data' => ['count' => $count],
]);
}
/**
* 导出权限
*/
public function export(Request $request)
{
$validated = $request->validate([
'ids' => 'nullable|array',
'ids.*' => 'integer',
]);
$filename = $this->importExportService->exportPermissions($validated['ids'] ?? []);
$filePath = $this->importExportService->getExportFilePath($filename);
return response()->download($filePath, $filename)->deleteFileAfterSend();
}
/**
* 导入权限
*/
public function import(Request $request)
{
$validated = $request->validate([
'file' => 'required|file|mimes:xlsx,xls',
]);
$file = $request->file('file');
$realPath = $file->getRealPath();
$filename = $file->getClientOriginalName();
$result = $this->importExportService->importPermissions($filename, $realPath);
return response()->json([
'code' => 200,
'message' => "导入完成,成功 {$result['success_count']} 条,失败 {$result['error_count']}",
'data' => $result,
]);
}
/**
* 下载权限导入模板
*/
public function downloadTemplate()
{
$filename = $this->importExportService->downloadPermissionTemplate();
$filePath = $this->importExportService->getExportFilePath($filename);
return response()->download($filePath, $filename)->deleteFileAfterSend();
}
}
+57 -2
View File
@@ -4,15 +4,20 @@
use App\Http\Controllers\Controller;
use App\Services\Auth\RoleService;
use App\Services\Auth\ImportExportService;
use Illuminate\Http\Request;
class Role extends Controller
{
protected $roleService;
protected $importExportService;
public function __construct(RoleService $roleService)
{
public function __construct(
RoleService $roleService,
ImportExportService $importExportService
) {
$this->roleService = $roleService;
$this->importExportService = $importExportService;
}
/**
@@ -237,4 +242,54 @@ public function batchCopy(Request $request)
'data' => $result,
]);
}
/**
* 导出角色
*/
public function export(Request $request)
{
$validated = $request->validate([
'ids' => 'nullable|array',
'ids.*' => 'integer',
]);
$filename = $this->importExportService->exportRoles($validated['ids'] ?? []);
$filePath = $this->importExportService->getExportFilePath($filename);
return response()->download($filePath, $filename)->deleteFileAfterSend();
}
/**
* 导入角色
*/
public function import(Request $request)
{
$validated = $request->validate([
'file' => 'required|file|mimes:xlsx,xls',
]);
$file = $request->file('file');
$realPath = $file->getRealPath();
$filename = $file->getClientOriginalName();
$result = $this->importExportService->importRoles($filename, $realPath);
return response()->json([
'code' => 200,
'message' => "导入完成,成功 {$result['success_count']} 条,失败 {$result['error_count']}",
'data' => $result,
]);
}
/**
* 下载角色导入模板
*/
public function downloadTemplate()
{
$filename = $this->importExportService->downloadRoleTemplate();
$filePath = $this->importExportService->getExportFilePath($filename);
return response()->download($filePath, $filename)->deleteFileAfterSend();
}
}
+166
View File
@@ -0,0 +1,166 @@
<?php
namespace App\Imports;
use App\Models\Auth\Permission;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;
class PermissionImport implements ToCollection, WithHeadingRow, WithValidation
{
protected $successCount = 0;
protected $errorCount = 0;
protected $errors = [];
/**
* 处理导入数据
*/
public function collection(Collection $rows)
{
foreach ($rows as $index => $row) {
try {
// 跳过空行
if (empty($row['权限标题'])) {
continue;
}
// 检查权限编码是否已存在
$exists = Permission::where('name', $row['权限编码'])->exists();
if ($exists) {
$this->addError($index + 2, '权限编码已存在');
continue;
}
// 查找父级权限
$parentId = null;
if (!empty($row['父级ID']) && $row['父级ID'] != 0) {
$parent = Permission::find($row['父级ID']);
if (!$parent) {
$this->addError($index + 2, '父级权限不存在');
continue;
}
$parentId = $parent->id;
}
// 解析类型
$type = $this->parseType($row['权限类型']);
// 解析元数据
$meta = null;
if ($type === 'menu' && !empty($row['元数据'])) {
// 元数据格式: icon:Setting,hidden:false,keepAlive:false
$meta = $this->parseMeta($row['元数据']);
}
// 创建权限
Permission::create([
'title' => $row['权限标题'],
'name' => $row['权限编码'],
'type' => $type,
'parent_id' => $parentId,
'path' => $row['路由路径'] ?? null,
'component' => $row['前端组件'] ?? null,
'meta' => $meta,
'sort' => $row['排序'] ?? 0,
'status' => 1,
]);
$this->successCount++;
} catch (\Exception $e) {
$this->addError($index + 2, $e->getMessage());
}
}
}
/**
* 验证规则
*/
public function rules(): array
{
return [
'权限标题' => 'required|string|max:50',
'权限编码' => 'required|string|max:100',
'权限类型' => 'required|in:菜单,API接口,按钮,链接,menu,api,button,url',
'父级ID' => 'nullable|integer|min:0',
'路由路径' => 'nullable|string|max:200',
'前端组件' => 'nullable|string|max:200',
'排序' => 'nullable|integer|min:0',
];
}
/**
* 自定义验证消息
*/
public function customValidationMessages(): array
{
return [
'权限标题.required' => '权限标题不能为空',
'权限编码.required' => '权限编码不能为空',
'权限类型.required' => '权限类型不能为空',
];
}
/**
* 解析类型
*/
protected function parseType($type): string
{
$typeMap = [
'菜单' => 'menu',
'API接口' => 'api',
'接口' => 'api',
'按钮' => 'button',
'链接' => 'url',
];
return $typeMap[$type] ?? $type;
}
/**
* 解析元数据
*/
protected function parseMeta($metaString): ?string
{
if (empty($metaString)) {
return null;
}
// 简单解析,实际项目中可能需要更复杂的解析逻辑
return $metaString;
}
/**
* 添加错误
*/
protected function addError(int $row, string $message): void
{
$this->errorCount++;
$this->errors[] = "{$row} 行: {$message}";
}
/**
* 获取成功数量
*/
public function getSuccessCount(): int
{
return $this->successCount;
}
/**
* 获取错误数量
*/
public function getErrorCount(): int
{
return $this->errorCount;
}
/**
* 获取错误信息
*/
public function getErrors(): array
{
return $this->errors;
}
}
+129
View File
@@ -0,0 +1,129 @@
<?php
namespace App\Imports;
use App\Models\Auth\Role;
use App\Models\Auth\Permission;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;
class RoleImport implements ToCollection, WithHeadingRow, WithValidation
{
protected $successCount = 0;
protected $errorCount = 0;
protected $errors = [];
/**
* 处理导入数据
*/
public function collection(Collection $rows)
{
foreach ($rows as $index => $row) {
try {
// 跳过空行
if (empty($row['角色名称'])) {
continue;
}
// 检查角色编码是否已存在
$exists = Role::where('code', $row['角色编码'])->exists();
if ($exists) {
$this->addError($index + 2, '角色编码已存在');
continue;
}
// 查找权限
$permissionIds = [];
if (!empty($row['权限(多个用逗号分隔)'])) {
$permissionNames = array_map('trim', explode(',', $row['权限(多个用逗号分隔)']));
$permissions = Permission::whereIn('title', $permissionNames)->get();
if ($permissions->count() != count($permissionNames)) {
$existingNames = $permissions->pluck('title')->toArray();
$notFound = array_diff($permissionNames, $existingNames);
$this->addError($index + 2, '权限不存在: ' . implode(', ', $notFound));
continue;
}
$permissionIds = $permissions->pluck('id')->toArray();
}
// 创建角色
$role = Role::create([
'name' => $row['角色名称'],
'code' => $row['角色编码'],
'description' => $row['描述'] ?? null,
'sort' => $row['排序'] ?? 0,
'status' => 1,
]);
// 分配权限
if (!empty($permissionIds)) {
$role->permissions()->attach($permissionIds);
}
$this->successCount++;
} catch (\Exception $e) {
$this->addError($index + 2, $e->getMessage());
}
}
}
/**
* 验证规则
*/
public function rules(): array
{
return [
'角色名称' => 'required|string|max:50',
'角色编码' => 'required|string|max:50',
'描述' => 'nullable|string|max:200',
'排序' => 'nullable|integer|min:0',
];
}
/**
* 自定义验证消息
*/
public function customValidationMessages(): array
{
return [
'角色名称.required' => '角色名称不能为空',
'角色编码.required' => '角色编码不能为空',
];
}
/**
* 添加错误
*/
protected function addError(int $row, string $message): void
{
$this->errorCount++;
$this->errors[] = "{$row} 行: {$message}";
}
/**
* 获取成功数量
*/
public function getSuccessCount(): int
{
return $this->successCount;
}
/**
* 获取错误数量
*/
public function getErrorCount(): int
{
return $this->errorCount;
}
/**
* 获取错误信息
*/
public function getErrors(): array
{
return $this->errors;
}
}
+2 -1
View File
@@ -2,13 +2,14 @@
namespace App\Models\Auth;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Department extends Model
{
use SoftDeletes;
use ModelTrait, SoftDeletes;
protected $table = 'auth_departments';
+2 -1
View File
@@ -2,13 +2,14 @@
namespace App\Models\Auth;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Permission extends Model
{
use SoftDeletes;
use ModelTrait, SoftDeletes;
protected $table = 'auth_permissions';
+2 -1
View File
@@ -2,13 +2,14 @@
namespace App\Models\Auth;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Role extends Model
{
use SoftDeletes;
use ModelTrait, SoftDeletes;
protected $table = 'auth_roles';
+2 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models\Auth;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@@ -11,7 +12,7 @@
class User extends Authenticatable implements JWTSubject
{
use SoftDeletes;
use ModelTrait, SoftDeletes;
protected $table = 'auth_users';
+2
View File
@@ -2,11 +2,13 @@
namespace App\Models\System;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class City extends Model
{
use ModelTrait;
protected $table = 'system_cities';
protected $fillable = [
+2 -1
View File
@@ -2,12 +2,13 @@
namespace App\Models\System;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Config extends Model
{
use SoftDeletes;
use ModelTrait, SoftDeletes;
protected $table = 'system_configs';
+2 -1
View File
@@ -2,13 +2,14 @@
namespace App\Models\System;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Dictionary extends Model
{
use SoftDeletes;
use ModelTrait, SoftDeletes;
protected $table = 'system_dictionaries';
+2
View File
@@ -2,11 +2,13 @@
namespace App\Models\System;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class DictionaryItem extends Model
{
use ModelTrait;
protected $table = 'system_dictionary_items';
protected $fillable = [
+2
View File
@@ -2,11 +2,13 @@
namespace App\Models\System;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Log extends Model
{
use ModelTrait;
protected $table = 'system_logs';
protected $fillable = [
+2 -1
View File
@@ -2,12 +2,13 @@
namespace App\Models\System;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Task extends Model
{
use SoftDeletes;
use ModelTrait, SoftDeletes;
protected $table = 'system_tasks';
+164
View File
@@ -10,8 +10,12 @@
use Maatwebsite\Excel\Facades\Excel;
use App\Exports\UserExport;
use App\Exports\DepartmentExport;
use App\Exports\RoleExport;
use App\Exports\PermissionExport;
use App\Imports\UserImport;
use App\Imports\DepartmentImport;
use App\Imports\RoleImport;
use App\Imports\PermissionImport;
class ImportExportService
{
@@ -187,6 +191,166 @@ public function getExportFilePath(string $filename): string
return storage_path('app/exports/' . $filename);
}
/**
* 下载角色导入模板
*/
public function downloadRoleTemplate(): string
{
$filename = 'role_import_template_' . date('YmdHis') . '.xlsx';
// 确保目录存在
if (!is_dir(storage_path('app/exports'))) {
mkdir(storage_path('app/exports'), 0755, true);
}
$templateData = [
[
'角色名称*',
'角色编码*',
'描述',
'权限(多个用逗号分隔)',
'排序',
],
[
'测试角色',
'test_role',
'这是一个测试角色',
'查看用户,编辑用户',
'1',
],
];
Excel::store(new \App\Exports\GenericExport($templateData), 'exports/' . $filename);
return $filename;
}
/**
* 导出角色数据
*/
public function exportRoles(array $roleIds = []): string
{
$filename = 'roles_export_' . date('YmdHis') . '.xlsx';
// 确保目录存在
if (!is_dir(storage_path('app/exports'))) {
mkdir(storage_path('app/exports'), 0755, true);
}
Excel::store(new RoleExport($roleIds), 'exports/' . $filename);
return $filename;
}
/**
* 导入角色数据
*/
public function importRoles(string $filePath, string $realPath): array
{
if (!file_exists($realPath)) {
throw ValidationException::withMessages([
'file' => ['文件不存在'],
]);
}
$import = new RoleImport();
Excel::import($import, $realPath);
// 删除临时文件
if (file_exists($realPath)) {
unlink($realPath);
}
return [
'success_count' => $import->getSuccessCount(),
'error_count' => $import->getErrorCount(),
'errors' => $import->getErrors(),
];
}
/**
* 下载权限导入模板
*/
public function downloadPermissionTemplate(): string
{
$filename = 'permission_import_template_' . date('YmdHis') . '.xlsx';
// 确保目录存在
if (!is_dir(storage_path('app/exports'))) {
mkdir(storage_path('app/exports'), 0755, true);
}
$templateData = [
[
'权限标题*',
'权限编码*',
'权限类型*',
'父级ID',
'路由路径',
'前端组件',
'元数据',
'排序',
],
[
'系统管理',
'system',
'菜单',
'0',
'/system',
null,
'icon:Setting',
'1',
],
];
Excel::store(new \App\Exports\GenericExport($templateData), 'exports/' . $filename);
return $filename;
}
/**
* 导出权限数据
*/
public function exportPermissions(array $permissionIds = []): string
{
$filename = 'permissions_export_' . date('YmdHis') . '.xlsx';
// 确保目录存在
if (!is_dir(storage_path('app/exports'))) {
mkdir(storage_path('app/exports'), 0755, true);
}
Excel::store(new PermissionExport($permissionIds), 'exports/' . $filename);
return $filename;
}
/**
* 导入权限数据
*/
public function importPermissions(string $filePath, string $realPath): array
{
if (!file_exists($realPath)) {
throw ValidationException::withMessages([
'file' => ['文件不存在'],
]);
}
$import = new PermissionImport();
Excel::import($import, $realPath);
// 删除临时文件
if (file_exists($realPath)) {
unlink($realPath);
}
return [
'success_count' => $import->getSuccessCount(),
'error_count' => $import->getErrorCount(),
'errors' => $import->getErrors(),
];
}
/**
* 删除导出文件
*/
+230
View File
@@ -0,0 +1,230 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace App\Support;
class Regex {
/**
* 验证用户名
*
* @param string $value 验证的值
* @param int $minLen 最小长度
* @param int $maxLen 最大长度
* @param string $type 验证类型,默认‘ALL,EN.验证英文,CN.验证中文,ALL.验证中文和英文
* @return bool
*/
public static function isUsername($value, $minLen = 2, $maxLen = 48, $type = 'ALL')
{
if (empty ($value)) {
return false;
}
switch ($type) {
case 'EN' :
$match = '/^[_\w\d]{' . $minLen . ',' . $maxLen . '}$/iu';
break;
case 'CN' :
$match = '/^[_\x{4e00}-\x{9fa5}\d]{' . $minLen . ',' . $maxLen . '}$/iu';
break;
default :
$match = '/^[_\w\d\x{4e00}-\x{9fa5}]{' . $minLen . ',' . $maxLen . '}$/iu';
}
return preg_match($match, $value) !== 0;
}
/**
* 验证密码
*
* @param string $value 验证的值
* @param int $minLen 最小长度
* @param int $maxLen 最大长度
* @return bool
*/
public static function isPassword($value, $minLen = 6, $maxLen = 16)
{
$value = trim($value);
if (empty ($value)) {
return false;
}
$match = '/^[\\~!@#$%^&*()-_=+|{}\[\],.?\/:;\'\"\d\w]{' . $minLen . ',' . $maxLen . '}$/';
return preg_match($match, $value) !== 0;
}
/**
* 验证eamil
*
* @param string $value 验证的值
* @return bool
*/
public static function isEmail($value)
{
$value = trim($value);
if (empty ($value)) {
return false;
}
$match = '/^[\w\d]+[\w\d-.]*@[\w\d-.]+\.[\w\d]{2,10}$/i';
return preg_match($match, $value) !== 0;
}
/**
* 验证电话号码
*
* @param string $value 验证的值
* @return bool
*/
public static function isTelephone($value)
{
$value = trim($value);
if (empty ($value)) {
return false;
}
$match = '/^0[0-9]{2,3}[-]?\d{7,8}$/';
return preg_match($match, $value) !== 0;
}
/**
* 验证手机
*
* @param string $value 验证的值
* @return bool
*/
public static function isMobile($value)
{
$value = trim($value);
if (empty ($value)) {
return false;
}
$match = '/^[(86)|0]?(1\d{10})$/';
return preg_match($match, $value) !== 0;
}
/**
* 验证邮政编码
*
* @param string $value 验证的值
* @return bool
*/
public static function isPostCode($value)
{
$value = trim($value);
if (empty ($value)) {
return false;
}
$match = '/\d{6}/';
return preg_match($match, $value) !== 0;
}
/**
* 验证IP
*
* @param string $value 验证的值
* @return boolean
*/
public static function isIp($value)
{
$value = trim($value);
if (empty ($value)) {
return false;
}
$match = '/^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])' .
'\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)' .
'\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)' .
'\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$/';
return preg_match($match, $value) !== 0;
}
/**
* 验证身份证号码
*
* @param string $value 验证的值
* @return boolean
*/
public static function isIDCard($value)
{
$value = trim($value);
if (empty ($value)) {
return false;
}
if (strlen($value) > 18) {
return false;
}
$match = '/^\d{6}((1[89])|(2\d))\d{2}((0\d)|(1[0-2]))((3[01])|([0-2]\d))\d{3}(\d|X)$/i';
return preg_match($match, $value) !== 0;
}
/**
* 验证URL
*
* @param string $value 验证的值
* @return boolean
*/
public static function isUrl($value)
{
$value = strtolower(trim($value));
if (empty ($value)) {
return false;
}
$match = '/^(http:\/\/)?(https:\/\/)?([\w\d-]+\.)+[\w-]+(\/[\d\w-.\/?%&=]*)?$/';
return preg_match($match, $value) !== 0;
}
/**
* 是否有数字
* 说明:如果字符串中含有非法字符返回假,没有返回真
*
* @param string $value 验证的值
* @return int
*/
public static function hasNumber($value)
{
return preg_match("/[0-9]/", $value) != false;
}
/**
* 是否含有英文
* 说明:如果字符串中含有非法字符返回假,没有返回真
*
* @param string $value 验证的值
* @return bool
*/
public static function hasEnglish($value)
{
return preg_match("/[a-zA-Z]/", $value) != false;
}
/**
* 是否有中文
* 说明:如果字符串中含有非法字符返回假,没有返回真
*
* @param string $value 验证的值
* @return bool
*/
public static function hasChinese($value)
{
return preg_match("/[\x7f-\xff]/", $value) != false;
}
}
+298
View File
@@ -0,0 +1,298 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace App\Support;
use Illuminate\Support\Carbon;
class Time {
/**
* 返回今日开始和结束的时间戳
*
* @return array
*/
public static function today($data = '') {
[$y, $m, $d] = explode('-', $data ? $data : date('Y-m-d'));
return [
mktime(0, 0, 0, $m, $d, $y),
mktime(23, 59, 59, $m, $d, $y),
];
}
/**
* 返回昨日开始和结束的时间戳
*
* @return array
*/
public static function yesterday() {
$yesterday = date('d') - 1;
return [
mktime(0, 0, 0, date('m'), $yesterday, date('Y')),
mktime(23, 59, 59, date('m'), $yesterday, date('Y')),
];
}
/**
* 返回本周开始和结束的时间戳
*
* @return array
*/
public static function week() {
[$y, $m, $d, $w] = explode('-', date('Y-m-d-w'));
if ($w == 0) $w = 7; //修正周日的问题
return [
mktime(0, 0, 0, $m, $d - $w + 1, $y), mktime(23, 59, 59, $m, $d - $w + 7, $y),
];
}
/**
* 返回上周开始和结束的时间戳
*
* @return array
*/
public static function lastWeek() {
$timestamp = time();
return [
strtotime(date('Y-m-d', strtotime("last week Monday", $timestamp))),
strtotime(date('Y-m-d', strtotime("last week Sunday", $timestamp))) + 24 * 3600 - 1,
];
}
/**
* 返回本月开始和结束的时间戳
*
* @return array
*/
public static function month($data = '') {
$res = [];
$data = $data ? $data : date('Y-m-d');
$nextMoth = date('Y-m-d', strtotime($data . ' +1 month'));
return [
mktime(0, 0, 0, date('m', strtotime($data)), 1, date('Y', strtotime($data))),
mktime(0, 0, 0, date('m', strtotime($nextMoth)), 1, date('Y', strtotime($nextMoth))),
];
}
/**
* 返回上个月开始和结束的时间戳
*
* @return array
*/
public static function lastMonth() {
$y = date('Y');
$m = date('m');
$begin = mktime(0, 0, 0, $m - 1, 1, $y);
$end = mktime(23, 59, 59, $m - 1, date('t', $begin), $y);
return [$begin, $end];
}
/**
* 返回今年开始和结束的时间戳
*
* @return array
*/
public static function year() {
$y = date('Y');
return [
mktime(0, 0, 0, 1, 1, $y),
mktime(23, 59, 59, 12, 31, $y),
];
}
/**
* 返回去年开始和结束的时间戳
*
* @return array
*/
public static function lastYear() {
$year = date('Y') - 1;
return [
mktime(0, 0, 0, 1, 1, $year),
mktime(23, 59, 59, 12, 31, $year),
];
}
/**
* 获取几天前零点到现在/昨日结束的时间戳
*
* @param int $day 天数
* @param bool $now 返回现在或者昨天结束时间戳
* @return array
*/
public static function dayToNow($day = 1, $now = true) {
$end = time();
if (!$now) {
[$foo, $end] = self::yesterday();
}
return [
mktime(0, 0, 0, date('m'), date('d') - $day, date('Y')),
$end,
];
}
/**
* 返回几天前的时间戳
*
* @param int $day
* @return int
*/
public static function daysAgo($day = 1) {
$nowTime = time();
return $nowTime - self::daysToSecond($day);
}
/**
* 返回几天后的时间戳
*
* @param int $day
* @return int
*/
public static function daysAfter($day = 1) {
$nowTime = time();
return $nowTime + self::daysToSecond($day);
}
/**
* 天数转换成秒数
*
* @param int $day
* @return int
*/
public static function daysToSecond($day = 1) {
return $day * 86400;
}
/**
* 周数转换成秒数
*
* @param int $week
* @return int
*/
public static function weekToSecond($week = 1) {
return self::daysToSecond() * 7 * $week;
}
/**
* 获取毫秒级别的时间戳
*/
public static function getMillisecond() {
$time = explode(" ", microtime());
$time = $time[1] . ($time[0] * 1000);
$time2 = explode(".", $time);
$time = $time2[0];
return $time;
}
/**
* 获取相对时间
*
* @param int $timeStamp
* @return string
*/
public static function formatRelative($timeStamp) {
$currentTime = time();
// 判断传入时间戳是否早于当前时间戳
$isEarly = $timeStamp <= $currentTime;
// 获取两个时间戳差值
$diff = abs($currentTime - $timeStamp);
$dirStr = $isEarly ? '前' : '后';
if ($diff < 60) { // 一分钟之内
$resStr = $diff . '秒' . $dirStr;
} elseif ($diff >= 60 && $diff < 3600) { // 多于59秒,少于等于59分钟59秒
$resStr = floor($diff / 60) . '分钟' . $dirStr;
} elseif ($diff >= 3600 && $diff < 86400) { // 多于59分钟59秒,少于等于23小时59分钟59秒
$resStr = floor($diff / 3600) . '小时' . $dirStr;
} elseif ($diff >= 86400 && $diff < 2623860) { // 多于23小时59分钟59秒,少于等于29天59分钟59秒
$resStr = floor($diff / 86400) . '天' . $dirStr;
} elseif ($diff >= 2623860 && $diff <= 31567860 && $isEarly) { // 多于29天59分钟59秒,少于364天23小时59分钟59秒,且传入的时间戳早于当前
$resStr = date('m-d H:i', $timeStamp);
} else {
$resStr = date('Y-m-d', $timeStamp);
}
return $resStr;
}
/**
* 范围日期转换时间戳
*
* @param string $rangeDatetime
* @param int $maxRange 最大时间间隔
* @param string $delimiter
* @return array
*/
public static function parseRange($rangeDatetime, $maxRange = 0, $delimiter = ' - ') {
$rangeDatetime = explode($delimiter, $rangeDatetime, 2);
$rangeDatetime[0] = strtotime($rangeDatetime[0]);
$rangeDatetime[1] = isset($rangeDatetime[1]) ? strtotime($rangeDatetime[1]) : time();
$rangeDatetime = [
min($rangeDatetime[0], $rangeDatetime[1]),
max($rangeDatetime[0], $rangeDatetime[1]),
];
// 如果结束时间小于或等于开始时间 直接返回null
// if ($rangeDatetime[1] < $rangeDatetime[0]) {
// return null;
// }
// 如果大于最大时间间隔 则用结束时间减去最大时间间隔获得开始时间
if ($maxRange > 0 && $rangeDatetime[1] - $rangeDatetime[0] > $maxRange) {
$rangeDatetime[0] = $rangeDatetime[1] - $maxRange;
}
return $rangeDatetime;
}
/**
* 获取指定时间范围内的日期数组
* @param int $startTime
* @param int $endTime
* @return \Carbon\CarbonPeriod
*/
public static function daysUntilOfTimestamp($startTime, $endTime) {
$startTime = Carbon::createFromTimestamp($startTime);
$endTime = Carbon::createFromTimestamp($endTime);
return $startTime->daysUntil($endTime);
}
/**
* 时间排序
*
* @param array $times
* @return array
*/
public static function sort($times) {
usort($times, function ($com1, $com2) {
$com1 = strtotime($com1);
$com2 = strtotime($com2);
return $com1 < $com2 ? -1 : 1;
});
return $times;
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace App\Traits;
use Illuminate\Support\Facades\Schema;
trait ModelTrait {
protected function casts(): array {
return [
'created_at' => 'datetime:Y-m-d H:i:s',
'updated_at' => 'datetime:Y-m-d H:i:s',
'deleted_at' => 'datetime:Y-m-d H:i:s',
];
}
protected function serializeDate($data){
return $data->timezone('Asia/Shanghai')->format('Y-m-d H:i:s');
}
/**
* 过滤移除非当前表的字段参数
*
* @param array $params
*
* @return array
*/
public function setFilterFields(array $params) : array {
$fields = Schema::getColumnListing($this->getTable());
foreach ($params as $key => $param) {
if ( !in_array($key, $fields) ) unset($params[$key]);
}
// 同时过滤时间戳字段【时间戳只允许自动更改,不允许手动设置】
if ( $this->timestamps === true && isset($params[self::CREATED_AT]) ) unset($params[self::CREATED_AT]);
if ( $this->timestamps === true && isset($params[self::UPDATED_AT]) ) unset($params[self::UPDATED_AT]);
return $params;
}
}