admin keywords.resource
parent
39c40820e0
commit
611721b700
|
|
@ -33,8 +33,8 @@ SESSION_PATH=/
|
|||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
FILESYSTEM_DISK=public
|
||||
QUEUE_CONNECTION=sync
|
||||
|
||||
CACHE_STORE=file
|
||||
CACHE_PREFIX=
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin;
|
||||
|
||||
use Slowlyo\OwlAdmin\Traits\MakeTrait;
|
||||
|
||||
class Components
|
||||
{
|
||||
use MakeTrait;
|
||||
|
||||
/**
|
||||
* 字典表-树形选择框
|
||||
*
|
||||
* @param array $params 查询参数
|
||||
*/
|
||||
public function keywordTreeSelectControl($params = [])
|
||||
{
|
||||
$url = amis()->BaseApi()->url(admin_url('api/keywords/tree-list'))->data($params);
|
||||
return amis()->TreeSelectControl()->source($url)->labelField('name')->valueField('id');
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ namespace App\Admin\Controllers;
|
|||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||
|
||||
class HomeController extends AdminController
|
||||
|
|
@ -16,6 +17,21 @@ class HomeController extends AdminController
|
|||
return $this->response()->success($page);
|
||||
}
|
||||
|
||||
protected function upload($type = 'file')
|
||||
{
|
||||
$file = request()->file('file');
|
||||
|
||||
if (! $file) {
|
||||
return $this->response()->fail(__('admin.upload_file_error'));
|
||||
}
|
||||
|
||||
$disk = request()->input('disk', Admin::config('admin.upload.disk'));
|
||||
|
||||
$path = $file->store(Admin::config('admin.upload.directory.'.$type), $disk);
|
||||
|
||||
return $this->response()->success(['value' => Storage::disk($disk)->url($path), 'path' => $path]);
|
||||
}
|
||||
|
||||
public function frameworkInfo()
|
||||
{
|
||||
$link = function ($label, $link) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Admin\Components;
|
||||
use App\Models\Keyword;
|
||||
use App\Services\KeywordService;
|
||||
use Illuminate\Http\Request;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||
|
||||
|
|
@ -16,49 +19,100 @@ class KeywordController extends AdminController
|
|||
protected string $serviceName = KeywordService::class;
|
||||
|
||||
public function list()
|
||||
{
|
||||
{
|
||||
$user = Admin::user();
|
||||
$crud = $this->baseCRUD()
|
||||
->filterTogglable(false)
|
||||
->bulkActions([])
|
||||
->columnsTogglable(false)
|
||||
$crud = $this->baseCRUD()
|
||||
->filterTogglable(false)
|
||||
->columnsTogglable(false)
|
||||
->loadDataOnce(true)
|
||||
->footerToolbar([])
|
||||
->headerToolbar([
|
||||
$this->createButton()->visible($user->can('keywords.create')),
|
||||
...$this->baseHeaderToolBar(),
|
||||
$this->createButton()->visible($user->can('keywords.create')),
|
||||
$this->exportAction()->visible($user->can('keywords.export')),
|
||||
...$this->baseHeaderToolBar(),
|
||||
])
|
||||
->columns([
|
||||
amis()->TableColumn('id', 'ID')->sortable(),
|
||||
amis()->TableColumn('key', 'KEY'),
|
||||
amis()->TableColumn('name', '名称'),
|
||||
amis()->TableColumn('value', '值'),
|
||||
$this->rowActions([
|
||||
->filter($this->baseFilter()->body([
|
||||
amis()->GroupControl()->mode('horizontal')->body([
|
||||
Components::make()->keywordTreeSelectControl()->name('path')->label(__('keywords.parent_id'))->columnRatio(3)->clearable(),
|
||||
])
|
||||
]))
|
||||
->columns([
|
||||
amis()->TableColumn()->name('id')->label(__('keywords.id')),
|
||||
amis()->TableColumn()->name('name')->label(__('keywords.name')),
|
||||
amis()->TableColumn()->name('key')->label(__('keywords.key')),
|
||||
amis()->TableColumn()->name('value')->label(__('keywords.value')),
|
||||
$this->rowActions([
|
||||
$this->rowShowButton()->visible($user->can('keywords.show')),
|
||||
$this->rowEditButton()->visible($user->can('keywords.edit')),
|
||||
$this->rowDeleteButton()->visible($user->can('keywords.delete')),
|
||||
])
|
||||
]);
|
||||
]),
|
||||
]);
|
||||
|
||||
return $this->baseList($crud);
|
||||
}
|
||||
return $this->baseList($crud);
|
||||
}
|
||||
|
||||
public function form($isEdit = false)
|
||||
{
|
||||
return $this->baseForm()->body([
|
||||
amis()->TextControl('key', 'KEY'),
|
||||
amis()->TextControl('name', '名称'),
|
||||
amis()->TextControl('value', '值'),
|
||||
]);
|
||||
}
|
||||
public function form()
|
||||
{
|
||||
return $this->baseForm()->mode('horizontal')->body([
|
||||
Components::make()->keywordTreeSelectControl()->name('parent_id')->label(__('keywords.parent_id')),
|
||||
amis()->TextControl()->name('name')->label(__('keywords.name'))->required(true),
|
||||
amis()->TextControl()->name('key')->label(__('keywords.key'))->required(true),
|
||||
amis()->TextControl()->name('value')->label(__('keywords.value')),
|
||||
amis()->ImageControl()->name('image')->label(__('keywords.image'))->autoUpload(true),
|
||||
amis()->ImageControl()->name('images')->label(__('keywords.images'))->multiple()->autoUpload(true),
|
||||
amis()->NumberControl()->min(0)->precision(0)->name('sort')->label(__('keywords.sort')),
|
||||
amis()->TextareaControl()->name('description')->label(__('keywords.description')),
|
||||
amis()->inputKV()->name('options')->label(__('keywords.options')),
|
||||
amis()->WangEditor()->height('auto')->name('content')->label(__('keywords.content')),
|
||||
]);
|
||||
}
|
||||
|
||||
public function detail()
|
||||
{
|
||||
return $this->baseDetail()->body([
|
||||
amis()->TextControl('id', 'ID')->static(),
|
||||
amis()->TextControl('key', 'KEY')->static(),
|
||||
amis()->TextControl('name', '名称')->static(),
|
||||
amis()->TextControl('value', '值')->static(),
|
||||
amis()->TextControl('created_at', admin_trans('admin.created_at'))->static(),
|
||||
amis()->TextControl('updated_at', admin_trans('admin.updated_at'))->static(),
|
||||
]);
|
||||
}
|
||||
public function detail()
|
||||
{
|
||||
return $this->baseDetail()->body(amis()->Property()->items([
|
||||
['label' => __('keywords.parent_id'), 'content' => '${parent.name}', 'span' => 3],
|
||||
|
||||
['label' => __('keywords.name'), 'content' => '${name}'],
|
||||
['label' => __('keywords.key'), 'content' => '${key}'],
|
||||
['label' => __('keywords.value'), 'content' => '${value}'],
|
||||
|
||||
['label' => __('keywords.image'), 'content' => amis()->Image()->name('image'), 'span' => 3],
|
||||
['label' => __('keywords.images'), 'content' => amis()->Images()->name('images'), 'span' => 3],
|
||||
['label' => __('keywords.sort'), 'content' => '${sort}', 'span' => 3],
|
||||
['label' => __('keywords.description'), 'content' => '${description}', 'span' => 3],
|
||||
['label' => __('keywords.options'), 'content' => amis()->Json()->name('options'), 'span' => 3],
|
||||
['label' => __('keywords.content'), 'content' => amis()->WangEditor()->height('auto')->name('content')->label(false)->static(), 'span' => 3],
|
||||
]));
|
||||
}
|
||||
|
||||
public function update(Request $request)
|
||||
{
|
||||
$result = $this->service->update($request->route()->parameter('keyword'), $request->all());
|
||||
|
||||
return $this->autoResponse($result, __('admin.save'));
|
||||
}
|
||||
|
||||
public function getTreeList(Request $request)
|
||||
{
|
||||
return $this->service->getTree($request->all());
|
||||
}
|
||||
|
||||
public function getList(Request $request)
|
||||
{
|
||||
$list = Keyword::filter($request->all())->select(['id as value', 'name as label'])->get();
|
||||
|
||||
return $this->response()->success($list);
|
||||
}
|
||||
|
||||
// protected function exportFileName()
|
||||
// {
|
||||
// return '此处为导出文件名';
|
||||
// }
|
||||
|
||||
// protected function exportMap($row)
|
||||
// {
|
||||
// return [
|
||||
// 'id' => __('keywords.id')
|
||||
// ];
|
||||
// }
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Admin\Controllers\HomeController;
|
||||
use App\Admin\Controllers\KeywordController;
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
|
@ -10,8 +12,18 @@ Route::group([
|
|||
'prefix' => config('admin.route.prefix'),
|
||||
'middleware' => config('admin.route.middleware'),
|
||||
], function (Router $router) {
|
||||
$router->get('dashboard', [\App\Admin\Controllers\HomeController::class, 'index'])->name('dashboard');
|
||||
$router->group([
|
||||
'prefix' => 'api',
|
||||
], function (Router $router) {
|
||||
$router->get('keywords/tree-list', [KeywordController::class, 'getTreeList']);
|
||||
$router->get('keywords/list', [KeywordController::class, 'getList']);
|
||||
});
|
||||
|
||||
$router->get('dashboard', [HomeController::class, 'index'])->name('dashboard');
|
||||
$router->resource('system/settings', \App\Admin\Controllers\SettingController::class)->only(['index', 'store']);
|
||||
|
||||
$router->resource('system/keywords', \App\Admin\Controllers\KeywordController::class);
|
||||
$router->any('upload_image', [HomeController::class, 'uploadImage']);
|
||||
$router->any('upload_file', [HomeController::class, 'uploadFile']);
|
||||
|
||||
$router->resource('system/keywords', KeywordController::class);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace App\Casts;
|
||||
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* 转换文件存储路径
|
||||
*
|
||||
* get: 返回全路径
|
||||
* set: 原样保存
|
||||
*/
|
||||
class StorageFile implements CastsAttributes
|
||||
{
|
||||
protected $disk;
|
||||
|
||||
public function __construct($disk = '')
|
||||
{
|
||||
$this->disk = $disk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast the given value.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param array $attributes
|
||||
* @return array
|
||||
*/
|
||||
public function get($model, $key, $value, $attributes)
|
||||
{
|
||||
return $value ? (Str::startsWith($value, ['http://', 'https://']) ? $value : Storage::disk($this->disk)->url($value)) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given value for storage.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param array $value
|
||||
* @param array $attributes
|
||||
* @return string
|
||||
*/
|
||||
public function set($model, $key, $value, $attributes)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace App\ModelFilters;
|
||||
|
||||
use App\Models\Keyword;
|
||||
use EloquentFilter\ModelFilter;
|
||||
|
||||
class KeywordFilter extends ModelFilter
|
||||
{
|
||||
/**
|
||||
* Related Models that have ModelFilters as well as the method on the ModelFilter
|
||||
* As [relationMethod => [input_key1, input_key2]].
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $relations = [];
|
||||
|
||||
public function parent($id)
|
||||
{
|
||||
$this->where('parent_id', $id);
|
||||
}
|
||||
|
||||
public function key($key)
|
||||
{
|
||||
$this->whereLike('key', $key);
|
||||
}
|
||||
|
||||
public function name($key)
|
||||
{
|
||||
$this->whereLike('name', $key);
|
||||
}
|
||||
|
||||
public function parentKey($key)
|
||||
{
|
||||
$id = Keyword::where('key', $key)->value('id');
|
||||
$this->path($id);
|
||||
}
|
||||
|
||||
public function parentName($key)
|
||||
{
|
||||
$id = Keyword::where('name', $key)->value('id');
|
||||
if ($id) {
|
||||
$this->parent($id);
|
||||
}
|
||||
}
|
||||
|
||||
public function path($key)
|
||||
{
|
||||
$this->whereLike('path', '-'.$key.'-');
|
||||
}
|
||||
|
||||
public function level($key)
|
||||
{
|
||||
$this->where('level', $key);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,22 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Slowlyo\OwlAdmin\Models\BaseModel as Model;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Slowlyo\OwlAdmin\Traits\DatetimeFormatterTrait;
|
||||
use EloquentFilter\Filterable;
|
||||
use App\Traits\TreePath;
|
||||
|
||||
/**
|
||||
* 字典管理
|
||||
*/
|
||||
class Keyword extends Model
|
||||
{
|
||||
use DatetimeFormatterTrait, Filterable, TreePath;
|
||||
|
||||
protected $fillable = ['id', 'name', 'key', 'value', 'parent_id', 'path', 'sort', 'level', 'options', 'image', 'images', 'description', 'content'];
|
||||
|
||||
protected $casts = [
|
||||
'options' => 'array',
|
||||
'images' => 'array',
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Database\Events\QueryExecuted;
|
||||
use Illuminate\Database\Events\TransactionBeginning;
|
||||
use Illuminate\Database\Events\TransactionCommitted;
|
||||
use Illuminate\Database\Events\TransactionRolledBack;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class QueryLogServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
if (! config('app.debug')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->app['events']->listen([
|
||||
QueryExecuted::class,
|
||||
TransactionBeginning::class,
|
||||
TransactionCommitted::class,
|
||||
TransactionRolledBack::class,
|
||||
], function ($event) {
|
||||
if ($event instanceof TransactionBeginning) {
|
||||
return $this->writeLog('begin transaction');
|
||||
} elseif ($event instanceof TransactionCommitted) {
|
||||
return $this->writeLog('commit transaction');
|
||||
} elseif ($event instanceof TransactionRolledBack) {
|
||||
return $this->writeLog('rollback transaction');
|
||||
}
|
||||
|
||||
$this->writeLog($this->prepareSql($event));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 准备 SQL 语句
|
||||
*/
|
||||
protected function prepareSql(QueryExecuted $query): string
|
||||
{
|
||||
$sql = str_replace(['%', '?'], ['%%', '%s'], $query->sql);
|
||||
|
||||
if (count($bindings = $query->connection->prepareBindings($query->bindings))) {
|
||||
$sql = vsprintf($sql, array_map([$query->connection->getPdo(), 'quote'], $bindings));
|
||||
}
|
||||
|
||||
return sprintf('[%s] %s', $this->formatDuration($query->time), $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间
|
||||
*
|
||||
* @param float $milliseconds
|
||||
*/
|
||||
protected function formatDuration($milliseconds): string
|
||||
{
|
||||
if ($milliseconds < 0.01) {
|
||||
return round($milliseconds * 1000).'μs';
|
||||
} elseif ($milliseconds >= 1000) {
|
||||
return round($milliseconds / 1000, 2).'s';
|
||||
}
|
||||
|
||||
return $milliseconds.'ms';
|
||||
}
|
||||
|
||||
/**
|
||||
* 将消息记录到日志中
|
||||
*
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
protected function writeLog($message, array $context = [])
|
||||
{
|
||||
Log::debug($message, $context);
|
||||
}
|
||||
}
|
||||
|
|
@ -14,4 +14,39 @@ use Slowlyo\OwlAdmin\Services\AdminService;
|
|||
class KeywordService extends AdminService
|
||||
{
|
||||
protected string $modelName = Keyword::class;
|
||||
|
||||
public function getTree($filters = [])
|
||||
{
|
||||
$list = $this->query()->filter($filters)->sort()->get();
|
||||
|
||||
return array2tree($list->toArray(), $list->min('parent_id') ?: 0);
|
||||
}
|
||||
|
||||
public function list()
|
||||
{
|
||||
return ['items' => $this->getTree(request()->all())];
|
||||
}
|
||||
|
||||
public function addRelations($query, string $scene = 'list')
|
||||
{
|
||||
if ($scene == 'detail') {
|
||||
$query->with(['parent']);
|
||||
}
|
||||
}
|
||||
|
||||
public function query()
|
||||
{
|
||||
return $this->modelName::query()->sort();
|
||||
}
|
||||
|
||||
public function deleted($ids)
|
||||
{
|
||||
$ids = explode(',', $ids);
|
||||
|
||||
$this->query()->where(function ($q) use ($ids) {
|
||||
foreach ($ids as $id) {
|
||||
$q->orWhere('path', 'like', '%-'.$id.'-%');
|
||||
}
|
||||
})->delete();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Model Tree
|
||||
*
|
||||
* parent_id: 上级id, 默认: 0
|
||||
* path: 所有上级id, 例如: -1-2-3-
|
||||
* sort: 排序(正序)
|
||||
*/
|
||||
trait TreePath
|
||||
{
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::creating(function (Model $model) {
|
||||
if ($model->parent_id) {
|
||||
$parent = static::query()->findOrFail($model->parent_id);
|
||||
$model->path = $parent->path . $parent->id . '-';
|
||||
} else {
|
||||
$model->parent_id = 0;
|
||||
$model->path = '-';
|
||||
}
|
||||
});
|
||||
|
||||
static::updating(function (Model $model) {
|
||||
if ($model->parent_id) {
|
||||
$parent = static::query()->findOrFail($model->parent_id);
|
||||
$model->path = $parent->path . $parent->id . '-';
|
||||
} else {
|
||||
$model->parent_id = 0;
|
||||
$model->path = '-';
|
||||
}
|
||||
});
|
||||
|
||||
static::deleting(function (Model $model) {
|
||||
static::query()->allChildren($model->id)->delete();
|
||||
});
|
||||
}
|
||||
protected function parentIds(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => explode('-', substr($this->path, 1, -1)),
|
||||
);
|
||||
}
|
||||
|
||||
public function children()
|
||||
{
|
||||
return $this->hasMany(static::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(static::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function scopeAllChildren($q, $pid)
|
||||
{
|
||||
return $q->where('path', 'like', '%-'.$pid.'-%');
|
||||
}
|
||||
|
||||
public function scopeSort($q)
|
||||
{
|
||||
return $q->orderBy('parent_id')->orderBy('sort');
|
||||
}
|
||||
|
||||
public static function getTreeList($list, $pid = 0)
|
||||
{
|
||||
$tree = collect();
|
||||
foreach ($list->where('parent_id', $pid)->all() as $item) {
|
||||
$item->children = [];
|
||||
$children = $list->where('parent_id', $item->id);
|
||||
if ($children->count() > 0) {
|
||||
$item->children = static::getTreeList($list, $item->id);
|
||||
}
|
||||
$tree->push($item);
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,4 +2,5 @@
|
|||
|
||||
return [
|
||||
App\Providers\AppServiceProvider::class,
|
||||
App\Providers\QueryLogServiceProvider::class,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"laravel/framework": "^11.9",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^2.9",
|
||||
"rap2hpoutre/fast-excel": "^5.5",
|
||||
"slowlyo/owl-admin": "^3.8",
|
||||
"tucker-eric/eloquentfilter": "^3.4"
|
||||
},
|
||||
|
|
@ -64,11 +65,5 @@
|
|||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist": {
|
||||
"type": "composer",
|
||||
"url": "https://mirrors.aliyun.com/composer/"
|
||||
}
|
||||
}
|
||||
"prefer-stable": true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c49fb7d62386a65cbd1917fa5cdcd780",
|
||||
"content-hash": "897c9f6897a2d847033ffd18be088aef",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
|
|
@ -2386,6 +2386,99 @@
|
|||
],
|
||||
"time": "2024-03-06T16:17:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "openspout/openspout",
|
||||
"version": "v4.24.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openspout/openspout.git",
|
||||
"reference": "24272c1f7d073cc64fa3ecc2a863dc5d13be33a8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/openspout/openspout/zipball/24272c1f7d073cc64fa3ecc2a863dc5d13be33a8",
|
||||
"reference": "24272c1f7d073cc64fa3ecc2a863dc5d13be33a8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-filter": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlreader": "*",
|
||||
"ext-zip": "*",
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-zlib": "*",
|
||||
"friendsofphp/php-cs-fixer": "^3.59.3",
|
||||
"infection/infection": "^0.29.5",
|
||||
"phpbench/phpbench": "^1.2.15",
|
||||
"phpstan/phpstan": "^1.11.4",
|
||||
"phpstan/phpstan-phpunit": "^1.4.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.6.0",
|
||||
"phpunit/phpunit": "^10.5.20 || ^11.2.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-iconv": "To handle non UTF-8 CSV files (if \"php-mbstring\" is not already installed or is too limited)",
|
||||
"ext-mbstring": "To handle non UTF-8 CSV files (if \"iconv\" is not already installed)"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"OpenSpout\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Adrien Loison",
|
||||
"email": "adrien@box.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP Library to read and write spreadsheet files (CSV, XLSX and ODS), in a fast and scalable way",
|
||||
"homepage": "https://github.com/openspout/openspout",
|
||||
"keywords": [
|
||||
"OOXML",
|
||||
"csv",
|
||||
"excel",
|
||||
"memory",
|
||||
"odf",
|
||||
"ods",
|
||||
"office",
|
||||
"open",
|
||||
"php",
|
||||
"read",
|
||||
"scale",
|
||||
"spreadsheet",
|
||||
"stream",
|
||||
"write",
|
||||
"xlsx"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/openspout/openspout/issues",
|
||||
"source": "https://github.com/openspout/openspout/tree/v4.24.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://paypal.me/filippotessarotto",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/Slamdunk",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-17T08:53:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
"version": "1.9.2",
|
||||
|
|
@ -3177,6 +3270,76 @@
|
|||
],
|
||||
"time": "2024-04-27T21:32:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rap2hpoutre/fast-excel",
|
||||
"version": "v5.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rap2hpoutre/fast-excel.git",
|
||||
"reference": "83604f2a16fbb0374747299173abe691b24916da"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rap2hpoutre/fast-excel/zipball/83604f2a16fbb0374747299173abe691b24916da",
|
||||
"reference": "83604f2a16fbb0374747299173abe691b24916da",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0",
|
||||
"openspout/openspout": "^4.24",
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/database": "^6.20.12 || ^7.30.4 || ^8.24.0 || ^9.0 || ^10.0 || ^11.0",
|
||||
"phpunit/phpunit": "^9.5 || ^10.1",
|
||||
"squizlabs/php_codesniffer": "3.*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Rap2hpoutre\\FastExcel\\Providers\\FastExcelServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions/fastexcel.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Rap2hpoutre\\FastExcel\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "rap2h",
|
||||
"email": "raphaelht@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Fast Excel import/export for Laravel",
|
||||
"keywords": [
|
||||
"csv",
|
||||
"excel",
|
||||
"laravel",
|
||||
"xls",
|
||||
"xlsx"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/rap2hpoutre/fast-excel/issues",
|
||||
"source": "https://github.com/rap2hpoutre/fast-excel/tree/v5.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/rap2hpoutre",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-03T08:00:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slowlyo/laravel-support",
|
||||
"version": "v0.0.3",
|
||||
|
|
@ -3238,23 +3401,17 @@
|
|||
},
|
||||
{
|
||||
"name": "slowlyo/owl-admin",
|
||||
"version": "v3.8.0",
|
||||
"version": "v3.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slowlyo/owl-admin.git",
|
||||
"reference": "002a00fe5d27a9eb5b13bc8f827bd199fcfeae61"
|
||||
"reference": "760513c1db8d3df96d9e1897791d53d7f79dcd5f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slowlyo/owl-admin/zipball/002a00fe5d27a9eb5b13bc8f827bd199fcfeae61",
|
||||
"reference": "002a00fe5d27a9eb5b13bc8f827bd199fcfeae61",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
"url": "https://api.github.com/repos/slowlyo/owl-admin/zipball/760513c1db8d3df96d9e1897791d53d7f79dcd5f",
|
||||
"reference": "760513c1db8d3df96d9e1897791d53d7f79dcd5f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gd": "*",
|
||||
|
|
@ -3305,10 +3462,10 @@
|
|||
"email": "slowlyo_email@qq.com",
|
||||
"forum": "https://github.com/orgs/owl-admin/discussions",
|
||||
"issues": "https://github.com/Slowlyo/owl-admin/issues",
|
||||
"source": "https://github.com/slowlyo/owl-admin/tree/v3.8.0",
|
||||
"source": "https://github.com/slowlyo/owl-admin/tree/v3.9.0",
|
||||
"wiki": "https://doc.owladmin.com/"
|
||||
},
|
||||
"time": "2024-06-09T17:39:14+00:00"
|
||||
"time": "2024-07-07T16:34:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/clock",
|
||||
|
|
|
|||
|
|
@ -23,15 +23,7 @@ return [
|
|||
'prefix' => 'admin-api',
|
||||
'domain' => null,
|
||||
'namespace' => 'App\\Admin\\Controllers',
|
||||
'middleware' => [
|
||||
// 'admin.autoSetLocale',
|
||||
// 'admin.auth',
|
||||
// 'admin.bootstrap',
|
||||
// AdminPermission::class,
|
||||
// 'sanctum',
|
||||
// 'substitute',
|
||||
'admin'
|
||||
],
|
||||
'middleware' => ['admin'],
|
||||
// 不包含额外路由, 配置后, 不会追加新增/详情/编辑页面路由
|
||||
'without_extra_routes' => [
|
||||
'/dashboard',
|
||||
|
|
@ -78,10 +70,10 @@ return [
|
|||
'https' => env('ADMIN_HTTPS', false),
|
||||
|
||||
// 是否显示 [开发者工具]
|
||||
'show_development_tools' => env('ADMIN_SHOW_DEVELOPMENT_TOOLS', true),
|
||||
'show_development_tools' => env('ADMIN_SHOW_DEVELOPMENT_TOOLS', false),
|
||||
|
||||
// 是否显示 [权限] 功能中的自动生成按钮
|
||||
'show_auto_generate_permission_button' => env('ADMIN_SHOW_AUTO_GENERATE_PERMISSION_BUTTON', true),
|
||||
'show_auto_generate_permission_button' => env('ADMIN_SHOW_AUTO_GENERATE_PERMISSION_BUTTON', false),
|
||||
|
||||
// 扩展
|
||||
'extension' => [
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ return [
|
|||
|
|
||||
*/
|
||||
|
||||
'default' => env('FILESYSTEM_DISK', 'local'),
|
||||
'default' => env('FILESYSTEM_DISK', 'public'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ class AdminPermissionSeeder extends Seeder
|
|||
$this->createPermission([
|
||||
'name' => $name,
|
||||
'slug' => $item['slug'].'.'.$key,
|
||||
'url' => null
|
||||
], $permission->id, $menu);
|
||||
}
|
||||
}
|
||||
|
|
@ -77,12 +76,14 @@ class AdminPermissionSeeder extends Seeder
|
|||
{
|
||||
$slug = data_get($item, 'slug');
|
||||
$url = data_get($item, 'url');
|
||||
$method = data_get($item, 'method');
|
||||
$permission = AdminPermission::create([
|
||||
'parent_id' => $pid,
|
||||
'custom_order' => data_get($item, 'custom_order', 0),
|
||||
'name' => data_get($item, 'name'),
|
||||
'slug' => $slug,
|
||||
'http_path' => $url ? [$url] : null,
|
||||
'http_path' => $url ? (is_array($url) ? $url : [$url]) : null,
|
||||
'http_method' => $method ? (is_array($method) ? $method : [$method]) : null,
|
||||
]);
|
||||
if ($menu) {
|
||||
$menu_has_permissions = [
|
||||
|
|
|
|||
|
|
@ -15,5 +15,6 @@ class DatabaseSeeder extends Seeder
|
|||
{
|
||||
$this->call(AdminPermissionSeeder::class);
|
||||
$this->call(AdminSeeder::class);
|
||||
$this->call(KeywordSeeder::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Keyword;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class KeywordSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
Keyword::truncate();
|
||||
|
||||
$list = [
|
||||
['key' => 'product_category', 'name' => '商品分类', 'children' => [
|
||||
['name' => '家用电器', 'children' => [
|
||||
['name' => '电视'],
|
||||
['name' => '冰箱'],
|
||||
['name' => '洗衣机'],
|
||||
]],
|
||||
['name' => '手机数码', 'children' => [
|
||||
['name' => '手机'],
|
||||
['name' => '手机配件'],
|
||||
['name' => '摄影摄像'],
|
||||
]],
|
||||
['name' => '电脑办公', 'children' => [
|
||||
['name' => '电脑整机'],
|
||||
['name' => '外设产品'],
|
||||
['name' => '网络产品'],
|
||||
]]
|
||||
]],
|
||||
['key' => 'article_category', 'name' => '文章分类', 'children' => [
|
||||
['name' => '后端'],
|
||||
['name' => '前端'],
|
||||
['name' => 'Android'],
|
||||
['name' => 'IOS'],
|
||||
['name' => '开发工具'],
|
||||
['name' => '人工智能'],
|
||||
]]
|
||||
];
|
||||
|
||||
$this->createByTree($list);
|
||||
}
|
||||
|
||||
protected function createByTree($list, $parent = null)
|
||||
{
|
||||
foreach ($list as $index => $item) {
|
||||
$params = Arr::except($item, ['children']);
|
||||
$params['sort'] = $index + 1;
|
||||
$params['parent_id'] = $parent ? $parent->id : 0;
|
||||
$params['key'] = data_get($item, 'key', data_get($parent, 'key') . '_' . $index);
|
||||
$model = Keyword::create($params);
|
||||
|
||||
if ($children = data_get($item, 'children')) {
|
||||
$this->createByTree($children, $model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,10 +8,11 @@ return [
|
|||
'parent_id' => '上级',
|
||||
'type_key' => '上级',
|
||||
'path' => '上级',
|
||||
'sort' => '排序(倒序)',
|
||||
'sort' => '排序',
|
||||
'level' => '层级',
|
||||
'options' => '扩展',
|
||||
'image' => '图片',
|
||||
'images' => '图片集',
|
||||
'description' => '描述',
|
||||
'content' => '内容',
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in New Issue