初始化项目
This commit is contained in:
198
app/Services/System/CityService.php
Normal file
198
app/Services/System/CityService.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\City;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class CityService
|
||||
{
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$query = City::query();
|
||||
|
||||
if (!empty($params['parent_id'])) {
|
||||
$query->where('parent_id', $params['parent_id']);
|
||||
}
|
||||
|
||||
if (!empty($params['level'])) {
|
||||
$query->where('level', $params['level']);
|
||||
}
|
||||
|
||||
if (!empty($params['keyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('name', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('code', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('pinyin', 'like', '%' . $params['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
$query->orderBy('sort')->orderBy('id');
|
||||
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->paginate($pageSize);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $list->currentPage(),
|
||||
'page_size' => $list->perPage(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getTree(): array
|
||||
{
|
||||
return $this->buildTree(City::where('status', true)->orderBy('sort')->get());
|
||||
}
|
||||
|
||||
public function getChildren(int $parentId): array
|
||||
{
|
||||
return City::where('parent_id', $parentId)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function getByCode(string $code): ?City
|
||||
{
|
||||
return City::where('code', $code)->first();
|
||||
}
|
||||
|
||||
public function getById(int $id): ?City
|
||||
{
|
||||
return City::find($id);
|
||||
}
|
||||
|
||||
public function getByPinyin(string $pinyin): array
|
||||
{
|
||||
return City::where('pinyin', 'like', '%' . $pinyin . '%')
|
||||
->where('status', true)
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function create(array $data): City
|
||||
{
|
||||
Validator::make($data, [
|
||||
'name' => 'required|string|max:100',
|
||||
'code' => 'required|string|max:50|unique:system_cities,code',
|
||||
'level' => 'required|integer|in:1,2,3',
|
||||
'parent_id' => 'sometimes|exists:system_cities,id',
|
||||
])->validate();
|
||||
|
||||
$city = City::create($data);
|
||||
$this->clearCache();
|
||||
return $city;
|
||||
}
|
||||
|
||||
public function update(int $id, array $data): City
|
||||
{
|
||||
$city = City::findOrFail($id);
|
||||
|
||||
Validator::make($data, [
|
||||
'name' => 'sometimes|required|string|max:100',
|
||||
'code' => 'sometimes|required|string|max:50|unique:system_cities,code,' . $id,
|
||||
'level' => 'sometimes|required|integer|in:1,2,3',
|
||||
'parent_id' => 'sometimes|exists:system_cities,id',
|
||||
])->validate();
|
||||
|
||||
$city->update($data);
|
||||
$this->clearCache();
|
||||
return $city;
|
||||
}
|
||||
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$city = City::findOrFail($id);
|
||||
|
||||
if ($city->children()->exists()) {
|
||||
throw new \Exception('该城市下有子级数据,不能删除');
|
||||
}
|
||||
|
||||
$city->delete();
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchDelete(array $ids): bool
|
||||
{
|
||||
City::whereIn('id', $ids)->delete();
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchUpdateStatus(array $ids, bool $status): bool
|
||||
{
|
||||
City::whereIn('id', $ids)->update(['status' => $status]);
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
private function buildTree(array $cities, int $parentId = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($cities as $city) {
|
||||
if ($city['parent_id'] == $parentId) {
|
||||
$children = $this->buildTree($cities, $city['id']);
|
||||
if (!empty($children)) {
|
||||
$city['children'] = $children;
|
||||
}
|
||||
$tree[] = $city;
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
private function clearCache(): void
|
||||
{
|
||||
Cache::forget('system:cities:tree');
|
||||
}
|
||||
|
||||
public function getCachedTree(): array
|
||||
{
|
||||
$cacheKey = 'system:cities:tree';
|
||||
$tree = Cache::get($cacheKey);
|
||||
|
||||
if ($tree === null) {
|
||||
$tree = $this->getTree();
|
||||
Cache::put($cacheKey, $tree, 3600);
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
public function getProvinces(): array
|
||||
{
|
||||
return City::where('level', 1)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function getCities(int $provinceId): array
|
||||
{
|
||||
return City::where('parent_id', $provinceId)
|
||||
->where('level', 2)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function getDistricts(int $cityId): array
|
||||
{
|
||||
return City::where('parent_id', $cityId)
|
||||
->where('level', 3)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
158
app/Services/System/ConfigService.php
Normal file
158
app/Services/System/ConfigService.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Config;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class ConfigService
|
||||
{
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$query = Config::query();
|
||||
|
||||
if (!empty($params['group'])) {
|
||||
$query->where('group', $params['group']);
|
||||
}
|
||||
|
||||
if (!empty($params['keyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('name', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('key', 'like', '%' . $params['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->orderBy('sort')->orderBy('id')->paginate($pageSize);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $list->currentPage(),
|
||||
'page_size' => $list->perPage(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getById(int $id): ?Config
|
||||
{
|
||||
return Config::find($id);
|
||||
}
|
||||
|
||||
public function getByKey(string $key): ?Config
|
||||
{
|
||||
return Config::where('key', $key)->first();
|
||||
}
|
||||
|
||||
public function getByGroup(string $group): array
|
||||
{
|
||||
return Config::where('group', $group)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function getAllConfig(): array
|
||||
{
|
||||
$cacheKey = 'system:configs:all';
|
||||
$configs = Cache::get($cacheKey);
|
||||
|
||||
if ($configs === null) {
|
||||
$configs = Config::where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->keyBy('key')
|
||||
->toArray();
|
||||
Cache::put($cacheKey, $configs, 3600);
|
||||
}
|
||||
|
||||
return $configs;
|
||||
}
|
||||
|
||||
public function getConfigValue(string $key, $default = null)
|
||||
{
|
||||
$config = $this->getByKey($key);
|
||||
if (!$config) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $config->value ?? $config->default_value ?? $default;
|
||||
}
|
||||
|
||||
public function create(array $data): Config
|
||||
{
|
||||
Validator::make($data, [
|
||||
'group' => 'required|string|max:50',
|
||||
'key' => 'required|string|max:100|unique:system_configs,key',
|
||||
'name' => 'required|string|max:100',
|
||||
'type' => 'required|string|in:string,text,number,boolean,select,radio,checkbox,file,json',
|
||||
])->validate();
|
||||
|
||||
$config = Config::create($data);
|
||||
$this->clearCache();
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function update(int $id, array $data): Config
|
||||
{
|
||||
$config = Config::findOrFail($id);
|
||||
|
||||
Validator::make($data, [
|
||||
'group' => 'sometimes|required|string|max:50',
|
||||
'key' => 'sometimes|required|string|max:100|unique:system_configs,key,' . $id,
|
||||
'name' => 'sometimes|required|string|max:100',
|
||||
'type' => 'sometimes|required|string|in:string,text,number,boolean,select,radio,checkbox,file,json',
|
||||
])->validate();
|
||||
|
||||
$config->update($data);
|
||||
$this->clearCache();
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$config = Config::findOrFail($id);
|
||||
|
||||
if ($config->is_system) {
|
||||
throw new \Exception('系统配置不能删除');
|
||||
}
|
||||
|
||||
$config->delete();
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchDelete(array $ids): bool
|
||||
{
|
||||
$configs = Config::whereIn('id', $ids)->where('is_system', false)->get();
|
||||
Config::whereIn('id', $configs->pluck('id'))->delete();
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchUpdateStatus(array $ids, bool $status): bool
|
||||
{
|
||||
Config::whereIn('id', $ids)->update(['status' => $status]);
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
private function clearCache(): void
|
||||
{
|
||||
Cache::forget('system:configs:all');
|
||||
}
|
||||
|
||||
public function getGroups(): array
|
||||
{
|
||||
return Config::where('status', true)
|
||||
->select('group')
|
||||
->distinct()
|
||||
->pluck('group')
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
210
app/Services/System/DictionaryService.php
Normal file
210
app/Services/System/DictionaryService.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Dictionary;
|
||||
use App\Models\System\DictionaryItem;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class DictionaryService
|
||||
{
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$query = Dictionary::query();
|
||||
|
||||
if (!empty($params['keyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('name', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('code', 'like', '%' . $params['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->orderBy('sort')->orderBy('id')->paginate($pageSize);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $list->currentPage(),
|
||||
'page_size' => $list->perPage(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getAll(): array
|
||||
{
|
||||
return Dictionary::where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function getById(int $id): ?Dictionary
|
||||
{
|
||||
return Dictionary::with('items')->find($id);
|
||||
}
|
||||
|
||||
public function getByCode(string $code): ?Dictionary
|
||||
{
|
||||
return Dictionary::where('code', $code)->first();
|
||||
}
|
||||
|
||||
public function getItemsByCode(string $code): array
|
||||
{
|
||||
$cacheKey = 'system:dictionary:' . $code;
|
||||
$items = Cache::get($cacheKey);
|
||||
|
||||
if ($items === null) {
|
||||
$dictionary = Dictionary::where('code', $code)->first();
|
||||
if ($dictionary) {
|
||||
$items = DictionaryItem::where('dictionary_id', $dictionary->id)
|
||||
->where('status', true)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->toArray();
|
||||
Cache::put($cacheKey, $items, 3600);
|
||||
} else {
|
||||
$items = [];
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function create(array $data): Dictionary
|
||||
{
|
||||
Validator::make($data, [
|
||||
'name' => 'required|string|max:100',
|
||||
'code' => 'required|string|max:50|unique:system_dictionaries,code',
|
||||
])->validate();
|
||||
|
||||
$dictionary = Dictionary::create($data);
|
||||
$this->clearCache();
|
||||
return $dictionary;
|
||||
}
|
||||
|
||||
public function update(int $id, array $data): Dictionary
|
||||
{
|
||||
$dictionary = Dictionary::findOrFail($id);
|
||||
|
||||
Validator::make($data, [
|
||||
'name' => 'sometimes|required|string|max:100',
|
||||
'code' => 'sometimes|required|string|max:50|unique:system_dictionaries,code,' . $id,
|
||||
])->validate();
|
||||
|
||||
$dictionary->update($data);
|
||||
$this->clearCache();
|
||||
return $dictionary;
|
||||
}
|
||||
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$dictionary = Dictionary::findOrFail($id);
|
||||
DictionaryItem::where('dictionary_id', $id)->delete();
|
||||
$dictionary->delete();
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchDelete(array $ids): bool
|
||||
{
|
||||
DictionaryItem::whereIn('dictionary_id', $ids)->delete();
|
||||
Dictionary::whereIn('id', $ids)->delete();
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchUpdateStatus(array $ids, bool $status): bool
|
||||
{
|
||||
Dictionary::whereIn('id', $ids)->update(['status' => $status]);
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
private function clearCache(): void
|
||||
{
|
||||
$codes = Dictionary::pluck('code')->toArray();
|
||||
foreach ($codes as $code) {
|
||||
Cache::forget('system:dictionary:' . $code);
|
||||
}
|
||||
}
|
||||
|
||||
public function getItemsList(array $params): array
|
||||
{
|
||||
$query = DictionaryItem::query();
|
||||
|
||||
if (!empty($params['dictionary_id'])) {
|
||||
$query->where('dictionary_id', $params['dictionary_id']);
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
$query->orderBy('sort')->orderBy('id');
|
||||
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->paginate($pageSize);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $list->currentPage(),
|
||||
'page_size' => $list->perPage(),
|
||||
];
|
||||
}
|
||||
|
||||
public function createItem(array $data): DictionaryItem
|
||||
{
|
||||
Validator::make($data, [
|
||||
'dictionary_id' => 'required|exists:system_dictionaries,id',
|
||||
'label' => 'required|string|max:100',
|
||||
'value' => 'required|string|max:100',
|
||||
])->validate();
|
||||
|
||||
$item = DictionaryItem::create($data);
|
||||
$this->clearCache();
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function updateItem(int $id, array $data): DictionaryItem
|
||||
{
|
||||
$item = DictionaryItem::findOrFail($id);
|
||||
|
||||
Validator::make($data, [
|
||||
'dictionary_id' => 'sometimes|required|exists:system_dictionaries,id',
|
||||
'label' => 'sometimes|required|string|max:100',
|
||||
'value' => 'sometimes|required|string|max:100',
|
||||
])->validate();
|
||||
|
||||
$item->update($data);
|
||||
$this->clearCache();
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function deleteItem(int $id): bool
|
||||
{
|
||||
$item = DictionaryItem::findOrFail($id);
|
||||
$item->delete();
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchDeleteItems(array $ids): bool
|
||||
{
|
||||
DictionaryItem::whereIn('id', $ids)->delete();
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchUpdateItemsStatus(array $ids, bool $status): bool
|
||||
{
|
||||
DictionaryItem::whereIn('id', $ids)->update(['status' => $status]);
|
||||
$this->clearCache();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
125
app/Services/System/LogService.php
Normal file
125
app/Services/System/LogService.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Log;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class LogService
|
||||
{
|
||||
public function create(array $data): Log
|
||||
{
|
||||
return Log::create($data);
|
||||
}
|
||||
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$query = $this->buildQuery($params);
|
||||
|
||||
$query->orderBy('created_at', 'desc');
|
||||
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->paginate($pageSize);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $list->currentPage(),
|
||||
'page_size' => $list->perPage(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询(用于导出等场景)
|
||||
*
|
||||
* @param array $params
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function getListQuery(array $params)
|
||||
{
|
||||
return $this->buildQuery($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建基础查询
|
||||
*
|
||||
* @param array $params
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
protected function buildQuery(array $params)
|
||||
{
|
||||
$query = Log::query()->with('user:id,name,username');
|
||||
|
||||
if (!empty($params['user_id'])) {
|
||||
$query->where('user_id', $params['user_id']);
|
||||
}
|
||||
|
||||
if (!empty($params['username'])) {
|
||||
$query->where('username', 'like', '%' . $params['username'] . '%');
|
||||
}
|
||||
|
||||
if (!empty($params['module'])) {
|
||||
$query->where('module', $params['module']);
|
||||
}
|
||||
|
||||
if (!empty($params['action'])) {
|
||||
$query->where('action', $params['action']);
|
||||
}
|
||||
|
||||
if (!empty($params['status'])) {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
if (!empty($params['start_date']) && !empty($params['end_date'])) {
|
||||
$query->whereBetween('created_at', [$params['start_date'], $params['end_date']]);
|
||||
}
|
||||
|
||||
if (!empty($params['ip'])) {
|
||||
$query->where('ip', 'like', '%' . $params['ip'] . '%');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function getById(int $id): ?Log
|
||||
{
|
||||
return Log::with('user')->find($id);
|
||||
}
|
||||
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$log = Log::findOrFail($id);
|
||||
return $log->delete();
|
||||
}
|
||||
|
||||
public function clearLogs(string $days = '30'): bool
|
||||
{
|
||||
Log::where('created_at', '<', now()->subDays($days))->delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchDelete(array $ids): bool
|
||||
{
|
||||
Log::whereIn('id', $ids)->delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getStatistics(array $params = []): array
|
||||
{
|
||||
$query = Log::query();
|
||||
|
||||
if (!empty($params['start_date']) && !empty($params['end_date'])) {
|
||||
$query->whereBetween('created_at', [$params['start_date'], $params['end_date']]);
|
||||
}
|
||||
|
||||
$total = $query->count();
|
||||
$successCount = (clone $query)->where('status', 'success')->count();
|
||||
$errorCount = (clone $query)->where('status', 'error')->count();
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'success' => $successCount,
|
||||
'error' => $errorCount,
|
||||
];
|
||||
}
|
||||
}
|
||||
167
app/Services/System/TaskService.php
Normal file
167
app/Services/System/TaskService.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Task;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class TaskService
|
||||
{
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$query = Task::query();
|
||||
|
||||
if (!empty($params['keyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('name', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('command', 'like', '%' . $params['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
if (isset($params['is_active']) && $params['is_active'] !== '') {
|
||||
$query->where('is_active', $params['is_active']);
|
||||
}
|
||||
|
||||
if (!empty($params['type'])) {
|
||||
$query->where('type', $params['type']);
|
||||
}
|
||||
|
||||
$query->orderBy('id');
|
||||
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->paginate($pageSize);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $list->currentPage(),
|
||||
'page_size' => $list->perPage(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getAll(): array
|
||||
{
|
||||
return Task::all()->toArray();
|
||||
}
|
||||
|
||||
public function getById(int $id): ?Task
|
||||
{
|
||||
return Task::find($id);
|
||||
}
|
||||
|
||||
public function create(array $data): Task
|
||||
{
|
||||
Validator::make($data, [
|
||||
'name' => 'required|string|max:100',
|
||||
'command' => 'required|string|max:255',
|
||||
'type' => 'required|string|in:command,job,closure',
|
||||
'expression' => 'required|string',
|
||||
])->validate();
|
||||
|
||||
return Task::create($data);
|
||||
}
|
||||
|
||||
public function update(int $id, array $data): Task
|
||||
{
|
||||
$task = Task::findOrFail($id);
|
||||
|
||||
Validator::make($data, [
|
||||
'name' => 'sometimes|required|string|max:100',
|
||||
'command' => 'sometimes|required|string|max:255',
|
||||
'type' => 'sometimes|required|string|in:command,job,closure',
|
||||
'expression' => 'sometimes|required|string',
|
||||
])->validate();
|
||||
|
||||
$task->update($data);
|
||||
return $task;
|
||||
}
|
||||
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$task = Task::findOrFail($id);
|
||||
return $task->delete();
|
||||
}
|
||||
|
||||
public function batchDelete(array $ids): bool
|
||||
{
|
||||
Task::whereIn('id', $ids)->delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function batchUpdateStatus(array $ids, bool $status): bool
|
||||
{
|
||||
Task::whereIn('id', $ids)->update(['is_active' => $status]);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function run(int $id): array
|
||||
{
|
||||
$task = Task::findOrFail($id);
|
||||
|
||||
$startTime = microtime(true);
|
||||
$output = '';
|
||||
$status = 'success';
|
||||
$errorMessage = '';
|
||||
|
||||
try {
|
||||
switch ($task->type) {
|
||||
case 'command':
|
||||
$command = $task->command;
|
||||
if ($task->run_in_background) {
|
||||
$command .= ' > /dev/null 2>&1 &';
|
||||
}
|
||||
exec($command, $output, $statusCode);
|
||||
$output = implode("\n", $output);
|
||||
if ($statusCode !== 0) {
|
||||
throw new \Exception('Command failed with status code: ' . $statusCode);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'job':
|
||||
$jobClass = $task->command;
|
||||
if (class_exists($jobClass)) {
|
||||
dispatch(new $jobClass());
|
||||
} else {
|
||||
throw new \Exception('Job class not found: ' . $jobClass);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'closure':
|
||||
throw new \Exception('Closure type tasks cannot be run directly');
|
||||
}
|
||||
|
||||
$task->increment('run_count');
|
||||
} catch (\Exception $e) {
|
||||
$status = 'error';
|
||||
$errorMessage = $e->getMessage();
|
||||
$task->increment('failed_count');
|
||||
}
|
||||
|
||||
$executionTime = round((microtime(true) - $startTime) * 1000);
|
||||
|
||||
$task->update([
|
||||
'last_run_at' => now(),
|
||||
'last_output' => substr($output, 0, 10000),
|
||||
]);
|
||||
|
||||
return [
|
||||
'status' => $status,
|
||||
'output' => $output,
|
||||
'error_message' => $errorMessage,
|
||||
'execution_time' => $executionTime,
|
||||
];
|
||||
}
|
||||
|
||||
public function getStatistics(): array
|
||||
{
|
||||
$total = Task::count();
|
||||
$active = Task::where('is_active', true)->count();
|
||||
$inactive = Task::where('is_active', false)->count();
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'active' => $active,
|
||||
'inactive' => $inactive,
|
||||
];
|
||||
}
|
||||
}
|
||||
160
app/Services/System/UploadService.php
Normal file
160
app/Services/System/UploadService.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\System;
|
||||
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Intervention\Image\Facades\Image;
|
||||
|
||||
class UploadService
|
||||
{
|
||||
protected $disk;
|
||||
protected $allowedImageTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
|
||||
protected $allowedFileTypes = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', 'txt'];
|
||||
protected $maxFileSize = 10 * 1024 * 1024; // 10MB
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->disk = Storage::disk('public');
|
||||
}
|
||||
|
||||
public function upload(UploadedFile $file, string $directory = 'uploads', array $options = []): array
|
||||
{
|
||||
$extension = strtolower($file->getClientOriginalExtension());
|
||||
|
||||
if (!$this->validateFile($file, $extension)) {
|
||||
throw new \Exception('文件验证失败');
|
||||
}
|
||||
|
||||
$fileName = $this->generateFileName($file, $extension);
|
||||
$filePath = $directory . '/' . date('Ymd') . '/' . $fileName;
|
||||
|
||||
if (in_array($extension, $this->allowedImageTypes) && isset($options['compress'])) {
|
||||
$this->compressImage($file, $filePath, $options);
|
||||
} else {
|
||||
$this->disk->put($filePath, file_get_contents($file));
|
||||
}
|
||||
|
||||
$url = $this->disk->url($filePath);
|
||||
$fullPath = $this->disk->path($filePath);
|
||||
|
||||
return [
|
||||
'url' => $url,
|
||||
'path' => $filePath,
|
||||
'name' => $file->getClientOriginalName(),
|
||||
'size' => $file->getSize(),
|
||||
'mime_type' => $file->getMimeType(),
|
||||
'extension' => $extension,
|
||||
];
|
||||
}
|
||||
|
||||
public function uploadMultiple(array $files, string $directory = 'uploads', array $options = []): array
|
||||
{
|
||||
$results = [];
|
||||
foreach ($files as $file) {
|
||||
if ($file instanceof UploadedFile) {
|
||||
$results[] = $this->upload($file, $directory, $options);
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
public function uploadBase64(string $base64, string $directory = 'uploads', string $fileName = null): array
|
||||
{
|
||||
if (preg_match('/^data:image\/(\w+);base64,/', $base64, $matches)) {
|
||||
$type = $matches[1];
|
||||
$extension = $type;
|
||||
$data = substr($base64, strpos($base64, ',') + 1);
|
||||
$data = base64_decode($data);
|
||||
|
||||
if (!$data) {
|
||||
throw new \Exception('Base64解码失败');
|
||||
}
|
||||
|
||||
$fileName = $fileName ?: $this->generateUniqueFileName($extension);
|
||||
$filePath = $directory . '/' . date('Ymd') . '/' . $fileName;
|
||||
$this->disk->put($filePath, $data);
|
||||
|
||||
return [
|
||||
'url' => $this->disk->url($filePath),
|
||||
'path' => $filePath,
|
||||
'name' => $fileName,
|
||||
'size' => strlen($data),
|
||||
'mime_type' => 'image/' . $type,
|
||||
'extension' => $extension,
|
||||
];
|
||||
}
|
||||
|
||||
throw new \Exception('无效的Base64图片数据');
|
||||
}
|
||||
|
||||
public function delete(string $path): bool
|
||||
{
|
||||
if ($this->disk->exists($path)) {
|
||||
return $this->disk->delete($path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function deleteMultiple(array $paths): bool
|
||||
{
|
||||
foreach ($paths as $path) {
|
||||
$this->delete($path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function validateFile(UploadedFile $file, string $extension): bool
|
||||
{
|
||||
if ($file->getSize() > $this->maxFileSize) {
|
||||
throw new \Exception('文件大小超过限制');
|
||||
}
|
||||
|
||||
$allowedTypes = array_merge($this->allowedImageTypes, $this->allowedFileTypes);
|
||||
if (!in_array($extension, $allowedTypes)) {
|
||||
throw new \Exception('不允许的文件类型');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function generateFileName(UploadedFile $file, string $extension): string
|
||||
{
|
||||
return uniqid() . '_' . Str::random(6) . '.' . $extension;
|
||||
}
|
||||
|
||||
private function generateUniqueFileName(string $extension): string
|
||||
{
|
||||
return uniqid() . '_' . Str::random(6) . '.' . $extension;
|
||||
}
|
||||
|
||||
private function compressImage(UploadedFile $file, string $filePath, array $options): void
|
||||
{
|
||||
$quality = $options['quality'] ?? 80;
|
||||
$width = $options['width'] ?? null;
|
||||
$height = $options['height'] ?? null;
|
||||
|
||||
$image = Image::make($file);
|
||||
|
||||
if ($width || $height) {
|
||||
$image->resize($width, $height, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
$constraint->upsize();
|
||||
});
|
||||
}
|
||||
|
||||
$image->encode(null, $quality);
|
||||
$this->disk->put($filePath, (string) $image);
|
||||
}
|
||||
|
||||
public function getFileUrl(string $path): string
|
||||
{
|
||||
return $this->disk->url($path);
|
||||
}
|
||||
|
||||
public function fileExists(string $path): bool
|
||||
{
|
||||
return $this->disk->exists($path);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user