generated from liutk/owl-admin-base
0.6
parent
9de912f7e5
commit
1c228d21e1
|
|
@ -40,6 +40,7 @@ class FriendLinkController extends AdminController
|
|||
amis()->TableColumn('link', __('admin.friend_links.link')),
|
||||
amis()->TableColumn('cover_url', __('admin.friend_links.cover'))->type('image')->height('50px')->width('250px')->enlargeAble(true),
|
||||
// amis()->TableColumn('description', __('admin.project_cates.description')),
|
||||
amis()->TableColumn('is_enable', __('admin.friend_links.is_enable'))->type('switch'),
|
||||
amis()->TableColumn('created_at', __('admin.created_at'))->set('type', 'datetime')->sortable()->width('150px'),
|
||||
amis()->Operation()->label(__('admin.actions'))->buttons([
|
||||
$this->rowEditTypeButton('drawer', 'md'),
|
||||
|
|
@ -60,6 +61,7 @@ class FriendLinkController extends AdminController
|
|||
Components::make()->cropImageControl('cover', __('admin.friend_links.cover'))->required(true),
|
||||
amis()->TextareaControl('description', __('admin.friend_links.description')),
|
||||
Components::make()->sortControl('sort', __('admin.friend_links.sort')),
|
||||
amis()->SwitchControl('is_enable', __('admin.friend_links.is_enable'))->value(false),
|
||||
])
|
||||
]),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ class ProjectCateController extends AdminController
|
|||
amis()->TableColumn('title', __('admin.project_cates.title')),
|
||||
amis()->TableColumn('cover_url', __('admin.project_cates.cover'))->type('image')->height('50px')->width('250px')->enlargeAble(true),
|
||||
// amis()->TableColumn('description', __('admin.project_cates.description')),
|
||||
amis()->TableColumn('is_enable', __('admin.project_cates.is_enable'))->type('switch'),
|
||||
amis()->TableColumn('created_at', __('admin.created_at'))->set('type', 'datetime')->sortable()->width('150px'),
|
||||
amis()->Operation()->label(__('admin.actions'))->buttons([
|
||||
$this->rowEditTypeButton('drawer', 'md'),
|
||||
|
|
@ -58,6 +59,7 @@ class ProjectCateController extends AdminController
|
|||
Components::make()->cropImageControl('cover', __('admin.project_cates.cover'), 1.68)->required(true),
|
||||
amis()->TextareaControl('description', __('admin.project_cates.description')),
|
||||
Components::make()->sortControl('sort', __('admin.project_cates.sort')),
|
||||
amis()->SwitchControl('is_enable', __('admin.project_cates.is_enable'))->value(false),
|
||||
])
|
||||
]),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class BizException extends Exception
|
||||
{
|
||||
public function __construct(string $message, int $code = 400)
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于响应的 HTTP 状态代码
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $status = 200;
|
||||
|
||||
/**
|
||||
* 设置用于响应的 HTTP 状态代码
|
||||
*
|
||||
* @param int $status
|
||||
* @return $this
|
||||
*/
|
||||
public function status(int $status)
|
||||
{
|
||||
$this->status = $status;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 报告异常
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function report()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\CaptchaService;
|
||||
use Gregwar\Captcha\CaptchaBuilder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CaptchaController extends Controller
|
||||
{
|
||||
/**
|
||||
* 创建图形验证码
|
||||
*/
|
||||
public function store(Request $request, CaptchaService $captchaService)
|
||||
{
|
||||
$request->validate([
|
||||
'key' => ['bail', 'filled', 'string', 'max:32'],
|
||||
'w' => ['bail', 'int'],
|
||||
'h' => ['bail', 'int'],
|
||||
]);
|
||||
|
||||
$builder = $this->builder();
|
||||
$builder->build($request->input('w', 150), $request->input('h', 40));
|
||||
|
||||
$captchaService->put(
|
||||
$key = $request->input('key', Str::random(16)),
|
||||
$builder->getPhrase()
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'key' => $key,
|
||||
'img' => $builder->inline(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看图形验证码
|
||||
*
|
||||
* @param string $key
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \App\Services\CaptchaService $captchaService
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($key, Request $request, CaptchaService $captchaService)
|
||||
{
|
||||
$builder = $this->builder();
|
||||
$builder->build(
|
||||
(int) $request->query('w', 150),
|
||||
(int) $request->query('h', 40),
|
||||
);
|
||||
|
||||
if (strlen($key) <= 32) {
|
||||
$captchaService->put($key, $builder->getPhrase());
|
||||
}
|
||||
|
||||
return response($builder->get())
|
||||
->header('Content-Type', 'image/jpeg')
|
||||
->header('Cache-Control', 'no-cache');
|
||||
}
|
||||
|
||||
/**
|
||||
* 图形验证码生成器
|
||||
*
|
||||
* @return \Gregwar\Captcha\CaptchaBuilder
|
||||
*/
|
||||
protected function builder(): CaptchaBuilder
|
||||
{
|
||||
return new CaptchaBuilder(Str::random(5));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\PaginatorTrait;
|
||||
use App\Models\Filters\ProjectArticleFilter;
|
||||
use App\Http\Resources\ProjectChildrenResource;
|
||||
use App\Models\ProjectArticle;
|
||||
|
||||
class ProjectChildrenController extends Controller
|
||||
{
|
||||
use PaginatorTrait;
|
||||
|
||||
public function index(Request $request){
|
||||
$query = ProjectArticle::filter($request->all(), ProjectArticleFilter::class)->sort();
|
||||
$list = $query->childrens()->show()->sort()->paginate($this->resolvePerPage('per_page', 20));
|
||||
|
||||
return $this->json(ProjectChildrenResource::collection($list));
|
||||
}
|
||||
|
||||
public function show(ProjectArticle $children){
|
||||
request()->merge(['include_content' => true]);
|
||||
return $this->json(ProjectChildrenResource::make($children));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\PaginatorTrait;
|
||||
use App\Models\ProjectCate;
|
||||
use App\Models\Filters\ProjectCateFilter;
|
||||
use App\Http\Resources\ProjectResource;
|
||||
use App\Models\ProjectArticle;
|
||||
|
||||
class ProjectController extends Controller
|
||||
{
|
||||
use PaginatorTrait;
|
||||
|
||||
public function index(Request $request){
|
||||
$query = ProjectCate::filter($request->all(), ProjectCateFilter::class)->sort();
|
||||
$list = $query->show()->sort()->paginate($this->resolvePerPage('per_page', 20));
|
||||
|
||||
return $this->json(ProjectResource::collection($list));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProjectChildrenResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'title' => $this->title,
|
||||
'cover' => $this->cover,
|
||||
'description' => $this->description,
|
||||
'content' => $this->when($request->boolean('include_content'), $this->content),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProjectResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'title' => $this->title,
|
||||
'cover' => $this->cover,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -32,4 +32,14 @@ class FriendLink extends Model
|
|||
get: fn($value) => $this->cover ? (Str::startsWith($this->cover, ['http://', 'https://']) ? $this->cover : Storage::url($this->cover)) : null,
|
||||
);
|
||||
}
|
||||
|
||||
public function scopeShow($q){
|
||||
$q->where('is_enable', true);
|
||||
}
|
||||
|
||||
public function scopeSort($q)
|
||||
{
|
||||
$q->orderBy('sort', 'asc')
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,11 @@ class ProjectArticle extends Model
|
|||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
public function scopeChildrens($q)
|
||||
{
|
||||
$q->where('type', self::TYPE_ARTICLE);
|
||||
}
|
||||
|
||||
protected function tags():Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
|
|
|
|||
|
|
@ -32,4 +32,14 @@ class ProjectCate extends Model
|
|||
get: fn($value) => $this->cover ? (Str::startsWith($this->cover, ['http://', 'https://']) ? $this->cover : Storage::url($this->cover)) : null,
|
||||
);
|
||||
}
|
||||
|
||||
public function scopeShow($q){
|
||||
$q->where('is_enable', true);
|
||||
}
|
||||
|
||||
public function scopeSort($q)
|
||||
{
|
||||
$q->orderBy('sort', 'asc')
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Exceptions\BizException;
|
||||
use Illuminate\Contracts\Cache\Repository as Cache;
|
||||
|
||||
class CaptchaService
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $cachePrefix = 'captchas_';
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Contracts\Cache\Repository $cache
|
||||
*/
|
||||
public function __construct(
|
||||
protected Cache $cache,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将验证码存入缓存中
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $phrase
|
||||
* @param integer $ttl
|
||||
* @return void
|
||||
*/
|
||||
public function put(string $key, string $phrase, int $ttl = 300): void
|
||||
{
|
||||
$this->cache->put($this->cacheKey($key), $phrase, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验验证码是否正确
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $phrase
|
||||
* @return bool
|
||||
*/
|
||||
public function testPhrase(string $key, string $phrase): bool
|
||||
{
|
||||
if ($phrase === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = (string) $this->cache->pull(
|
||||
$this->cacheKey($key)
|
||||
);
|
||||
|
||||
return strtolower($value) === strtolower($phrase);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验验证码是否正确
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $phrase
|
||||
* @return void
|
||||
*
|
||||
* @throws \App\Exceptions\BizException
|
||||
*/
|
||||
public function validatePhrase(string $key, string $phrase): void
|
||||
{
|
||||
if (! $this->testPhrase($key, $phrase)) {
|
||||
throw new BizException(__('Invalid captcha'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成验证码缓存的 key
|
||||
*
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
protected function cacheKey(string $key): string
|
||||
{
|
||||
return $this->cachePrefix.$key;
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,11 @@ trait UploadTrait
|
|||
switch($file['state']){
|
||||
case 'init':
|
||||
if(strpos($file['value'], 'temporary') !== false){
|
||||
$filePath = $path.'/'.($file['name'] ?? $file['id']);
|
||||
if(!isset($file['name'])){
|
||||
$filePathInfo = pathinfo($file['value']);
|
||||
$file['name'] = $filePathInfo['basename'];
|
||||
}
|
||||
$filePath = $path.'/'.$file['name'];
|
||||
Storage::disk(Admin::config('admin.upload.disk'))->move($file['value'], $filePath);
|
||||
$fileArr[] = Storage::disk(Admin::config('admin.upload.disk'))->url($filePath);
|
||||
}else{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"require": {
|
||||
"php": "^8.1",
|
||||
"alphasnow/aliyun-oss-laravel": "^4.7",
|
||||
"gregwar/captcha": "^1.3",
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"laravel/framework": "^10.10",
|
||||
"laravel/sanctum": "^3.3",
|
||||
|
|
|
|||
|
|
@ -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": "6ce90738fadc40a447dfead6b131ec62",
|
||||
"content-hash": "097769e6f2cd7e3bab775e47a9cce358",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aliyuncs/oss-sdk-php",
|
||||
|
|
@ -599,6 +599,64 @@
|
|||
],
|
||||
"time": "2023-11-12T22:16:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gregwar/captcha",
|
||||
"version": "v1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Gregwar/Captcha.git",
|
||||
"reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Gregwar/Captcha/zipball/4edbcd09fde4353b94ce550f43460eba73baf2cc",
|
||||
"reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-fileinfo": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=5.3.0",
|
||||
"symfony/finder": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6.4 || ^7.0 || ^8.0 || ^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Gregwar\\": "src/Gregwar"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Grégoire Passault",
|
||||
"email": "g.passault@gmail.com",
|
||||
"homepage": "http://www.gregwar.com/"
|
||||
},
|
||||
{
|
||||
"name": "Jeremy Livingston",
|
||||
"email": "jeremy.j.livingston@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Captcha generator",
|
||||
"homepage": "https://github.com/Gregwar/Captcha",
|
||||
"keywords": [
|
||||
"bot",
|
||||
"captcha",
|
||||
"spam"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Gregwar/Captcha/issues",
|
||||
"source": "https://github.com/Gregwar/Captcha/tree/v1.3.0"
|
||||
},
|
||||
"time": "2025-06-23T12:25:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "7.8.1",
|
||||
|
|
@ -6575,5 +6633,5 @@
|
|||
"php": "^8.1"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ return new class extends Migration
|
|||
$table->string('cover')->nullable()->comment('封面');
|
||||
$table->unsignedInteger('sort')->default(0)->comment('排序');
|
||||
$table->text('content')->nullable()->comment('内容');
|
||||
$table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ return new class extends Migration
|
|||
$table->string('cover')->nullable()->comment('封面');
|
||||
$table->unsignedInteger('sort')->default(0)->comment('排序');
|
||||
$table->string('link')->nullable()->comment('链接地址');
|
||||
$table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,7 +324,8 @@ return [
|
|||
'description'=> '简介',
|
||||
'content' => '内容',
|
||||
'cover' =>'封面',
|
||||
'sort' => '排序'
|
||||
'sort' => '排序',
|
||||
'is_enable' => '显示',
|
||||
],
|
||||
'project_articles' => [
|
||||
'id' => '主键ID',
|
||||
|
|
@ -350,6 +351,7 @@ return [
|
|||
'content' => '内容',
|
||||
'cover' =>'封面',
|
||||
'sort' => '排序',
|
||||
'is_enable' => '显示',
|
||||
'link'=>'链接地址'
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
|
@ -19,5 +21,12 @@ Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
|
|||
});
|
||||
|
||||
Route::middleware('api')->group(function () {
|
||||
Route::get('/ads', [App\Http\Controllers\Api\AdController::class, 'index']);
|
||||
Route::post('captchas', [CaptchaController::class, 'store']);
|
||||
Route::get('captchas/{captcha}', [CaptchaController::class, 'show']);
|
||||
|
||||
Route::get('/ads', [AdController::class, 'index']);
|
||||
Route::get('/project_cates', [ProjectController::class, 'index']);
|
||||
Route::get('/project_childrens', [ProjectChildrenController::class, 'index']);
|
||||
Route::get('/project_childrens/{children}', [ProjectChildrenController::class, 'show']);
|
||||
|
||||
});
|
||||
Loading…
Reference in New Issue