Compare commits
200 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38d52c4609 | ||
|
|
2b3f31a204 | ||
|
|
94332ee597 | ||
|
|
aa6dd044ba | ||
|
|
aa9aa31c42 | ||
|
|
bbdb1fb39d | ||
|
|
b3f3594cd5 | ||
|
|
c0504fe62f | ||
|
|
0bc23c796d | ||
|
|
011b291e05 | ||
|
|
effe173d9c | ||
|
|
bdd440d38f | ||
|
|
fe5e4d9a67 | ||
|
|
66d7a0dce1 | ||
|
|
4f13d7d5a1 | ||
|
|
093ef71c2c | ||
|
|
4a87a90d5b | ||
|
|
17cb901046 | ||
|
|
c0ba47d47d | ||
|
|
1d0cb15854 | ||
|
|
465ff63230 | ||
|
|
04a421d3eb | ||
|
|
2642719769 | ||
|
|
4de97fd91e | ||
|
|
ee93913aac | ||
|
|
e54c4e551c | ||
|
|
743409726f | ||
|
|
2fa82cc231 | ||
|
|
dd4c40d846 | ||
|
|
8acf78dac4 | ||
|
|
eb7c051512 | ||
|
|
5ec90a08a1 | ||
|
|
911275c13b | ||
|
|
704a15896d | ||
|
|
c80b92b346 | ||
|
|
67fc980968 | ||
|
|
05af7dffb8 | ||
|
|
ee068513c6 | ||
|
|
fbb022c877 | ||
|
|
2b90d5eb75 | ||
|
|
edb36f8a92 | ||
|
|
a5bbb26ec8 | ||
|
|
9394e590a8 | ||
|
|
0cb84a9662 | ||
|
|
bb37a11bfb | ||
|
|
d5230acdb3 | ||
|
|
c66e58353a | ||
|
|
6661f35a15 | ||
|
|
5a8eb833be | ||
|
|
1925a1ae7a | ||
|
|
bb9ef6e267 | ||
|
|
923f567e0a | ||
|
|
62809f5300 | ||
|
|
c46207c278 | ||
|
|
289ecffbb1 | ||
|
|
2fdb10a60f | ||
|
|
b2b1693a2f | ||
|
|
b6f5f2405b | ||
|
|
f49f52dc34 | ||
|
|
cd1436add2 | ||
|
|
aefbbda2bf | ||
|
|
768ca9f24a | ||
|
|
fb9c390bc7 | ||
|
|
a4a60f13a0 | ||
|
|
5071c3a904 | ||
|
|
2c52c87c95 | ||
|
|
3161394a83 | ||
|
|
8f6da67f4f | ||
|
|
4d3bfed846 | ||
|
|
2086daf1ae | ||
|
|
a8ab0c6680 | ||
|
|
8b5bf74aa2 | ||
|
|
c0513f85a1 | ||
|
|
8f0db089af | ||
|
|
d705542f44 | ||
|
|
4266fd60b7 | ||
|
|
315b5b8296 | ||
|
|
10699d69f6 | ||
|
|
58da33d3c9 | ||
|
|
20871efb5c | ||
|
|
912e3747ee | ||
|
|
fba0d77e7b | ||
|
|
10dea5cffd | ||
|
|
f7983a2f21 | ||
|
|
8ab428c593 | ||
|
|
fb5f83f43c | ||
|
|
73750890d2 | ||
|
|
3ad7e711be | ||
|
|
b6fd41841b | ||
|
|
b61db2b31a | ||
|
|
cff42566c8 | ||
|
|
e44fabbd31 | ||
|
|
3cdf495bef | ||
|
|
6291acbcee | ||
|
|
1434d6fa1c | ||
|
|
73c55b1a77 | ||
|
|
8780a21fe7 | ||
|
|
3acabd7b38 | ||
|
|
1f826fd652 | ||
|
|
8d266b3d5a | ||
|
|
02b9695882 | ||
|
|
5bba6d0d52 | ||
|
|
52f9c0cbe8 | ||
|
|
d2b4910196 | ||
|
|
9a5cbb2ea7 | ||
|
|
b9a3ea2c44 | ||
|
|
0d826042ad | ||
|
|
f9a84c149c | ||
|
|
798e72f634 | ||
|
|
dec4e6fdb7 | ||
|
|
3cecc20f44 | ||
|
|
86d67450ea | ||
|
|
aa9887715a | ||
|
|
fc1c2095a6 | ||
|
|
a0d216fb2d | ||
|
|
b8471f2ca2 | ||
|
|
b7601272dd | ||
|
|
184dd51122 | ||
|
|
3df02550c4 | ||
|
|
f9b046a32f | ||
|
|
01c850739a | ||
|
|
43bb7792ac | ||
|
|
6c31ace31a | ||
|
|
e9050f4b9b | ||
|
|
a2a45e72ba | ||
|
|
317c2ea369 | ||
|
|
df2ed46ab2 | ||
|
|
979b628f59 | ||
|
|
71924b0397 | ||
|
|
b33c309a56 | ||
|
|
ae785cc56f | ||
|
|
66423b1d18 | ||
|
|
ab21fb203f | ||
|
|
31503d340a | ||
|
|
165635bce9 | ||
|
|
45a639fe3e | ||
|
|
b22a334b86 | ||
|
|
4be12d828d | ||
|
|
683a0a4888 | ||
|
|
769eb4bbd5 | ||
|
|
10921b34fc | ||
|
|
ede1ec5344 | ||
|
|
6f6403165c | ||
|
|
43b54a05ca | ||
|
|
b1b5bd0782 | ||
|
|
b2a4c5b971 | ||
|
|
b86d5053f2 | ||
|
|
aa4fd1c80a | ||
|
|
ed48d6ca75 | ||
|
|
97a8c74e22 | ||
|
|
8d79647974 | ||
|
|
07cd115048 | ||
|
|
e227e5acd6 | ||
|
|
2fb3eba233 | ||
|
|
dde0e988f8 | ||
|
|
32a9c2e85c | ||
|
|
5bd4e81ec5 | ||
|
|
d428d535f5 | ||
|
|
3b1d566973 | ||
|
|
659afb6a50 | ||
|
|
59c490b5d3 | ||
|
|
f1af71d3f3 | ||
|
|
2511fd6abb | ||
|
|
b2663b8ec0 | ||
|
|
eee6346bec | ||
|
|
6edee6b783 | ||
|
|
e526d0b4c8 | ||
|
|
37c6ccd29d | ||
|
|
b0c6a6defa | ||
|
|
3badd7f7a3 | ||
|
|
96ba030b03 | ||
|
|
54d421f93b | ||
|
|
9495179f96 | ||
|
|
32f629bac9 | ||
|
|
a9650b6780 | ||
|
|
08e016e8b0 | ||
|
|
bcffb4c8fc | ||
|
|
985af20b5b | ||
|
|
0c8e4f20c3 | ||
|
|
86cc72f27a | ||
|
|
bf26cb6699 | ||
|
|
928727c149 | ||
|
|
db9d878fe2 | ||
|
|
8663fb4134 | ||
|
|
7464decb8e | ||
|
|
7d5df4cfba | ||
|
|
03f0544ff4 | ||
|
|
ca5a215fc9 | ||
|
|
4ba44d7a16 | ||
|
|
476d797191 | ||
|
|
1714e7c876 | ||
|
|
a3acf85199 | ||
|
|
6d0631b494 | ||
|
|
d465172509 | ||
|
|
f2089c96ca | ||
|
|
e9e2a1eb0e | ||
|
|
51b2682dd0 | ||
|
|
d0bd143e17 | ||
|
|
aab42fb630 | ||
|
|
2389f7b39b |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,3 +17,4 @@ npm-debug.log
|
|||||||
yarn-error.log
|
yarn-error.log
|
||||||
/.idea
|
/.idea
|
||||||
/.vscode
|
/.vscode
|
||||||
|
/public/i
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -12,12 +12,18 @@
|
|||||||
[](https://github.com/lsky-org/lsky-pro/commits/dev)
|
[](https://github.com/lsky-org/lsky-pro/commits/dev)
|
||||||
[](https://github.com/lsky-org/lsky-pro/blob/master/LICENSE)
|
[](https://github.com/lsky-org/lsky-pro/blob/master/LICENSE)
|
||||||
|
|
||||||
[官网](https://www.lsky.pro)
|
[官网](https://www.lsky.pro) ·
|
||||||
[文档](https://docs.lsky.pro)
|
[文档](https://docs.lsky.pro) ·
|
||||||
[演示](https://pic.iqy.ink)
|
[社区](https://github.com/lsky-org/lsky-pro/discussions) ·
|
||||||
|
[演示](https://pic.vv1234.cn) ·
|
||||||
[Telegram 群组](https://t.me/lsky_pro)
|
[Telegram 群组](https://t.me/lsky_pro)
|
||||||
|
|
||||||
> 正式版本请点击 [这里](https://github.com/lsky-org/lsky-pro/releases) 下载,发现 bug 请提交 [issues](https://github.com/lsky-org/lsky-pro/issues) (提问前建议阅读[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md))
|
> [!WARNING]
|
||||||
|
> 开源版本已停止维护,不再进行新特性更新和 bug 修复。
|
||||||
|
|
||||||
|
> master 分支为未安装三方拓展的版本,通常包含了最新未发布版本的一些实验性新特性和修复补丁,正式版本请点击 [这里](https://github.com/lsky-org/lsky-pro/releases) 下载。
|
||||||
|
> 发现 bug 请提交 [issues](https://github.com/lsky-org/lsky-pro/issues) (提问前建议阅读[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md))
|
||||||
|
> 有任何想法、建议、或分享,请移步 [社区](https://github.com/lsky-org/lsky-pro/discussions)
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
@@ -51,6 +57,7 @@
|
|||||||
- exec、shell_exec 函数
|
- exec、shell_exec 函数
|
||||||
- readlink、symlink 函数
|
- readlink、symlink 函数
|
||||||
- putenv、getenv 函数
|
- putenv、getenv 函数
|
||||||
|
- chmod、chown、fileperms 函数
|
||||||
|
|
||||||
### 😋 鸣谢
|
### 😋 鸣谢
|
||||||
- [Laravel](https://laravel.com)
|
- [Laravel](https://laravel.com)
|
||||||
|
|||||||
58
app/Console/Commands/MakeThumbnails.php
Normal file
58
app/Console/Commands/MakeThumbnails.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Image;
|
||||||
|
use App\Services\ImageService;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use League\Flysystem\FilesystemException;
|
||||||
|
use Symfony\Component\Console\Helper\ProgressBar;
|
||||||
|
|
||||||
|
class MakeThumbnails extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'lsky:thumbnails';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Make images thumbnails.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$progress = new ProgressBar($this->output, Image::query()->count());
|
||||||
|
$progress->setMessage('获取图片处理中...');
|
||||||
|
$progress->start();
|
||||||
|
|
||||||
|
$service = new ImageService();
|
||||||
|
|
||||||
|
/** @var Image $image */
|
||||||
|
foreach (Image::query()->whereNotNull('strategy_id')->cursor() as $image) {
|
||||||
|
try {
|
||||||
|
$service->makeThumbnail(
|
||||||
|
image: $image,
|
||||||
|
data: $image->filesystem()->read($image->pathname),
|
||||||
|
force: true,
|
||||||
|
);
|
||||||
|
$progress->advance();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->error("缩略图生成失败, {$e->getMessage()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$progress->finish();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,4 +54,10 @@ final class GroupConfigKey
|
|||||||
|
|
||||||
/** @var string 图片缓存时间 */
|
/** @var string 图片缓存时间 */
|
||||||
const ImageCacheTtl = 'image_cache_ttl';
|
const ImageCacheTtl = 'image_cache_ttl';
|
||||||
|
|
||||||
|
/** @var string 图片保存格式 */
|
||||||
|
const ImageSaveFormat = 'image_save_format';
|
||||||
|
|
||||||
|
/** @var string 图片保存质量 */
|
||||||
|
const ImageSaveQuality = 'image_save_quality';
|
||||||
}
|
}
|
||||||
|
|||||||
9
app/Enums/PastedAction.php
Normal file
9
app/Enums/PastedAction.php
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
final class PastedAction
|
||||||
|
{
|
||||||
|
const Upload = 2; // 直接上传
|
||||||
|
const Waiting = 1; // 等待上传
|
||||||
|
}
|
||||||
15
app/Enums/Scan/NsfwJsOption.php
Normal file
15
app/Enums/Scan/NsfwJsOption.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Scan;
|
||||||
|
|
||||||
|
final class NsfwJsOption
|
||||||
|
{
|
||||||
|
/** @var string 接口地址 */
|
||||||
|
const ApiUrl = 'api_url';
|
||||||
|
|
||||||
|
/** @var string 表单属性名称 */
|
||||||
|
const AttrName = 'attr_name';
|
||||||
|
|
||||||
|
/** @var string 阈值 */
|
||||||
|
const Threshold = 'threshold';
|
||||||
|
}
|
||||||
21
app/Enums/Scan/TencentOption.php
Normal file
21
app/Enums/Scan/TencentOption.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Scan;
|
||||||
|
|
||||||
|
final class TencentOption
|
||||||
|
{
|
||||||
|
/** @var string SecretId */
|
||||||
|
const SecretId = 'secret_id';
|
||||||
|
|
||||||
|
/** @var string SecretKey */
|
||||||
|
const SecretKey = 'secret_key';
|
||||||
|
|
||||||
|
/** @var string Region */
|
||||||
|
const Region = 'region';
|
||||||
|
|
||||||
|
/** @var string Endpoint */
|
||||||
|
const Endpoint = 'endpoint';
|
||||||
|
|
||||||
|
/** @var string 业务场景 */
|
||||||
|
const BizType = 'biz_type';
|
||||||
|
}
|
||||||
@@ -16,6 +16,12 @@ final class MinioOption
|
|||||||
/** @var string Endpoint */
|
/** @var string Endpoint */
|
||||||
const Endpoint = 'endpoint';
|
const Endpoint = 'endpoint';
|
||||||
|
|
||||||
|
/** @var string 区域 */
|
||||||
|
const Region = 'region';
|
||||||
|
|
||||||
/** @var string Bucket */
|
/** @var string Bucket */
|
||||||
const Bucket = 'bucket';
|
const Bucket = 'bucket';
|
||||||
|
|
||||||
|
/** @var string BucketEndpoint */
|
||||||
|
const BucketEndpoint = 'bucket_endpoint';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ final class S3Option
|
|||||||
/** @var string SecretAccessKey */
|
/** @var string SecretAccessKey */
|
||||||
const SecretAccessKey = 'secret_access_key';
|
const SecretAccessKey = 'secret_access_key';
|
||||||
|
|
||||||
|
/** @var string Endpoint */
|
||||||
|
const Endpoint = 'endpoint';
|
||||||
|
|
||||||
/** @var string 区域 */
|
/** @var string 区域 */
|
||||||
const Region = 'region';
|
const Region = 'region';
|
||||||
|
|
||||||
|
|||||||
@@ -15,4 +15,10 @@ final class WebDavOption
|
|||||||
|
|
||||||
/** @var string 密码 */
|
/** @var string 密码 */
|
||||||
const Password = 'password';
|
const Password = 'password';
|
||||||
|
|
||||||
|
/** @var string 认证方式 */
|
||||||
|
const AuthType = 'auth_type';
|
||||||
|
|
||||||
|
/** @var string 地址前缀 */
|
||||||
|
const Prefix = 'prefix';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ final class UserConfigKey
|
|||||||
/** @var string 默认权限 */
|
/** @var string 默认权限 */
|
||||||
const DefaultPermission = 'default_permission';
|
const DefaultPermission = 'default_permission';
|
||||||
|
|
||||||
|
/** @var string 图片粘贴后动作 */
|
||||||
|
const PastedAction = 'pasted_action';
|
||||||
|
|
||||||
/** @var string 上传是否自动清除预览 */
|
/** @var string 上传是否自动清除预览 */
|
||||||
const IsAutoClearPreview = 'is_auto_clear_preview';
|
const IsAutoClearPreview = 'is_auto_clear_preview';
|
||||||
}
|
}
|
||||||
|
|||||||
9
app/Enums/Watermark/Mode.php
Normal file
9
app/Enums/Watermark/Mode.php
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Watermark;
|
||||||
|
|
||||||
|
final class Mode
|
||||||
|
{
|
||||||
|
const Overlay = 1; // 覆盖原图
|
||||||
|
const Dynamic = 2; // 动态生成
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ class ConsoleController extends Controller
|
|||||||
|
|
||||||
$images = Image::query()
|
$images = Image::query()
|
||||||
->whereBetween('created_at', [$start->format($format), $end->format($format)])
|
->whereBetween('created_at', [$start->format($format), $end->format($format)])
|
||||||
->get()
|
->get(['user_id', 'created_at'])
|
||||||
->transform(function (Image $image) {
|
->transform(function (Image $image) {
|
||||||
$image['date'] = $image->created_at->format('Y-m-d');
|
$image['date'] = $image->created_at->format('Y-m-d');
|
||||||
return $image;
|
return $image;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use Illuminate\View\View;
|
|||||||
|
|
||||||
class GroupController extends Controller
|
class GroupController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct()
|
private function share()
|
||||||
{
|
{
|
||||||
\Illuminate\Support\Facades\View::share([
|
\Illuminate\Support\Facades\View::share([
|
||||||
'default' => Group::getDefaultConfigs(),
|
'default' => Group::getDefaultConfigs(),
|
||||||
@@ -28,20 +28,31 @@ class GroupController extends Controller
|
|||||||
|
|
||||||
public function index(Request $request): View
|
public function index(Request $request): View
|
||||||
{
|
{
|
||||||
$groups = Group::query()->when($request->query('keywords'), function (Builder $builder, $keywords) {
|
$keywords = $request->query('keywords');
|
||||||
|
$groups = Group::query()->when($keywords, function (Builder $builder, $keywords) {
|
||||||
$builder->where('name', 'like', "%{$keywords}%");
|
$builder->where('name', 'like', "%{$keywords}%");
|
||||||
})->withCount('users')->withCount('strategies')->latest()->paginate();
|
})->withCount('users')->withCount('strategies')->latest()->paginate();
|
||||||
|
|
||||||
|
$groups->appends(compact('keywords'));
|
||||||
|
|
||||||
|
$this->share();
|
||||||
|
|
||||||
return view('admin.group.index', compact('groups'));
|
return view('admin.group.index', compact('groups'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add(): View
|
public function add(): View
|
||||||
{
|
{
|
||||||
|
$this->share();
|
||||||
|
|
||||||
return view('admin.group.add');
|
return view('admin.group.add');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function edit(Request $request): View
|
public function edit(Request $request): View
|
||||||
{
|
{
|
||||||
$group = Group::query()->findOrFail($request->route('id'));
|
$group = Group::query()->findOrFail($request->route('id'));
|
||||||
|
|
||||||
|
$this->share();
|
||||||
|
|
||||||
return view('admin.group.edit', compact('group'));
|
return view('admin.group.edit', compact('group'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +64,8 @@ class GroupController extends Controller
|
|||||||
$group->save();
|
$group->save();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->share();
|
||||||
|
|
||||||
return $this->success('创建成功');
|
return $this->success('创建成功');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ class ImageController extends Controller
|
|||||||
{
|
{
|
||||||
public function index(Request $request): View
|
public function index(Request $request): View
|
||||||
{
|
{
|
||||||
|
$keywords = $request->query('keywords');
|
||||||
$images = Image::query()->with(['user' => function (BelongsTo $belongsTo) {
|
$images = Image::query()->with(['user' => function (BelongsTo $belongsTo) {
|
||||||
$belongsTo->withSum('images', 'size');
|
$belongsTo->withSum('images', 'size');
|
||||||
}, 'album', 'group', 'strategy'])->when($request->input('keywords'), function (Builder $builder, $keywords) {
|
}, 'album', 'group', 'strategy'])->when($keywords, function (Builder $builder, $keywords) {
|
||||||
$words = [];
|
$words = [];
|
||||||
$qualifiers = [
|
$qualifiers = [
|
||||||
'name:', 'album:', 'group:', 'strategy:', 'email:', 'extension:', 'md5:', 'sha1:', 'ip:', 'is:', 'order:',
|
'name:', 'album:', 'group:', 'strategy:', 'email:', 'extension:', 'md5:', 'sha1:', 'ip:', 'is:', 'order:',
|
||||||
@@ -38,8 +39,8 @@ class ImageController extends Controller
|
|||||||
'is:guest' => $builder->whereNull('user_id'),
|
'is:guest' => $builder->whereNull('user_id'),
|
||||||
'is:adminer' => $builder->whereHas('user', fn (Builder $builder) => $builder->where('is_adminer', 1)),
|
'is:adminer' => $builder->whereHas('user', fn (Builder $builder) => $builder->where('is_adminer', 1)),
|
||||||
'order:earliest' => $builder->orderBy('created_at'),
|
'order:earliest' => $builder->orderBy('created_at'),
|
||||||
'order:utmost' => $builder->orderBy('size'),
|
'order:utmost' => $builder->orderByDesc('size'),
|
||||||
'order:least' => $builder->orderByDesc('size'),
|
'order:least' => $builder->orderBy('size'),
|
||||||
default => 0,
|
default => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,16 +64,20 @@ class ImageController extends Controller
|
|||||||
});
|
});
|
||||||
|
|
||||||
foreach ($words as $word) {
|
foreach ($words as $word) {
|
||||||
$builder->where('origin_name', 'like', "%{$word}%")->orWhere('alias_name', 'like', "%{$word}%");
|
$builder->where('name', 'like', "%{$word}%")
|
||||||
|
->orWhere('origin_name', 'like', "%{$word}%")
|
||||||
|
->orWhere('alias_name', 'like', "%{$word}%");
|
||||||
}
|
}
|
||||||
})->latest()->paginate(40);
|
})->latest()->paginate(40);
|
||||||
$images->getCollection()->each(function (Image $image) {
|
$images->getCollection()->each(function (Image $image) {
|
||||||
$image->append('url', 'pathname');
|
$image->append('url', 'pathname', 'thumb_url');
|
||||||
$image->album?->setVisible(['name']);
|
$image->album?->setVisible(['name']);
|
||||||
$image->group?->setVisible(['name']);
|
$image->group?->setVisible(['name']);
|
||||||
$image->strategy?->setVisible(['name']);
|
$image->strategy?->setVisible(['name']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$images->appends(compact('keywords'));
|
||||||
|
|
||||||
return view('admin.image.index', compact('images'));
|
return view('admin.image.index', compact('images'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,13 @@ class StrategyController extends Controller
|
|||||||
{
|
{
|
||||||
public function index(Request $request): View
|
public function index(Request $request): View
|
||||||
{
|
{
|
||||||
$strategies = Strategy::query()->when($request->query('keywords'), function (Builder $builder, $keywords) {
|
$keywords = $request->query('keywords');
|
||||||
|
$strategies = Strategy::query()->when($keywords, function (Builder $builder, $keywords) {
|
||||||
$builder->where('name', 'like', "%{$keywords}%")->orWhere('intro', 'like', "%{$keywords}%");
|
$builder->where('name', 'like', "%{$keywords}%")->orWhere('intro', 'like', "%{$keywords}%");
|
||||||
})->withCount('images')->withSum('images', 'size')->latest()->paginate();
|
})->withCount('images')->withSum('images', 'size')->latest()->paginate();
|
||||||
|
|
||||||
|
$strategies->appends(compact('keywords'));
|
||||||
|
|
||||||
return view('admin.strategy.index', compact('strategies'));
|
return view('admin.strategy.index', compact('strategies'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,8 +63,12 @@ class StrategyController extends Controller
|
|||||||
|
|
||||||
public function delete(Request $request): Response
|
public function delete(Request $request): Response
|
||||||
{
|
{
|
||||||
if ($group = Strategy::query()->find($request->route('id'))) {
|
/** @var Strategy $strategy */
|
||||||
$group->delete();
|
if ($strategy = Strategy::query()->find($request->route('id'))) {
|
||||||
|
DB::transaction(function () use ($strategy) {
|
||||||
|
$strategy->images()->update(['strategy_id' => null]);
|
||||||
|
$strategy->delete();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return $this->success('删除成功');
|
return $this->success('删除成功');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,15 +19,19 @@ class UserController extends Controller
|
|||||||
public function index(Request $request): View
|
public function index(Request $request): View
|
||||||
{
|
{
|
||||||
$status = $request->query('status');
|
$status = $request->query('status');
|
||||||
|
$keywords = $request->query('keywords');
|
||||||
$users = User::query()->when($status > -1, function (Builder $builder) use ($status) {
|
$users = User::query()->when($status > -1, function (Builder $builder) use ($status) {
|
||||||
$builder->where('status', $status);
|
$builder->where('status', $status);
|
||||||
})->when($request->query('keywords'), function (Builder $builder, $keywords) {
|
})->when($keywords, function (Builder $builder, $keywords) {
|
||||||
$builder->where('name', 'like', "%{$keywords}%")->orWhere('email', 'like', "%{$keywords}%");
|
$builder->where('name', 'like', "%{$keywords}%")->orWhere('email', 'like', "%{$keywords}%");
|
||||||
})->with('group')->withSum('images', 'size')->latest()->paginate();
|
})->with('group')->withSum('images', 'size')->latest()->paginate();
|
||||||
$users->getCollection()->each(function (User $user) {
|
$users->getCollection()->each(function (User $user) {
|
||||||
$user->group->setVisible(['name']);
|
$user->group->setVisible(['name']);
|
||||||
});
|
});
|
||||||
$statuses = [-1 => '全部', 1 => '正常', 0 => '冻结'];
|
$statuses = [-1 => '全部', 1 => '正常', 0 => '冻结'];
|
||||||
|
|
||||||
|
$users->appends(compact('status', 'keywords'));
|
||||||
|
|
||||||
return view('admin.user.index', compact('users', 'statuses'));
|
return view('admin.user.index', compact('users', 'statuses'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,9 +47,7 @@ class UserController extends Controller
|
|||||||
$user = User::query()->findOrFail($request->route('id'));
|
$user = User::query()->findOrFail($request->route('id'));
|
||||||
$validated = $request->validated();
|
$validated = $request->validated();
|
||||||
|
|
||||||
if (empty($validated['password'])) {
|
if (! empty($validated['password'])) {
|
||||||
unset($validated['password']);
|
|
||||||
} else {
|
|
||||||
$user->forceFill([
|
$user->forceFill([
|
||||||
'password' => Hash::make($validated['password']),
|
'password' => Hash::make($validated['password']),
|
||||||
'remember_token' => Str::random(60),
|
'remember_token' => Str::random(60),
|
||||||
@@ -54,6 +56,7 @@ class UserController extends Controller
|
|||||||
event(new PasswordReset($user));
|
event(new PasswordReset($user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unset($validated['password']);
|
||||||
$user->fill($validated);
|
$user->fill($validated);
|
||||||
$user->group_id = $validated['group_id'];
|
$user->group_id = $validated['group_id'];
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Models\Image;
|
use App\Models\Image;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\ImageService;
|
use App\Services\ImageService;
|
||||||
|
use App\Services\UserService;
|
||||||
use App\Utils;
|
use App\Utils;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -76,7 +77,7 @@ class ImageController extends Controller
|
|||||||
{
|
{
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$user->images()->where('key', $request->route('key'))->delete();
|
(new UserService())->deleteImages([$request->route('key')], $user, 'key');
|
||||||
return $this->success('删除成功');
|
return $this->success('删除成功');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,6 @@ use Illuminate\Validation\Rules;
|
|||||||
|
|
||||||
class RegisteredUserController extends Controller
|
class RegisteredUserController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
if (! Utils::config(ConfigKey::IsEnableRegistration)) {
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the registration view.
|
* Display the registration view.
|
||||||
*
|
*
|
||||||
@@ -52,6 +45,7 @@ class RegisteredUserController extends Controller
|
|||||||
'name' => $request->name,
|
'name' => $request->name,
|
||||||
'email' => $request->email,
|
'email' => $request->email,
|
||||||
'password' => Hash::make($request->password),
|
'password' => Hash::make($request->password),
|
||||||
|
'registered_ip' => $request->ip(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (Utils::config(ConfigKey::IsUserNeedVerify)) {
|
if (Utils::config(ConfigKey::IsUserNeedVerify)) {
|
||||||
|
|||||||
@@ -2,20 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Common;
|
namespace App\Http\Controllers\Common;
|
||||||
|
|
||||||
use App\Enums\ConfigKey;
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Utils;
|
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
class ApiController extends Controller
|
class ApiController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
if (! Utils::config(ConfigKey::IsEnableApi)) {
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function index(): View
|
public function index(): View
|
||||||
{
|
{
|
||||||
return view('common.api');
|
return view('common.api');
|
||||||
|
|||||||
@@ -2,22 +2,13 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Common;
|
namespace App\Http\Controllers\Common;
|
||||||
|
|
||||||
use App\Enums\ConfigKey;
|
|
||||||
use App\Enums\ImagePermission;
|
use App\Enums\ImagePermission;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Image;
|
use App\Models\Image;
|
||||||
use App\Utils;
|
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
class GalleryController extends Controller
|
class GalleryController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
if (! Utils::config(ConfigKey::IsEnableGallery)) {
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function index(): View
|
public function index(): View
|
||||||
{
|
{
|
||||||
$images = Image::query()
|
$images = Image::query()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Enums\GroupConfigKey;
|
use App\Enums\GroupConfigKey;
|
||||||
use App\Enums\UserStatus;
|
use App\Enums\UserStatus;
|
||||||
|
use App\Enums\Watermark\Mode;
|
||||||
use App\Exceptions\UploadException;
|
use App\Exceptions\UploadException;
|
||||||
use App\Http\Result;
|
use App\Http\Result;
|
||||||
use App\Models\Group;
|
use App\Models\Group;
|
||||||
@@ -22,6 +23,7 @@ use Illuminate\Support\Facades\Artisan;
|
|||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
use Intervention\Image\Facades\Image as InterventionImage;
|
||||||
use League\Flysystem\FilesystemException;
|
use League\Flysystem\FilesystemException;
|
||||||
use Symfony\Component\Console\Output\BufferedOutput;
|
use Symfony\Component\Console\Output\BufferedOutput;
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
@@ -67,6 +69,10 @@ class Controller extends BaseController
|
|||||||
'name' => 'exec、shell_exec 函数',
|
'name' => 'exec、shell_exec 函数',
|
||||||
'intro' => '执行外部命令',
|
'intro' => '执行外部命令',
|
||||||
'result' => function_exists('exec') && function_exists('shell_exec'),
|
'result' => function_exists('exec') && function_exists('shell_exec'),
|
||||||
|
])->push([
|
||||||
|
'name' => 'chmod、chown、fileperms 函数',
|
||||||
|
'intro' => '设置和获取文件、文件夹权限函数',
|
||||||
|
'result' => function_exists('chmod') && function_exists('chown') && function_exists('fileperms'),
|
||||||
])->push([
|
])->push([
|
||||||
'name' => 'PHP >= 8.0.2',
|
'name' => 'PHP >= 8.0.2',
|
||||||
'intro' => '最低要求 PHP 8.0.2 版本',
|
'intro' => '最低要求 PHP 8.0.2 版本',
|
||||||
@@ -143,7 +149,7 @@ class Controller extends BaseController
|
|||||||
->where('key', $request->route('key'))
|
->where('key', $request->route('key'))
|
||||||
->where('extension', strtolower($request->route('extension')))
|
->where('extension', strtolower($request->route('extension')))
|
||||||
->firstOr(fn() => abort(404));
|
->firstOr(fn() => abort(404));
|
||||||
if (! $image->group->configs->get(GroupConfigKey::IsEnableOriginalProtection)) {
|
if (! $image->group?->configs->get(GroupConfigKey::IsEnableOriginalProtection)) {
|
||||||
abort(404);
|
abort(404);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -153,12 +159,18 @@ class Controller extends BaseController
|
|||||||
$contents = Cache::get($cacheKey);
|
$contents = Cache::get($cacheKey);
|
||||||
} else {
|
} else {
|
||||||
$contents = $image->filesystem()->read($image->pathname);
|
$contents = $image->filesystem()->read($image->pathname);
|
||||||
// 是否启用了水印功能,跳过gif图片
|
$configs = collect($image->group?->configs->get(GroupConfigKey::WatermarkConfigs));
|
||||||
if ($image->group->configs->get(GroupConfigKey::IsEnableWatermark) && $image->mimetype !== 'image/gif') {
|
|
||||||
$configs = $image->group->configs->get(GroupConfigKey::WatermarkConfigs);
|
// 是否启用了水印功能,跳过gif和ico图片
|
||||||
$contents = (string)$service->stickWatermark($contents, collect($configs))->encode();
|
if (
|
||||||
|
$image->group?->configs->get(GroupConfigKey::IsEnableWatermark) &&
|
||||||
|
$configs->get('mode', Mode::Overlay) == Mode::Dynamic &&
|
||||||
|
! in_array($image->extension, ['ico', 'gif', 'svg'])
|
||||||
|
) {
|
||||||
|
$quality = $image->group?->configs->get(GroupConfigKey::ImageSaveQuality, 75);
|
||||||
|
$contents = $service->stickWatermark($contents, $configs)->encode($image->extension, $quality)->getEncoded();
|
||||||
}
|
}
|
||||||
$cacheTtl = (int)$image->group->configs->get(GroupConfigKey::ImageCacheTtl, 0);
|
$cacheTtl = (int)$image->group?->configs->get(GroupConfigKey::ImageCacheTtl, 0);
|
||||||
// 是否启用了缓存
|
// 是否启用了缓存
|
||||||
if ($cacheTtl) {
|
if ($cacheTtl) {
|
||||||
Cache::remember($cacheKey, $cacheTtl, fn () => $contents);
|
Cache::remember($cacheKey, $cacheTtl, fn () => $contents);
|
||||||
@@ -167,51 +179,27 @@ class Controller extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (FilesystemException $e) {
|
} catch (FilesystemException $e) {
|
||||||
|
Utils::e($e, '图片输出时出现异常');
|
||||||
abort(404);
|
abort(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return \response()->stream(function () use ($contents) {
|
$mimetype = $image->mimetype;
|
||||||
echo $contents;
|
|
||||||
}, headers: ['Content-type' => $image->mimetype]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function thumbnail(Request $request): StreamedResponse
|
// ico svg 图片直接输出,不经过 InterventionImage 处理
|
||||||
{
|
if (in_array($image->extension, ['ico', 'svg'])) {
|
||||||
/** @var Image $image */
|
goto out;
|
||||||
$image = Image::query()
|
|
||||||
->where('key', $request->route('key'))
|
|
||||||
->where('extension', strtolower($request->route('extension')))
|
|
||||||
->firstOr(fn() => abort(404));
|
|
||||||
|
|
||||||
try {
|
|
||||||
$cacheKey = "image_thumb_{$image->key}";
|
|
||||||
|
|
||||||
if (Cache::has($cacheKey)) {
|
|
||||||
$contents = Cache::get($cacheKey);
|
|
||||||
} else {
|
|
||||||
$stream = $image->filesystem()->readStream($image->pathname);
|
|
||||||
$img = \Intervention\Image\Facades\Image::make($stream);
|
|
||||||
|
|
||||||
$width = $w = $image->width;
|
|
||||||
$height = $h = $image->height;
|
|
||||||
|
|
||||||
$max = 400; // 最大宽高
|
|
||||||
|
|
||||||
if ($w > $max && $h > $max) {
|
|
||||||
$scale = min($max / $w, $max / $h);
|
|
||||||
$width = (int)($w * $scale);
|
|
||||||
$height = (int)($h * $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
$contents = $img->fit($width, $height, fn($constraint) => $constraint->upsize())->encode();
|
|
||||||
Cache::rememberForever($cacheKey, fn () => (string)$contents);
|
|
||||||
}
|
|
||||||
} catch (FilesystemException $e) {
|
|
||||||
abort(404);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 浏览器无法预览的图片,改为 png 格式输出
|
||||||
|
if (in_array($image->extension, ['psd', 'tif', 'bmp'])) {
|
||||||
|
$mimetype = 'image/png';
|
||||||
|
$contents = InterventionImage::make($contents)->encode('png')->getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
return \response()->stream(function () use ($contents) {
|
return \response()->stream(function () use ($contents) {
|
||||||
echo $contents;
|
echo $contents;
|
||||||
}, headers: ['Content-type' => $image->mimetype]);
|
}, headers: ['Content-type' => $mimetype]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ class ImageController extends Controller
|
|||||||
|
|
||||||
$images = $user->images()->filter($request)->with('group', 'strategy')->paginate(40);
|
$images = $user->images()->filter($request)->with('group', 'strategy')->paginate(40);
|
||||||
$images->getCollection()->each(function (Image $image) {
|
$images->getCollection()->each(function (Image $image) {
|
||||||
|
// 图片宽高过小会导致前端排版异常
|
||||||
|
$image->width = max($image->width, 200);
|
||||||
|
$image->height = max($image->height, 200);
|
||||||
|
|
||||||
$image->human_date = $image->created_at->diffForHumans();
|
$image->human_date = $image->created_at->diffForHumans();
|
||||||
$image->date = $image->created_at->format('Y-m-d H:i:s');
|
$image->date = $image->created_at->format('Y-m-d H:i:s');
|
||||||
$image->append(['url', 'thumb_url', 'filename', 'links'])->setVisible([
|
$image->append(['url', 'thumb_url', 'filename', 'links'])->setVisible([
|
||||||
@@ -46,7 +50,7 @@ class ImageController extends Controller
|
|||||||
if (!$image = $user->images()->find($request->route('id'))) {
|
if (!$image = $user->images()->find($request->route('id'))) {
|
||||||
return $this->fail('未找到该图片');
|
return $this->fail('未找到该图片');
|
||||||
}
|
}
|
||||||
$image->strategy->setVisible(['name']);
|
$image->strategy?->setVisible(['name']);
|
||||||
$image->album?->setVisible(['name']);
|
$image->album?->setVisible(['name']);
|
||||||
$image->append(['url', 'thumb_url', 'filename', 'links'])->setVisible([
|
$image->append(['url', 'thumb_url', 'filename', 'links'])->setVisible([
|
||||||
'id', 'filename', 'origin_name', 'url', 'thumb_url', 'width', 'height', 'size', 'mimetype', 'md5', 'sha1',
|
'id', 'filename', 'origin_name', 'url', 'thumb_url', 'width', 'height', 'size', 'mimetype', 'md5', 'sha1',
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ class CheckIsEnableApi
|
|||||||
public function handle(Request $request, Closure $next)
|
public function handle(Request $request, Closure $next)
|
||||||
{
|
{
|
||||||
if (! Utils::config(ConfigKey::IsEnableApi)) {
|
if (! Utils::config(ConfigKey::IsEnableApi)) {
|
||||||
return $this->fail('管理员未启用 API')->setStatusCode(403);
|
if ($request->expectsJson()) {
|
||||||
|
return $this->fail('管理员未启用 API')->setStatusCode(403);
|
||||||
|
}
|
||||||
|
abort(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
|||||||
26
app/Http/Middleware/CheckIsEnableGallery.php
Normal file
26
app/Http/Middleware/CheckIsEnableGallery.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Enums\ConfigKey;
|
||||||
|
use App\Http\Result;
|
||||||
|
use App\Utils;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class CheckIsEnableGallery
|
||||||
|
{
|
||||||
|
use Result;
|
||||||
|
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
if (! Utils::config(ConfigKey::IsEnableGallery)) {
|
||||||
|
if ($request->expectsJson()) {
|
||||||
|
return $this->fail('管理员未启用画廊功能')->setStatusCode(403);
|
||||||
|
}
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/Http/Middleware/CheckIsEnableRegistration.php
Normal file
26
app/Http/Middleware/CheckIsEnableRegistration.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Enums\ConfigKey;
|
||||||
|
use App\Http\Result;
|
||||||
|
use App\Utils;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class CheckIsEnableRegistration
|
||||||
|
{
|
||||||
|
use Result;
|
||||||
|
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
if (! Utils::config(ConfigKey::IsEnableRegistration)) {
|
||||||
|
if ($request->expectsJson()) {
|
||||||
|
return $this->fail('站点管理员关闭了注册功能')->setStatusCode(403);
|
||||||
|
}
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ class TrustProxies extends Middleware
|
|||||||
*
|
*
|
||||||
* @var array<int, string>|string|null
|
* @var array<int, string>|string|null
|
||||||
*/
|
*/
|
||||||
protected $proxies;
|
protected $proxies = '*';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The headers that should be used to detect proxies.
|
* The headers that should be used to detect proxies.
|
||||||
|
|||||||
@@ -34,26 +34,39 @@ class GroupRequest extends FormRequest
|
|||||||
'configs.limit_per_day' => 'required|integer',
|
'configs.limit_per_day' => 'required|integer',
|
||||||
'configs.limit_per_week' => 'required|integer',
|
'configs.limit_per_week' => 'required|integer',
|
||||||
'configs.limit_per_month' => 'required|integer',
|
'configs.limit_per_month' => 'required|integer',
|
||||||
|
'configs.image_save_quality' => 'required|min:1|max:100',
|
||||||
|
'configs.image_save_format' => '',
|
||||||
'configs.path_naming_rule' => 'max:400',
|
'configs.path_naming_rule' => 'max:400',
|
||||||
'configs.file_naming_rule' => 'max:400',
|
'configs.file_naming_rule' => 'max:400',
|
||||||
'configs.accepted_file_suffixes' => 'required|array|in:jpeg,jpg,png,gif,tif,bmp,ico,psd,webp',
|
'configs.accepted_file_suffixes' => 'required|array|in:jpeg,jpg,png,gif,tif,bmp,ico,psd,webp,svg',
|
||||||
|
|
||||||
'configs.is_enable_scan' => 'boolean',
|
'configs.is_enable_scan' => 'boolean',
|
||||||
'configs.scanned_action' => [
|
'configs.scanned_action' => [
|
||||||
'exclude_if:configs.is_enable_scan,false',
|
'exclude_if:configs.is_enable_scan,false',
|
||||||
'in:mark,delete',
|
'in:mark,delete',
|
||||||
],
|
],
|
||||||
'configs.scan_configs.driver' => ['exclude_if:configs.is_enable_scan,false', 'in:aliyun'],
|
'configs.scan_configs.driver' => ['exclude_if:configs.is_enable_scan,false', 'in:tencent,aliyun,nsfwjs'],
|
||||||
|
'configs.scan_configs.drivers.tencent.endpoint' => [$requiredIfReview('tencent')],
|
||||||
|
'configs.scan_configs.drivers.tencent.secret_id' => [$requiredIfReview('tencent')],
|
||||||
|
'configs.scan_configs.drivers.tencent.secret_key' => [$requiredIfReview('tencent')],
|
||||||
|
'configs.scan_configs.drivers.tencent.region' => [$requiredIfReview('tencent')],
|
||||||
|
'configs.scan_configs.drivers.tencent.biz_type' => '',
|
||||||
|
|
||||||
'configs.scan_configs.drivers.aliyun.access_key_id' => [$requiredIfReview('aliyun')],
|
'configs.scan_configs.drivers.aliyun.access_key_id' => [$requiredIfReview('aliyun')],
|
||||||
'configs.scan_configs.drivers.aliyun.access_key_secret' => [$requiredIfReview('aliyun')],
|
'configs.scan_configs.drivers.aliyun.access_key_secret' => [$requiredIfReview('aliyun')],
|
||||||
'configs.scan_configs.drivers.aliyun.biz_type' => [$requiredIfReview('aliyun')],
|
|
||||||
'configs.scan_configs.drivers.aliyun.region_id' => [$requiredIfReview('aliyun')],
|
'configs.scan_configs.drivers.aliyun.region_id' => [$requiredIfReview('aliyun')],
|
||||||
|
'configs.scan_configs.drivers.aliyun.biz_type' => '',
|
||||||
'configs.scan_configs.drivers.aliyun.scenes' => [$requiredIfReview('aliyun'), 'array'],
|
'configs.scan_configs.drivers.aliyun.scenes' => [$requiredIfReview('aliyun'), 'array'],
|
||||||
|
|
||||||
|
'configs.scan_configs.drivers.nsfwjs.api_url' => [$requiredIfReview('nsfwjs')],
|
||||||
|
'configs.scan_configs.drivers.nsfwjs.attr_name' => [$requiredIfReview('nsfwjs'), 'nullable'],
|
||||||
|
'configs.scan_configs.drivers.nsfwjs.threshold' => [$requiredIfReview('nsfwjs'), 'nullable', 'integer', 'between:1,100'],
|
||||||
|
|
||||||
'configs.is_enable_original_protection' => 'boolean',
|
'configs.is_enable_original_protection' => 'boolean',
|
||||||
'configs.image_cache_ttl' => 'nullable|numeric',
|
'configs.image_cache_ttl' => 'nullable|numeric',
|
||||||
|
|
||||||
'configs.is_enable_watermark' => 'boolean',
|
'configs.is_enable_watermark' => 'boolean',
|
||||||
|
'configs.watermark_configs.mode' => ['in:1,2'],
|
||||||
'configs.watermark_configs.driver' => ['exclude_if:configs.is_enable_watermark,false', 'in:font,image'],
|
'configs.watermark_configs.driver' => ['exclude_if:configs.is_enable_watermark,false', 'in:font,image'],
|
||||||
'configs.watermark_configs.drivers.font.font' => [
|
'configs.watermark_configs.drivers.font.font' => [
|
||||||
$requiredIfWatermark('font'),
|
$requiredIfWatermark('font'),
|
||||||
@@ -65,6 +78,7 @@ class GroupRequest extends FormRequest
|
|||||||
],
|
],
|
||||||
'configs.watermark_configs.drivers.font.position' => [$requiredIfWatermark('font')],
|
'configs.watermark_configs.drivers.font.position' => [$requiredIfWatermark('font')],
|
||||||
'configs.watermark_configs.drivers.font.text' => [$requiredIfWatermark('font')],
|
'configs.watermark_configs.drivers.font.text' => [$requiredIfWatermark('font')],
|
||||||
|
'configs.watermark_configs.drivers.font.color' => [$requiredIfWatermark('font')],
|
||||||
'configs.watermark_configs.drivers.font.size' => [$requiredIfWatermark('font'), 'nullable', 'integer'],
|
'configs.watermark_configs.drivers.font.size' => [$requiredIfWatermark('font'), 'nullable', 'integer'],
|
||||||
'configs.watermark_configs.drivers.font.angle' => [$requiredIfWatermark('font'), 'nullable', 'integer'],
|
'configs.watermark_configs.drivers.font.angle' => [$requiredIfWatermark('font'), 'nullable', 'integer'],
|
||||||
'configs.watermark_configs.drivers.font.x' => [$requiredIfWatermark('font'), 'nullable', 'integer'],
|
'configs.watermark_configs.drivers.font.x' => [$requiredIfWatermark('font'), 'nullable', 'integer'],
|
||||||
@@ -104,16 +118,26 @@ class GroupRequest extends FormRequest
|
|||||||
'configs.limit_per_month' => '每月上传限制',
|
'configs.limit_per_month' => '每月上传限制',
|
||||||
'configs.path_naming_rule' => '路径命名规则',
|
'configs.path_naming_rule' => '路径命名规则',
|
||||||
'configs.file_naming_rule' => '文件命名规则',
|
'configs.file_naming_rule' => '文件命名规则',
|
||||||
|
'configs.image_save_quality' => '图片保存质量',
|
||||||
|
'configs.image_save_format' => '图片保存格式',
|
||||||
'configs.accepted_file_suffixes' => '允许上传的文件后缀',
|
'configs.accepted_file_suffixes' => '允许上传的文件后缀',
|
||||||
|
|
||||||
'configs.is_enable_scan' => '是否启用图片审核',
|
'configs.is_enable_scan' => '是否启用图片审核',
|
||||||
'configs.scanned_action' => '图片审核动作',
|
'configs.scanned_action' => '图片审核动作',
|
||||||
'configs.scan_configs.driver' => '图片审核驱动',
|
'configs.scan_configs.driver' => '图片审核驱动',
|
||||||
|
'configs.scan_configs.drivers.tencent.endpoint' => 'Endpoint',
|
||||||
|
'configs.scan_configs.drivers.tencent.secret_id' => 'SecretId',
|
||||||
|
'configs.scan_configs.drivers.tencent.secret_key' => 'SecretKey',
|
||||||
|
'configs.scan_configs.drivers.tencent.region' => '地域节点',
|
||||||
|
'configs.scan_configs.drivers.tencent.biz_type' => '业务场景',
|
||||||
'configs.scan_configs.drivers.aliyun.access_key_id' => 'AccessKeyId',
|
'configs.scan_configs.drivers.aliyun.access_key_id' => 'AccessKeyId',
|
||||||
'configs.scan_configs.drivers.aliyun.access_key_secret' => 'AccessKeySecret',
|
'configs.scan_configs.drivers.aliyun.access_key_secret' => 'AccessKeySecret',
|
||||||
'configs.scan_configs.drivers.aliyun.biz_type' => '场景名称',
|
|
||||||
'configs.scan_configs.drivers.aliyun.region_id' => '地域节点',
|
'configs.scan_configs.drivers.aliyun.region_id' => '地域节点',
|
||||||
|
'configs.scan_configs.drivers.aliyun.biz_type' => '场景名称',
|
||||||
'configs.scan_configs.drivers.aliyun.scenes' => '审核场景',
|
'configs.scan_configs.drivers.aliyun.scenes' => '审核场景',
|
||||||
|
'configs.scan_configs.drivers.nsfwjs.api_url' => '接口地址',
|
||||||
|
'configs.scan_configs.drivers.nsfwjs.attr_name' => '表单名称',
|
||||||
|
'configs.scan_configs.drivers.nsfwjs.threshold' => '阈值',
|
||||||
|
|
||||||
'configs.is_enable_original_protection' => '是否启用原图保护功能',
|
'configs.is_enable_original_protection' => '是否启用原图保护功能',
|
||||||
'configs.image_cache_ttl' => '图片缓存时间',
|
'configs.image_cache_ttl' => '图片缓存时间',
|
||||||
@@ -123,6 +147,7 @@ class GroupRequest extends FormRequest
|
|||||||
'configs.watermark_configs.drivers.font.font' => '字体文件',
|
'configs.watermark_configs.drivers.font.font' => '字体文件',
|
||||||
'configs.watermark_configs.drivers.font.position' => '水印位置',
|
'configs.watermark_configs.drivers.font.position' => '水印位置',
|
||||||
'configs.watermark_configs.drivers.font.text' => '水印文字',
|
'configs.watermark_configs.drivers.font.text' => '水印文字',
|
||||||
|
'configs.watermark_configs.drivers.font.color' => '字体颜色',
|
||||||
'configs.watermark_configs.drivers.font.size' => '水印文字大小',
|
'configs.watermark_configs.drivers.font.size' => '水印文字大小',
|
||||||
'configs.watermark_configs.drivers.font.angle' => '水印旋转角度',
|
'configs.watermark_configs.drivers.font.angle' => '水印旋转角度',
|
||||||
'configs.watermark_configs.drivers.font.x' => '水印X轴偏移量',
|
'configs.watermark_configs.drivers.font.x' => '水印X轴偏移量',
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ class StrategyRequest extends FormRequest
|
|||||||
{
|
{
|
||||||
$checkUrl = function ($attribute, $value, $fail) {
|
$checkUrl = function ($attribute, $value, $fail) {
|
||||||
if ($this->input('key') == StrategyKey::Local) {
|
if ($this->input('key') == StrategyKey::Local) {
|
||||||
$folders = ['fonts', 'css', 'js'];
|
$folders = [config('app.thumbnail_path'), 'fonts', 'css', 'js'];
|
||||||
$symlink = Strategy::getRootPath($value);
|
$symlink = Strategy::getRootPath($value);
|
||||||
if (! $symlink) {
|
if (! $symlink) {
|
||||||
return $fail('访问域名缺少根路径');
|
return $fail('访问域名缺少根路径');
|
||||||
}
|
}
|
||||||
if (in_array($symlink, $folders)) {
|
if (in_array($symlink, $folders)) {
|
||||||
return $fail('系统保留路径');
|
return $fail('系统保留路径:'. $symlink);
|
||||||
}
|
}
|
||||||
if (false !== strpbrk($symlink, "\\/?%*:|\"<>")) {
|
if (false !== strpbrk($symlink, "\\/?%*:|\"<>")) {
|
||||||
return $fail('根路径名称不符合规则');
|
return $fail('根路径名称不符合规则');
|
||||||
@@ -54,6 +54,7 @@ class StrategyRequest extends FormRequest
|
|||||||
'intro' => 'max:2000',
|
'intro' => 'max:2000',
|
||||||
'key' => 'required|integer',
|
'key' => 'required|integer',
|
||||||
'configs.url' => ['required', 'url'],
|
'configs.url' => ['required', 'url'],
|
||||||
|
'configs.queries' => '',
|
||||||
];
|
];
|
||||||
|
|
||||||
return array_merge($array, match((int)$this->input('key')) {
|
return array_merge($array, match((int)$this->input('key')) {
|
||||||
@@ -73,6 +74,7 @@ class StrategyRequest extends FormRequest
|
|||||||
StrategyKey::S3 => [
|
StrategyKey::S3 => [
|
||||||
'configs.access_key_id' => 'required',
|
'configs.access_key_id' => 'required',
|
||||||
'configs.secret_access_key' => 'required',
|
'configs.secret_access_key' => 'required',
|
||||||
|
'configs.endpoint' => '',
|
||||||
'configs.region' => '',
|
'configs.region' => '',
|
||||||
'configs.bucket' => 'required',
|
'configs.bucket' => 'required',
|
||||||
],
|
],
|
||||||
@@ -122,12 +124,16 @@ class StrategyRequest extends FormRequest
|
|||||||
'configs.base_uri' => 'required',
|
'configs.base_uri' => 'required',
|
||||||
'configs.username' => '',
|
'configs.username' => '',
|
||||||
'configs.password' => '',
|
'configs.password' => '',
|
||||||
|
'configs.auth_type' => '',
|
||||||
|
'configs.prefix' => '',
|
||||||
],
|
],
|
||||||
StrategyKey::Minio => [
|
StrategyKey::Minio => [
|
||||||
'configs.access_key' => 'required',
|
'configs.access_key' => 'required',
|
||||||
'configs.secret_key' => 'required',
|
'configs.secret_key' => 'required',
|
||||||
'configs.endpoint' => 'required',
|
'configs.endpoint' => '',
|
||||||
|
'configs.region' => '',
|
||||||
'configs.bucket' => 'required',
|
'configs.bucket' => 'required',
|
||||||
|
'configs.bucket_endpoint' => '',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -139,6 +145,7 @@ class StrategyRequest extends FormRequest
|
|||||||
'intro' => '简介',
|
'intro' => '简介',
|
||||||
'key' => '策略',
|
'key' => '策略',
|
||||||
'configs.url' => '访问网址',
|
'configs.url' => '访问网址',
|
||||||
|
'configs.queries' => 'Url 额外参数',
|
||||||
];
|
];
|
||||||
|
|
||||||
return array_merge($array, match((int)$this->input('key')) {
|
return array_merge($array, match((int)$this->input('key')) {
|
||||||
@@ -148,6 +155,7 @@ class StrategyRequest extends FormRequest
|
|||||||
StrategyKey::S3 => [
|
StrategyKey::S3 => [
|
||||||
'configs.access_key_id' => 'AccessKeyId',
|
'configs.access_key_id' => 'AccessKeyId',
|
||||||
'configs.secret_access_key' => 'SecretAccessKey',
|
'configs.secret_access_key' => 'SecretAccessKey',
|
||||||
|
'configs.endpoint' => '连接地址',
|
||||||
'configs.region' => '区域',
|
'configs.region' => '区域',
|
||||||
'configs.bucket' => '储存桶名称',
|
'configs.bucket' => '储存桶名称',
|
||||||
],
|
],
|
||||||
@@ -194,15 +202,19 @@ class StrategyRequest extends FormRequest
|
|||||||
'configs.passive' => '被动模式',
|
'configs.passive' => '被动模式',
|
||||||
],
|
],
|
||||||
StrategyKey::Webdav => [
|
StrategyKey::Webdav => [
|
||||||
'configs.base_uri' => 'required',
|
'configs.base_uri' => '连接地址',
|
||||||
'configs.username' => 'required',
|
'configs.username' => '用户名',
|
||||||
'configs.password' => 'required',
|
'configs.password' => '密码',
|
||||||
|
'configs.auth_type' => '认证方式',
|
||||||
|
'configs.prefix' => '前缀',
|
||||||
],
|
],
|
||||||
StrategyKey::Minio => [
|
StrategyKey::Minio => [
|
||||||
'configs.access_key' => 'AccessKey',
|
'configs.access_key' => 'AccessKey',
|
||||||
'configs.secret_key' => 'SecretKey',
|
'configs.secret_key' => 'SecretKey',
|
||||||
'configs.endpoint' => '连接地址',
|
'configs.endpoint' => '连接地址',
|
||||||
|
'configs.region' => '区域',
|
||||||
'configs.bucket' => 'Bucket 名称',
|
'configs.bucket' => 'Bucket 名称',
|
||||||
|
'configs.bucket_endpoint' => 'BucketEndpoint',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class AlbumRequest extends FormRequest
|
|||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => 'required|max:60',
|
'name' => 'required|max:60|alpha_dash',
|
||||||
'intro' => 'max:600'
|
'intro' => 'max:600'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,7 @@ class AlbumRequest extends FormRequest
|
|||||||
return [
|
return [
|
||||||
'name.required' => '名称不能为空',
|
'name.required' => '名称不能为空',
|
||||||
'name.max' => '名称字符过长,最大不能超过 60',
|
'name.max' => '名称字符过长,最大不能超过 60',
|
||||||
|
'name.alpha_dash' => '名称只能是字母、数字,短破折号(-)和下划线(_)',
|
||||||
'intro.max' => '简介字符过长,最大不能超过 600'
|
'intro.max' => '简介字符过长,最大不能超过 600'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ImageRenameRequest extends FormRequest
|
|||||||
'id.numeric' => '图片选择异常',
|
'id.numeric' => '图片选择异常',
|
||||||
'name.required' => '请输入名称',
|
'name.required' => '请输入名称',
|
||||||
'name.max' => '名称长度不能超过 50 个字符',
|
'name.max' => '名称长度不能超过 50 个字符',
|
||||||
'name.string' => '名称格式不正确'
|
'name.string' => '名称格式不正确',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class UserSettingRequest extends FormRequest
|
|||||||
'configs.default_album' => 'required|numeric',
|
'configs.default_album' => 'required|numeric',
|
||||||
'configs.default_strategy' => 'required|numeric',
|
'configs.default_strategy' => 'required|numeric',
|
||||||
'configs.default_permission' => 'required|in:1,0',
|
'configs.default_permission' => 'required|in:1,0',
|
||||||
|
'configs.pasted_action' => 'required|in:1,2',
|
||||||
'configs.is_auto_clear_preview' => 'nullable|boolean'
|
'configs.is_auto_clear_preview' => 'nullable|boolean'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -29,7 +30,7 @@ class UserSettingRequest extends FormRequest
|
|||||||
'name.required' => '昵称不能为空',
|
'name.required' => '昵称不能为空',
|
||||||
'name.between' => '昵称必须在 2-20 个字符之间',
|
'name.between' => '昵称必须在 2-20 个字符之间',
|
||||||
'url.url' => '个人主页地址格式不正确',
|
'url.url' => '个人主页地址格式不正确',
|
||||||
'password.between' => '昵称必须在 6-32 个字符之间',
|
'password.between' => '密码必须在 6-32 个字符之间',
|
||||||
'configs.array' => '配置值不正确',
|
'configs.array' => '配置值不正确',
|
||||||
'configs.default_album.required' => '默认相册选择错误',
|
'configs.default_album.required' => '默认相册选择错误',
|
||||||
'configs.default_album.numeric' => '默认相册选择错误',
|
'configs.default_album.numeric' => '默认相册选择错误',
|
||||||
@@ -37,6 +38,8 @@ class UserSettingRequest extends FormRequest
|
|||||||
'configs.default_strategy.numeric' => '默认策略选择错误',
|
'configs.default_strategy.numeric' => '默认策略选择错误',
|
||||||
'configs.default_permission.required' => '权限值选择错误',
|
'configs.default_permission.required' => '权限值选择错误',
|
||||||
'configs.default_permission.in' => '权限值不正确',
|
'configs.default_permission.in' => '权限值不正确',
|
||||||
|
'configs.pasted_action.required' => '粘贴动作值选择错误',
|
||||||
|
'configs.pasted_action.in' => '粘贴动作值不正确',
|
||||||
'configs.is_auto_clear_preview.boolean' => '是否自动清除预览选择错误'
|
'configs.is_auto_clear_preview.boolean' => '是否自动清除预览选择错误'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ namespace App\Models;
|
|||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property string $name
|
* @property string $name
|
||||||
|
|||||||
@@ -3,10 +3,8 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Utils;
|
use App\Utils;
|
||||||
use Carbon\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -83,7 +81,7 @@ class Group extends Model
|
|||||||
*/
|
*/
|
||||||
public static function getDefaultConfigs(): Collection
|
public static function getDefaultConfigs(): Collection
|
||||||
{
|
{
|
||||||
return collect(config('convention.app.group'));
|
return collect(config('convention.group'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function users(): HasMany
|
public function users(): HasMany
|
||||||
|
|||||||
@@ -6,11 +6,10 @@ use App\Enums\GroupConfigKey;
|
|||||||
use App\Enums\ImagePermission;
|
use App\Enums\ImagePermission;
|
||||||
use App\Services\ImageService;
|
use App\Services\ImageService;
|
||||||
use App\Utils;
|
use App\Utils;
|
||||||
use Carbon\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -93,6 +92,8 @@ class Image extends Model
|
|||||||
'permission' => 'integer',
|
'permission' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected ?Filesystem $filesystem = null;
|
||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::creating(function (self $image) {
|
static::creating(function (self $image) {
|
||||||
@@ -110,10 +111,12 @@ class Image extends Model
|
|||||||
->exists()
|
->exists()
|
||||||
) {
|
) {
|
||||||
// 删除本地缓存文件
|
// 删除本地缓存文件
|
||||||
Cache::forget("image_thumb_{$image->key}");
|
|
||||||
try {
|
try {
|
||||||
// 删除物理文件
|
// 删除物理文件
|
||||||
$image->filesystem()->delete($image->pathname);
|
$image->filesystem()->delete($image->pathname);
|
||||||
|
@unlink(public_path($image->getThumbnailPathname()));
|
||||||
|
// 删除缓存
|
||||||
|
Cache::forget("image_{$image->key}");
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Utils::e($e, '删除物理文件时发生异常');
|
Utils::e($e, '删除物理文件时发生异常');
|
||||||
}
|
}
|
||||||
@@ -162,25 +165,36 @@ class Image extends Model
|
|||||||
|
|
||||||
public function pathname(): Attribute
|
public function pathname(): Attribute
|
||||||
{
|
{
|
||||||
return new Attribute(fn() => "{$this->path}/{$this->name}");
|
$path = $this->path ? "{$this->path}/" : '';
|
||||||
|
return new Attribute(fn() => "{$path}{$this->name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function url(): Attribute
|
public function url(): Attribute
|
||||||
{
|
{
|
||||||
return new Attribute(function () {
|
return new Attribute(function () {
|
||||||
// 是否启用原图保护功能
|
// 是否启用原图保护功能
|
||||||
if ($this->group->configs->get(GroupConfigKey::IsEnableOriginalProtection)) {
|
if ($this->group?->configs->get(GroupConfigKey::IsEnableOriginalProtection)) {
|
||||||
return asset("{$this->key}.{$this->extension}");
|
$url = asset("{$this->key}.{$this->extension}");
|
||||||
} else {
|
} else {
|
||||||
return rtrim($this->strategy->configs->get('url'), '/').'/'.$this->pathname;
|
$url = rtrim($this->strategy?->configs->get('url'), '/').'/'.ltrim($this->pathname, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 拼接图片 url
|
||||||
|
return $url.($this->strategy?->configs->get('queries') ?: '');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function thumbUrl(): Attribute
|
public function thumbUrl(): Attribute
|
||||||
{
|
{
|
||||||
return new Attribute(function () {
|
return new Attribute(function () {
|
||||||
return asset("{$this->key}.{$this->extension}!thumbnail");
|
$pathname = $this->getThumbnailPathname();
|
||||||
|
|
||||||
|
// 没有缩略图则返回原图
|
||||||
|
if (! file_exists(public_path($pathname))) {
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return asset($pathname);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +212,10 @@ class Image extends Model
|
|||||||
|
|
||||||
public function filesystem(): Filesystem
|
public function filesystem(): Filesystem
|
||||||
{
|
{
|
||||||
return new Filesystem((new ImageService())->getAdapter($this->strategy));
|
if (is_null($this->filesystem)) {
|
||||||
|
$this->filesystem = new Filesystem((new ImageService())->getAdapter($this->strategy));
|
||||||
|
}
|
||||||
|
return $this->filesystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function user(): BelongsTo
|
public function user(): BelongsTo
|
||||||
@@ -221,6 +238,11 @@ class Image extends Model
|
|||||||
return $this->belongsTo(Strategy::class, 'strategy_id', 'id');
|
return $this->belongsTo(Strategy::class, 'strategy_id', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getThumbnailPathname(): string
|
||||||
|
{
|
||||||
|
return trim(config('app.thumbnail_path'), '/')."/{$this->md5}.". ($this->extension === 'svg' ? 'svg' : "png");
|
||||||
|
}
|
||||||
|
|
||||||
private function generateKey($length = 6): string
|
private function generateKey($length = 6): string
|
||||||
{
|
{
|
||||||
$key = Str::random($length);
|
$key = Str::random($length);
|
||||||
|
|||||||
13
app/Models/Model.php
Normal file
13
app/Models/Model.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Carbon\CarbonInterface;
|
||||||
|
|
||||||
|
abstract class Model extends \Illuminate\Database\Eloquent\Model
|
||||||
|
{
|
||||||
|
protected function serializeDate(\DateTimeInterface $date): string
|
||||||
|
{
|
||||||
|
return $date->format(CarbonInterface::DEFAULT_TO_STRING_FORMAT);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,14 +3,14 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\StrategyKey;
|
use App\Enums\StrategyKey;
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Filesystem\Filesystem;
|
use Illuminate\Filesystem\Filesystem;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Sabre\DAV\Client;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property int $id
|
* @property int $id
|
||||||
@@ -57,6 +57,13 @@ class Strategy extends Model
|
|||||||
StrategyKey::Minio => 'Minio',
|
StrategyKey::Minio => 'Minio',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const WEBDAV_AUTH_TYPES = [
|
||||||
|
'' => 'Auto',
|
||||||
|
Client::AUTH_BASIC => 'Basic',
|
||||||
|
Client::AUTH_DIGEST => 'Digest',
|
||||||
|
Client::AUTH_NTLM => 'Ntlm',
|
||||||
|
];
|
||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::saving(function (self $strategy) {
|
static::saving(function (self $strategy) {
|
||||||
@@ -78,6 +85,14 @@ class Strategy extends Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static::deleted(function (self $strategy) {
|
||||||
|
// 如果是本地策略,删除的时候同时删除符号连接
|
||||||
|
if ($strategy->key === StrategyKey::Local) {
|
||||||
|
$symlink = self::getRootPath($strategy->configs['url']);
|
||||||
|
@unlink(public_path($symlink));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getRootPath($url): string
|
public static function getRootPath($url): string
|
||||||
|
|||||||
@@ -3,10 +3,8 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\ConfigKey;
|
use App\Enums\ConfigKey;
|
||||||
use App\Enums\ImagePermission;
|
|
||||||
use App\Enums\UserConfigKey;
|
|
||||||
use App\Utils;
|
use App\Utils;
|
||||||
use Carbon\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
@@ -26,6 +24,7 @@ use Laravel\Sanctum\HasApiTokens;
|
|||||||
* @property string $remember_token
|
* @property string $remember_token
|
||||||
* @property boolean $is_adminer
|
* @property boolean $is_adminer
|
||||||
* @property float $capacity
|
* @property float $capacity
|
||||||
|
* @property float $use_capacity
|
||||||
* @property string $url
|
* @property string $url
|
||||||
* @property Collection $configs
|
* @property Collection $configs
|
||||||
* @property int $image_num
|
* @property int $image_num
|
||||||
@@ -58,6 +57,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
'configs',
|
'configs',
|
||||||
'configs->default_strategy',
|
'configs->default_strategy',
|
||||||
'registered_ip',
|
'registered_ip',
|
||||||
|
'status',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,13 +99,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
$user->group_id = Group::query()->where('is_default', true)->value('id');
|
$user->group_id = Group::query()->where('is_default', true)->value('id');
|
||||||
// 初始容量
|
// 初始容量
|
||||||
$user->capacity = Utils::config(ConfigKey::UserInitialCapacity);
|
$user->capacity = Utils::config(ConfigKey::UserInitialCapacity);
|
||||||
|
$user->configs = collect(config('convention.user'))->merge($user->configs ?: []);
|
||||||
$user->configs = collect([
|
|
||||||
UserConfigKey::DefaultAlbum => 0,
|
|
||||||
UserConfigKey::DefaultStrategy => 0,
|
|
||||||
UserConfigKey::DefaultPermission => ImagePermission::Private,
|
|
||||||
UserConfigKey::IsAutoClearPreview => false,
|
|
||||||
])->merge($user->configs ?: []);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +108,11 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
return new Attribute(fn () => Utils::getAvatar($this->email));
|
return new Attribute(fn () => Utils::getAvatar($this->email));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function useCapacity(): Attribute
|
||||||
|
{
|
||||||
|
return new Attribute(fn () => $this->images()->sum('size'));
|
||||||
|
}
|
||||||
|
|
||||||
public function group(): BelongsTo
|
public function group(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Group::class, 'group_id', 'id');
|
return $this->belongsTo(Group::class, 'group_id', 'id');
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
View::composer('*', function (\Illuminate\View\View $view) {
|
View::composer('*', function (\Illuminate\View\View $view) {
|
||||||
/** @var Group $group */
|
/** @var Group $group */
|
||||||
$group = Auth::check() ? Auth::user()->group : Group::query()->where('is_guest', true)->first();
|
$group = Auth::check() ? Auth::user()->group : Group::query()->where('is_guest', true)->first();
|
||||||
$view->with('_group', $group);
|
$view->with([
|
||||||
|
'_group' => $group,
|
||||||
|
'_is_notice' => strip_tags(Utils::config(ConfigKey::SiteNotice)),
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ use App\Enums\ConfigKey;
|
|||||||
use App\Enums\GroupConfigKey;
|
use App\Enums\GroupConfigKey;
|
||||||
use App\Enums\ImagePermission;
|
use App\Enums\ImagePermission;
|
||||||
use App\Enums\Scan\AliyunOption;
|
use App\Enums\Scan\AliyunOption;
|
||||||
|
use App\Enums\Scan\NsfwJsOption;
|
||||||
|
use App\Enums\Scan\TencentOption;
|
||||||
use App\Enums\Strategy\CosOption;
|
use App\Enums\Strategy\CosOption;
|
||||||
use App\Enums\Strategy\FtpOption;
|
use App\Enums\Strategy\FtpOption;
|
||||||
use App\Enums\Strategy\KodoOption;
|
use App\Enums\Strategy\KodoOption;
|
||||||
@@ -23,6 +25,7 @@ use App\Enums\UserConfigKey;
|
|||||||
use App\Enums\UserStatus;
|
use App\Enums\UserStatus;
|
||||||
use App\Enums\Watermark\FontOption;
|
use App\Enums\Watermark\FontOption;
|
||||||
use App\Enums\Watermark\ImageOption;
|
use App\Enums\Watermark\ImageOption;
|
||||||
|
use App\Enums\Watermark\Mode;
|
||||||
use App\Exceptions\UploadException;
|
use App\Exceptions\UploadException;
|
||||||
use App\Models\Group;
|
use App\Models\Group;
|
||||||
use App\Models\Image;
|
use App\Models\Image;
|
||||||
@@ -30,14 +33,14 @@ use App\Models\Strategy;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Utils;
|
use App\Utils;
|
||||||
use Aws\S3\S3Client;
|
use Aws\S3\S3Client;
|
||||||
use Carbon\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Intervention\Image\Facades\Image as InterventionImage;
|
use Intervention\Image\Facades\Image as InterventionImage;
|
||||||
use Intervention\Image\Imagick\Font;
|
use Intervention\Image\Imagick\Font;
|
||||||
@@ -49,17 +52,20 @@ use League\Flysystem\FilesystemException;
|
|||||||
use League\Flysystem\Ftp\FtpAdapter;
|
use League\Flysystem\Ftp\FtpAdapter;
|
||||||
use League\Flysystem\Ftp\FtpConnectionOptions;
|
use League\Flysystem\Ftp\FtpConnectionOptions;
|
||||||
use League\Flysystem\Local\LocalFilesystemAdapter;
|
use League\Flysystem\Local\LocalFilesystemAdapter;
|
||||||
use League\Flysystem\PhpseclibV2\SftpAdapter;
|
use League\Flysystem\PhpseclibV3\SftpAdapter;
|
||||||
use League\Flysystem\PhpseclibV2\SftpConnectionProvider;
|
use League\Flysystem\PhpseclibV3\SftpConnectionProvider;
|
||||||
use League\Flysystem\UnixVisibility\PortableVisibilityConverter;
|
|
||||||
use League\Flysystem\Visibility;
|
|
||||||
use League\Flysystem\WebDAV\WebDAVAdapter;
|
use League\Flysystem\WebDAV\WebDAVAdapter;
|
||||||
use OSS\OssClient;
|
|
||||||
use Overtrue\Flysystem\Cos\CosAdapter;
|
use Overtrue\Flysystem\Cos\CosAdapter;
|
||||||
use Overtrue\Flysystem\Qiniu\QiniuAdapter;
|
use Overtrue\Flysystem\Qiniu\QiniuAdapter;
|
||||||
use Sabre\DAV\Client;
|
use Sabre\DAV\Client;
|
||||||
|
use TencentCloud\Common\Credential;
|
||||||
|
use TencentCloud\Common\Profile\ClientProfile;
|
||||||
|
use TencentCloud\Common\Profile\HttpProfile;
|
||||||
|
use TencentCloud\Ims\V20201229\ImsClient;
|
||||||
|
use TencentCloud\Ims\V20201229\Models\ImageModerationRequest;
|
||||||
use WispX\Flysystem\Upyun\UpyunAdapter;
|
use WispX\Flysystem\Upyun\UpyunAdapter;
|
||||||
use Zing\Flysystem\Oss\OssAdapter;
|
use Zing\Flysystem\Oss\OssAdapter;
|
||||||
|
use OSS\OssClient;
|
||||||
|
|
||||||
class ImageService
|
class ImageService
|
||||||
{
|
{
|
||||||
@@ -76,8 +82,6 @@ class ImageService
|
|||||||
throw new UploadException('管理员关闭了游客上传');
|
throw new UploadException('管理员关闭了游客上传');
|
||||||
}
|
}
|
||||||
|
|
||||||
$img = InterventionImage::make($file);
|
|
||||||
|
|
||||||
$image = new Image();
|
$image = new Image();
|
||||||
/** @var User|null $user */
|
/** @var User|null $user */
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
@@ -92,7 +96,9 @@ class ImageService
|
|||||||
throw new UploadException('没有可用的储存,请联系管理员。');
|
throw new UploadException('没有可用的储存,请联系管理员。');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in_array($file->getClientOriginalExtension(), $configs->get(GroupConfigKey::AcceptedFileSuffixes))) {
|
$extension = strtolower($file->getClientOriginalExtension());
|
||||||
|
|
||||||
|
if (! in_array($extension, $configs->get(GroupConfigKey::AcceptedFileSuffixes))) {
|
||||||
throw new UploadException('不支持的文件类型');
|
throw new UploadException('不支持的文件类型');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,27 +151,58 @@ class ImageService
|
|||||||
// 上传频率限制
|
// 上传频率限制
|
||||||
$this->rateLimiter($configs, $request);
|
$this->rateLimiter($configs, $request);
|
||||||
|
|
||||||
|
// 图片处理,跳过 ico gif svg
|
||||||
|
if (! in_array($extension, ['ico', 'gif', 'svg'])) {
|
||||||
|
// 图片保存质量与格式
|
||||||
|
$quality = $configs->get(GroupConfigKey::ImageSaveQuality, 75);
|
||||||
|
$format = $configs->get(GroupConfigKey::ImageSaveFormat);
|
||||||
|
if ($quality < 100 || $format) {
|
||||||
|
// 获取拓展名,判断是否需要转换
|
||||||
|
$format = $format ?: $extension;
|
||||||
|
$filename = Str::replaceLast($extension, $format, $file->getClientOriginalName());
|
||||||
|
$handleImage = InterventionImage::make($file)->save('tmp_' . md5_file($file->getRealPath()), $quality);
|
||||||
|
$file = new UploadedFile($handleImage->basePath(), $filename, $handleImage->mime());
|
||||||
|
// 重新设置拓展名
|
||||||
|
$extension = $format;
|
||||||
|
$handleImage->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否启用水印,覆盖原图片
|
||||||
|
if (
|
||||||
|
$configs->get(GroupConfigKey::IsEnableWatermark) &&
|
||||||
|
collect($configs->get(GroupConfigKey::WatermarkConfigs))->get('mode', Mode::Overlay) == Mode::Overlay
|
||||||
|
) {
|
||||||
|
$watermarkImage = $this->stickWatermark($file, collect($configs->get(GroupConfigKey::WatermarkConfigs)));
|
||||||
|
$watermarkImage->save();
|
||||||
|
$file = new UploadedFile($watermarkImage->basePath(), $file->getClientOriginalName(), $file->getMimeType());
|
||||||
|
$watermarkImage->destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$filename = $this->replacePathname(
|
$filename = $this->replacePathname(
|
||||||
$configs->get(GroupConfigKey::PathNamingRule).'/'.$configs->get(GroupConfigKey::FileNamingRule), $file,
|
$configs->get(GroupConfigKey::PathNamingRule).'/'.$configs->get(GroupConfigKey::FileNamingRule), $file,
|
||||||
);
|
);
|
||||||
$pathname = $filename.".{$file->getClientOriginalExtension()}";
|
$pathname = $filename.".{$extension}";
|
||||||
|
|
||||||
|
[$width, $height] = @getimagesize($file->getRealPath()) ?: [400, 400];
|
||||||
|
|
||||||
$image->fill([
|
$image->fill([
|
||||||
'md5' => md5_file($file->getRealPath()),
|
'md5' => md5_file($file->getRealPath()),
|
||||||
'sha1' => sha1_file($file->getRealPath()),
|
'sha1' => sha1_file($file->getRealPath()),
|
||||||
'path' => dirname($pathname),
|
'path' => $configs->get(GroupConfigKey::PathNamingRule) ? dirname($pathname) : '',
|
||||||
'name' => basename($pathname),
|
'name' => basename($pathname),
|
||||||
'origin_name' => $file->getClientOriginalName(),
|
'origin_name' => $file->getClientOriginalName(),
|
||||||
'size' => $file->getSize() / 1024,
|
'size' => $file->getSize() / 1024,
|
||||||
'mimetype' => $file->getMimeType(),
|
'mimetype' => $file->getMimeType(),
|
||||||
'extension' => strtolower($file->getClientOriginalExtension()),
|
'extension' => strtolower($extension),
|
||||||
'width' => $img->width(),
|
'width' => $width,
|
||||||
'height' => $img->height(),
|
'height' => $height,
|
||||||
'is_unhealthy' => false,
|
'is_unhealthy' => false,
|
||||||
'uploaded_ip' => $request->ip(),
|
'uploaded_ip' => $request->ip(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$filesystem = new Filesystem($this->getAdapter($strategy));
|
$filesystem = new Filesystem($this->getAdapter($strategy));
|
||||||
|
|
||||||
// 检测该策略是否存在该图片,有则只创建记录不保存文件
|
// 检测该策略是否存在该图片,有则只创建记录不保存文件
|
||||||
/** @var Image $existing */
|
/** @var Image $existing */
|
||||||
$existing = Image::query()->when($image->strategy_id, function (Builder $builder, $id) {
|
$existing = Image::query()->when($image->strategy_id, function (Builder $builder, $id) {
|
||||||
@@ -179,7 +216,7 @@ class ImageService
|
|||||||
Utils::e($e, '保存图片时出现异常');
|
Utils::e($e, '保存图片时出现异常');
|
||||||
throw new UploadException(config('app.debug', false) ? $e->getMessage() : '图片上传失败');
|
throw new UploadException(config('app.debug', false) ? $e->getMessage() : '图片上传失败');
|
||||||
}
|
}
|
||||||
@fclose($handle);
|
if (is_resource($handle)) @fclose($handle);
|
||||||
} else {
|
} else {
|
||||||
$image->fill($existing->only('path', 'name'));
|
$image->fill($existing->only('path', 'name'));
|
||||||
}
|
}
|
||||||
@@ -208,10 +245,15 @@ class ImageService
|
|||||||
throw new UploadException('图片记录保存失败');
|
throw new UploadException('图片记录保存失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图片检测
|
// 图片检测,跳过 tif、ico、psd、svg 格式
|
||||||
if ($configs->get(GroupConfigKey::IsEnableScan)) {
|
if ($configs->get(GroupConfigKey::IsEnableScan) && ! in_array($extension, ['psd', 'ico', 'tif', 'svg'])) {
|
||||||
$scanConfigs = $configs->get(GroupConfigKey::ScanConfigs);
|
$scanConfigs = $configs->get(GroupConfigKey::ScanConfigs);
|
||||||
if ($this->scan($scanConfigs['driver'], collect($scanConfigs['drivers'][$scanConfigs['driver']]), $image)) {
|
if ($this->scan(
|
||||||
|
driver: $scanConfigs['driver'],
|
||||||
|
configs: collect($scanConfigs['drivers'][$scanConfigs['driver']]),
|
||||||
|
image: $image,
|
||||||
|
file: $file,
|
||||||
|
)) {
|
||||||
// 标记 or 删除
|
// 标记 or 删除
|
||||||
if ($configs->get(GroupConfigKey::ScannedAction) === 'delete') {
|
if ($configs->get(GroupConfigKey::ScannedAction) === 'delete') {
|
||||||
$image->delete();
|
$image->delete();
|
||||||
@@ -224,6 +266,11 @@ class ImageService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->makeThumbnail($image, $file);
|
||||||
|
|
||||||
|
// 上传完成后删除临时文件
|
||||||
|
unlink($file->getPathname());
|
||||||
|
|
||||||
return $image;
|
return $image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,17 +287,17 @@ class ImageService
|
|||||||
'key' => $configs->get(S3Option::AccessKeyId),
|
'key' => $configs->get(S3Option::AccessKeyId),
|
||||||
'secret' => $configs->get(S3Option::SecretAccessKey)
|
'secret' => $configs->get(S3Option::SecretAccessKey)
|
||||||
],
|
],
|
||||||
|
'endpoint' => $configs->get(S3Option::Endpoint),
|
||||||
'region' => $configs->get(S3Option::Region),
|
'region' => $configs->get(S3Option::Region),
|
||||||
'version' => '2006-03-01',
|
'version' => '2006-03-01',
|
||||||
]),
|
]),
|
||||||
bucket: $configs->get(S3Option::Bucket),
|
bucket: $configs->get(S3Option::Bucket),
|
||||||
visibility: new \League\Flysystem\AwsS3V3\PortableVisibilityConverter(Visibility::PUBLIC),
|
|
||||||
),
|
),
|
||||||
StrategyKey::Oss => new OssAdapter(
|
StrategyKey::Oss => new OssAdapter(
|
||||||
client: new OssClient(
|
client: new OssClient($configs->get(
|
||||||
accessKeyId: $configs->get(OssOption::AccessKeyId),
|
OssOption::AccessKeyId),
|
||||||
accessKeySecret: $configs->get(OssOption::AccessKeySecret),
|
$configs->get(OssOption::AccessKeySecret),
|
||||||
endpoint: $configs->get(OssOption::Endpoint),
|
$configs->get(OssOption::Endpoint),
|
||||||
),
|
),
|
||||||
bucket: $configs->get(OssOption::Bucket),
|
bucket: $configs->get(OssOption::Bucket),
|
||||||
),
|
),
|
||||||
@@ -280,16 +327,6 @@ class ImageService
|
|||||||
useAgent: (bool)$configs->get(SftpOption::UseAgent)
|
useAgent: (bool)$configs->get(SftpOption::UseAgent)
|
||||||
),
|
),
|
||||||
root: $configs->get(SftpOption::Root),
|
root: $configs->get(SftpOption::Root),
|
||||||
visibilityConverter: PortableVisibilityConverter::fromArray([
|
|
||||||
'file' => [
|
|
||||||
'public' => 0640,
|
|
||||||
'private' => 0604,
|
|
||||||
],
|
|
||||||
'dir' => [
|
|
||||||
'public' => 0740,
|
|
||||||
'private' => 7604,
|
|
||||||
],
|
|
||||||
])
|
|
||||||
),
|
),
|
||||||
StrategyKey::Ftp => new FtpAdapter(
|
StrategyKey::Ftp => new FtpAdapter(
|
||||||
connectionOptions: FtpConnectionOptions::fromArray([
|
connectionOptions: FtpConnectionOptions::fromArray([
|
||||||
@@ -303,11 +340,12 @@ class ImageService
|
|||||||
'timeout' => 30,
|
'timeout' => 30,
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
StrategyKey::Webdav => new WebDAVAdapter(new Client([
|
StrategyKey::Webdav => new WebDAVAdapter(new Client(([
|
||||||
'baseUri' => $configs->get(WebDavOption::BaseUri),
|
'baseUri' => $configs->get(WebDavOption::BaseUri),
|
||||||
'userName' => $configs->get(WebDavOption::Username),
|
'userName' => $configs->get(WebDavOption::Username),
|
||||||
'password' => $configs->get(WebDavOption::Password)
|
'password' => $configs->get(WebDavOption::Password),
|
||||||
])),
|
'authType' => (int)$configs->get(WebDavOption::AuthType),
|
||||||
|
])), $configs->get(WebDavOption::Prefix) ?: ''),
|
||||||
StrategyKey::Minio => new AwsS3V3Adapter(
|
StrategyKey::Minio => new AwsS3V3Adapter(
|
||||||
client: new S3Client([
|
client: new S3Client([
|
||||||
'credentials' => [
|
'credentials' => [
|
||||||
@@ -315,11 +353,11 @@ class ImageService
|
|||||||
'secret' => $configs->get(MinioOption::SecretKey)
|
'secret' => $configs->get(MinioOption::SecretKey)
|
||||||
],
|
],
|
||||||
'endpoint' => $configs->get(MinioOption::Endpoint),
|
'endpoint' => $configs->get(MinioOption::Endpoint),
|
||||||
'region' => '',
|
'region' => $configs->get(MinioOption::Region),
|
||||||
'version' => '2006-03-01',
|
'version' => '2006-03-01',
|
||||||
|
'bucket_endpoint' => (bool)$configs->get(MinioOption::BucketEndpoint),
|
||||||
]),
|
]),
|
||||||
bucket: $configs->get(MinioOption::Bucket),
|
bucket: $configs->get(MinioOption::Bucket),
|
||||||
visibility: new \League\Flysystem\AwsS3V3\PortableVisibilityConverter(Visibility::PUBLIC),
|
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -337,7 +375,7 @@ class ImageService
|
|||||||
'hours' => ['key' => GroupConfigKey::LimitPerHour, 'str' => '小时'],
|
'hours' => ['key' => GroupConfigKey::LimitPerHour, 'str' => '小时'],
|
||||||
'days' => ['key' => GroupConfigKey::LimitPerDay, 'str' => '天'],
|
'days' => ['key' => GroupConfigKey::LimitPerDay, 'str' => '天'],
|
||||||
'weeks' => ['key' => GroupConfigKey::LimitPerWeek, 'str' => '周'],
|
'weeks' => ['key' => GroupConfigKey::LimitPerWeek, 'str' => '周'],
|
||||||
'months' => ['key' => GroupConfigKey::LimitPerWeek, 'str' => '月'],
|
'months' => ['key' => GroupConfigKey::LimitPerMonth, 'str' => '月'],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($array as $key => $item) {
|
foreach ($array as $key => $item) {
|
||||||
@@ -362,14 +400,47 @@ class ImageService
|
|||||||
* @param $driver
|
* @param $driver
|
||||||
* @param Collection $configs
|
* @param Collection $configs
|
||||||
* @param Image $image
|
* @param Image $image
|
||||||
|
* @param UploadedFile $file
|
||||||
* @return bool true=违规
|
* @return bool true=违规
|
||||||
* @throws UploadException
|
* @throws UploadException
|
||||||
*/
|
*/
|
||||||
public function scan($driver, Collection $configs, Image $image): bool
|
public function scan($driver, Collection $configs, Image $image, UploadedFile $file): bool
|
||||||
{
|
{
|
||||||
$flag = false;
|
$flag = false;
|
||||||
try {
|
try {
|
||||||
|
if ($driver === 'tencent') {
|
||||||
|
// 图片大小不得超过 5mb
|
||||||
|
if ($file->getSize() >= 5242880) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cred = new Credential($configs->get(TencentOption::SecretId), $configs->get(TencentOption::SecretKey));
|
||||||
|
$httpProfile = new HttpProfile();
|
||||||
|
$httpProfile->setEndpoint($configs->get(TencentOption::Endpoint));
|
||||||
|
$clientProfile = new ClientProfile();
|
||||||
|
$clientProfile->setHttpProfile($httpProfile);
|
||||||
|
$client = new ImsClient($cred, $configs->get(TencentOption::Region), $clientProfile);
|
||||||
|
$req = new ImageModerationRequest();
|
||||||
|
$params = [
|
||||||
|
"FileContent" => base64_encode($file->getContent()),
|
||||||
|
];
|
||||||
|
if ($configs->get(TencentOption::BizType)) {
|
||||||
|
$params['BizType'] = $configs->get(TencentOption::BizType);
|
||||||
|
}
|
||||||
|
$req->fromJsonString(json_encode($params));
|
||||||
|
$resp = $client->ImageModeration($req);
|
||||||
|
|
||||||
|
if ($resp->getSuggestion() === 'Block') {
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($driver === 'aliyun') {
|
if ($driver === 'aliyun') {
|
||||||
|
// 20 mb以内、宽高不超过 30000px
|
||||||
|
if ($file->getSize() >= 20971520 || $image->width >= 30000 || $image->height >= 30000) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
AlibabaCloud::accessKeyClient(
|
AlibabaCloud::accessKeyClient(
|
||||||
$configs->get(AliyunOption::AccessKeyId),
|
$configs->get(AliyunOption::AccessKeyId),
|
||||||
$configs->get(AliyunOption::AccessKeySecret),
|
$configs->get(AliyunOption::AccessKeySecret),
|
||||||
@@ -393,6 +464,29 @@ class ImageService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($driver === 'nsfwjs') {
|
||||||
|
// 不支持 bmp 格式
|
||||||
|
if ($image->extension === 'bmp') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$response = Http::timeout(180)->withOptions(['timeout' => 180])->attach(
|
||||||
|
$configs->get(NsfwJsOption::AttrName, 'image'), $file->getContent(), $file->getClientOriginalName(),
|
||||||
|
)->post($configs->get(NsfwJsOption::ApiUrl));
|
||||||
|
$ratio = $configs->get(NsfwJsOption::Threshold, 60) / 100;
|
||||||
|
|
||||||
|
if ($response->json('hentai', 0.00) >= $ratio) {
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->json('porn', 0.00) >= $ratio) {
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->json('sexy', 0.00) >= $ratio) {
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
throw new UploadException('Scan: '.$e->getMessage());
|
throw new UploadException('Scan: '.$e->getMessage());
|
||||||
}
|
}
|
||||||
@@ -443,6 +537,52 @@ class ImageService
|
|||||||
return $image;
|
return $image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成缩略图,缩略图目录必须在 public 目录下,且该目录必须存在
|
||||||
|
*
|
||||||
|
* @param mixed $image 图片数据
|
||||||
|
* @param mixed $data 物理图片数据
|
||||||
|
* @param int $max 最大宽高
|
||||||
|
* @param bool $force 是否强制覆盖
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function makeThumbnail(Image $image, mixed $data, int $max = 400, bool $force = false): void
|
||||||
|
{
|
||||||
|
$pathname = public_path($image->getThumbnailPathname());
|
||||||
|
|
||||||
|
if (! file_exists($pathname) || $force) {
|
||||||
|
try {
|
||||||
|
// 创建文件夹
|
||||||
|
if (! is_dir(dirname($pathname))) {
|
||||||
|
@mkdir(dirname($pathname));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成缩略图,svg等格式本身体积足够小且网页原生支持(比生成的png缩略图还小),不用生成缩略图,直接复制文件
|
||||||
|
if($image->extension ==='svg') {
|
||||||
|
copy($data->getPathname(), $pathname);
|
||||||
|
}else{
|
||||||
|
@ini_set('memory_limit', '512M');
|
||||||
|
|
||||||
|
$img = InterventionImage::make($data);
|
||||||
|
|
||||||
|
$width = $w = $image->width;
|
||||||
|
$height = $h = $image->height;
|
||||||
|
|
||||||
|
if ($w > $max && $h > $max) {
|
||||||
|
$scale = min($max / $w, $max / $h);
|
||||||
|
$width = (int)($w * $scale);
|
||||||
|
$height = (int)($h * $scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
$img->fit($width, $height, fn($constraint) => $constraint->upsize())->encode('png', 60)->save($pathname);
|
||||||
|
$img->destroy();
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Utils::e($e, '生成缩略图时出现异常');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取水印画布
|
* 获取水印画布
|
||||||
*
|
*
|
||||||
@@ -504,7 +644,7 @@ class ImageService
|
|||||||
'{md5-16}' => substr(md5(microtime().Str::random()), 0, 16),
|
'{md5-16}' => substr(md5(microtime().Str::random()), 0, 16),
|
||||||
'{str-random-16}' => Str::random(),
|
'{str-random-16}' => Str::random(),
|
||||||
'{str-random-10}' => Str::random(10),
|
'{str-random-10}' => Str::random(10),
|
||||||
'{filename}' => rtrim($file->getClientOriginalName(), '.'.$file->getClientOriginalExtension()),
|
'{filename}' => Str::replaceLast('.'.$file->getClientOriginalExtension(), '', $file->getClientOriginalName()),
|
||||||
'{uid}' => Auth::check() ? Auth::id() : 0,
|
'{uid}' => Auth::check() ? Auth::id() : 0,
|
||||||
];
|
];
|
||||||
return str_replace(array_keys($array), array_values($array), $pathname);
|
return str_replace(array_keys($array), array_values($array), $pathname);
|
||||||
|
|||||||
@@ -10,14 +10,13 @@ use Illuminate\Support\Collection;
|
|||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use League\Flysystem\Filesystem;
|
use League\Flysystem\Filesystem;
|
||||||
use League\Flysystem\FilesystemException;
|
use League\Flysystem\FilesystemException;
|
||||||
use League\Flysystem\Local\LocalFilesystemAdapter;
|
use League\Flysystem\Local\LocalFilesystemAdapter;
|
||||||
|
|
||||||
class UpgradeService
|
class UpgradeService
|
||||||
{
|
{
|
||||||
const ApiUrl = 'https://api.lsky.pro/v1';
|
const ApiUrl = 'https://api.lsky.pro/v2';
|
||||||
|
|
||||||
/** @var array|array[] 所有版本 */
|
/** @var array|array[] 所有版本 */
|
||||||
protected array $versions = [];
|
protected array $versions = [];
|
||||||
@@ -34,7 +33,7 @@ class UpgradeService
|
|||||||
|
|
||||||
public function __construct(protected string $version)
|
public function __construct(protected string $version)
|
||||||
{
|
{
|
||||||
$this->http = Http::baseUrl(self::ApiUrl)->withOptions(['timeout' => 30])->timeout(30);
|
$this->http = Http::baseUrl(self::ApiUrl)->withOptions(['timeout' => 1800])->timeout(1800);
|
||||||
$this->filesystem = new Filesystem(new LocalFilesystemAdapter(base_path()));
|
$this->filesystem = new Filesystem(new LocalFilesystemAdapter(base_path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +54,7 @@ class UpgradeService
|
|||||||
public function getVersions(): Collection
|
public function getVersions(): Collection
|
||||||
{
|
{
|
||||||
if (! $this->versions) {
|
if (! $this->versions) {
|
||||||
$response = $this->http->timeout(30)->get('/versions');
|
$response = $this->http->get('/versions');
|
||||||
if (! $response->successful()) {
|
if (! $response->successful()) {
|
||||||
throw new \Exception('无法请求升级服务器');
|
throw new \Exception('无法请求升级服务器');
|
||||||
}
|
}
|
||||||
@@ -82,17 +81,23 @@ class UpgradeService
|
|||||||
$this->setProgress('准备升级...');
|
$this->setProgress('准备升级...');
|
||||||
|
|
||||||
@ini_set('memory_limit', '1G');
|
@ini_set('memory_limit', '1G');
|
||||||
|
@ini_set('max_execution_time', '86400');
|
||||||
// 获取差异信息
|
// 获取差异信息
|
||||||
$response = $this->http->timeout(30)->get('/diff/'.urlencode(Utils::config(ConfigKey::AppVersion)));
|
$response = $this->http->get('/diff/'.urlencode(Utils::config(ConfigKey::AppVersion)));
|
||||||
if (! $response->successful()) {
|
if ($response->failed()) {
|
||||||
throw new \Exception('无法请求升级服务器');
|
throw new \Exception('无法请求升级服务器');
|
||||||
}
|
}
|
||||||
$files = $response->json();
|
$result = $response->json();
|
||||||
|
$files = $result['files'];
|
||||||
|
|
||||||
$this->setProgress('下载补丁包...');
|
$this->setProgress('下载补丁包...');
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
if ($file['action'] === 'deleted') continue;
|
if ($file['action'] === 'deleted') continue;
|
||||||
$this->filesystem->write($this->temp.'/'.$file['pathname'], base64_decode($file['content']));
|
$res = $this->http->baseUrl($result['download_url'])->get($file['pathname']);
|
||||||
|
if ($res->failed()) {
|
||||||
|
throw new \Exception("补丁文件 {$file['pathname']} 下载失败。");
|
||||||
|
}
|
||||||
|
$this->filesystem->write($this->temp.'/'.$file['pathname'], $res->body());
|
||||||
// 校验文件
|
// 校验文件
|
||||||
if ($file['md5'] !== md5_file(base_path($this->temp).'/'.$file['pathname'])) {
|
if ($file['md5'] !== md5_file(base_path($this->temp).'/'.$file['pathname'])) {
|
||||||
throw new \Exception("补丁文件 {$file['pathname']} 校验失败。");
|
throw new \Exception("补丁文件 {$file['pathname']} 校验失败。");
|
||||||
@@ -110,9 +115,9 @@ class UpgradeService
|
|||||||
$version = $this->getVersions()->first()['name'];
|
$version = $this->getVersions()->first()['name'];
|
||||||
Config::query()->where('name', ConfigKey::AppVersion)->update(['value' => $version]);
|
Config::query()->where('name', ConfigKey::AppVersion)->update(['value' => $version]);
|
||||||
// 执行数据库迁移
|
// 执行数据库迁移
|
||||||
Artisan::call('migrate');
|
Artisan::call('migrate', ['--seed' => true]);
|
||||||
// 清除配置缓存
|
// 清除缓存
|
||||||
Cache::forget('configs');
|
Artisan::call('optimize:clear');
|
||||||
Artisan::call('package:discover');
|
Artisan::call('package:discover');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Utils::e($e, '升级失败');
|
Utils::e($e, '升级失败');
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ class UserService
|
|||||||
*
|
*
|
||||||
* @param array $keys
|
* @param array $keys
|
||||||
* @param User|null $user 传入用户数据则会根据用户id过滤
|
* @param User|null $user 传入用户数据则会根据用户id过滤
|
||||||
|
* @param string $field
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function deleteImages(array $keys, ?User $user = null): int
|
public function deleteImages(array $keys, ?User $user = null, string $field = 'id'): int
|
||||||
{
|
{
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$model = Image::with('user', 'strategy', 'album')->when(! is_null($user), function (Builder $builder) use ($user) {
|
$model = Image::with('user', 'strategy', 'album')->when(! is_null($user), function (Builder $builder) use ($user) {
|
||||||
$builder->where('user_id', $user->id);
|
$builder->where('user_id', $user->id);
|
||||||
})->whereIn('id', $keys);
|
})->whereIn($field, $keys);
|
||||||
|
|
||||||
DB::transaction(function () use ($model, $keys, &$count) {
|
DB::transaction(function () use ($model, $keys, &$count) {
|
||||||
/** @var Image $image */
|
/** @var Image $image */
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class Utils
|
|||||||
*/
|
*/
|
||||||
public static function getAvatar($email, int $s = 96, string $d = 'mp', string $r = 'g'): string
|
public static function getAvatar($email, int $s = 96, string $d = 'mp', string $r = 'g'): string
|
||||||
{
|
{
|
||||||
$url = 'https://gravatar.cat.net/avatar/';
|
$url = 'https://cravatar.cn/avatar/';
|
||||||
$url .= md5(strtolower(trim($email)));
|
$url .= md5(strtolower(trim($email)));
|
||||||
$url .= "?s=$s&d=$d&r=$r";
|
$url .= "?s=$s&d=$d&r=$r";
|
||||||
return $url;
|
return $url;
|
||||||
@@ -147,7 +147,7 @@ class Utils
|
|||||||
{
|
{
|
||||||
foreach ($array as &$value) {
|
foreach ($array as &$value) {
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
$value = self::filter($value);
|
$value = self::filter($value, $callback, $mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return array_filter($array, $callback, $mode);
|
return array_filter($array, $callback, $mode);
|
||||||
|
|||||||
@@ -12,16 +12,19 @@
|
|||||||
"fruitcake/laravel-cors": "^2.0.5",
|
"fruitcake/laravel-cors": "^2.0.5",
|
||||||
"guzzlehttp/guzzle": "^7.2",
|
"guzzlehttp/guzzle": "^7.2",
|
||||||
"intervention/image": "^2.7",
|
"intervention/image": "^2.7",
|
||||||
|
"intervention/imagecache": "^2.5",
|
||||||
"laravel/breeze": "^1.8",
|
"laravel/breeze": "^1.8",
|
||||||
"laravel/framework": "^9.0",
|
"laravel/framework": "^9.0",
|
||||||
|
"laravel/octane": "^1.2",
|
||||||
"laravel/sanctum": "^2.14",
|
"laravel/sanctum": "^2.14",
|
||||||
"laravel/tinker": "^2.7",
|
"laravel/tinker": "^2.7",
|
||||||
"league/flysystem-aws-s3-v3": "^3.0",
|
"league/flysystem-aws-s3-v3": "^3.0",
|
||||||
"league/flysystem-ftp": "^3.0",
|
"league/flysystem-ftp": "^3.0",
|
||||||
"league/flysystem-sftp": "^3.0",
|
"league/flysystem-sftp-v3": "^3.0",
|
||||||
"league/flysystem-webdav": "^3.0",
|
"league/flysystem-webdav": "^3.0",
|
||||||
"overtrue/flysystem-cos": "^5.0",
|
"overtrue/flysystem-cos": "^5.0",
|
||||||
"overtrue/flysystem-qiniu": "^3.0",
|
"overtrue/flysystem-qiniu": "^3.0",
|
||||||
|
"tencentcloud/ims": "^3.0",
|
||||||
"wispx/flysystem-upyun": "^1.0",
|
"wispx/flysystem-upyun": "^1.0",
|
||||||
"zing/flysystem-oss": "^2.1"
|
"zing/flysystem-oss": "^2.1"
|
||||||
},
|
},
|
||||||
|
|||||||
3779
composer.lock
generated
3779
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -194,4 +194,11 @@ return [
|
|||||||
// ...
|
// ...
|
||||||
])->toArray(),
|
])->toArray(),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Lsky configs
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
'thumbnail_path' => env('THUMBNAIL_PATH', 'thumbnails')
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -4,15 +4,21 @@
|
|||||||
|
|
||||||
use App\Enums\ConfigKey;
|
use App\Enums\ConfigKey;
|
||||||
use App\Enums\GroupConfigKey;
|
use App\Enums\GroupConfigKey;
|
||||||
|
use App\Enums\ImagePermission;
|
||||||
use App\Enums\Mail\SmtpOption;
|
use App\Enums\Mail\SmtpOption;
|
||||||
|
use App\Enums\PastedAction;
|
||||||
use App\Enums\Scan\AliyunOption;
|
use App\Enums\Scan\AliyunOption;
|
||||||
|
use App\Enums\Scan\NsfwJsOption;
|
||||||
|
use App\Enums\Scan\TencentOption;
|
||||||
|
use App\Enums\UserConfigKey;
|
||||||
use App\Enums\Watermark\FontOption;
|
use App\Enums\Watermark\FontOption;
|
||||||
use App\Enums\Watermark\ImageOption;
|
use App\Enums\Watermark\ImageOption;
|
||||||
|
use App\Enums\Watermark\Mode;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'app' => [
|
'app' => [
|
||||||
ConfigKey::AppName => 'Lsky Pro',
|
ConfigKey::AppName => 'Lsky Pro',
|
||||||
ConfigKey::AppVersion => 'V 2.0',
|
ConfigKey::AppVersion => 'V 2.1',
|
||||||
ConfigKey::SiteKeywords => 'Lsky Pro,lsky,兰空图床',
|
ConfigKey::SiteKeywords => 'Lsky Pro,lsky,兰空图床',
|
||||||
ConfigKey::SiteDescription => 'Lsky Pro, Your photo album on the cloud.',
|
ConfigKey::SiteDescription => 'Lsky Pro, Your photo album on the cloud.',
|
||||||
ConfigKey::SiteNotice => '',
|
ConfigKey::SiteNotice => '',
|
||||||
@@ -37,59 +43,81 @@ return [
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
ConfigKey::Group => [
|
|
||||||
GroupConfigKey::MaximumFileSize => 5120,
|
|
||||||
GroupConfigKey::ConcurrentUploadNum => 3,
|
|
||||||
GroupConfigKey::IsEnableScan => 0,
|
|
||||||
GroupConfigKey::IsEnableWatermark => 0,
|
|
||||||
GroupConfigKey::IsEnableOriginalProtection => 0,
|
|
||||||
GroupConfigKey::ScannedAction => 'mark', // in mark or delete
|
|
||||||
GroupConfigKey::ScanConfigs => [
|
|
||||||
'driver' => 'aliyun',
|
|
||||||
'drivers' => [
|
|
||||||
'aliyun' => [
|
|
||||||
AliyunOption::AccessKeyId => '',
|
|
||||||
AliyunOption::AccessKeySecret => '',
|
|
||||||
AliyunOption::RegionId => '',
|
|
||||||
AliyunOption::Scenes => ['porn'],
|
|
||||||
AliyunOption::BizType => '',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
GroupConfigKey::WatermarkConfigs => [
|
|
||||||
'driver' => 'font',
|
|
||||||
'drivers' => [
|
|
||||||
'font' => [
|
|
||||||
FontOption::Text => 'Lsky Pro',
|
|
||||||
FontOption::Position => 'bottom-right',
|
|
||||||
FontOption::Angle => 0,
|
|
||||||
FontOption::Size => 50,
|
|
||||||
FontOption::Font => '',
|
|
||||||
FontOption::Color => '#000000',
|
|
||||||
FontOption::X => 10,
|
|
||||||
FontOption::Y => 10,
|
|
||||||
],
|
|
||||||
'image' => [
|
|
||||||
ImageOption::Image => '',
|
|
||||||
ImageOption::Position => 'bottom-right',
|
|
||||||
ImageOption::Opacity => 100,
|
|
||||||
ImageOption::Rotate => 0,
|
|
||||||
ImageOption::Width => 0,
|
|
||||||
ImageOption::Height => 0,
|
|
||||||
ImageOption::X => 10,
|
|
||||||
ImageOption::Y => 10,
|
|
||||||
]
|
|
||||||
],
|
|
||||||
],
|
|
||||||
GroupConfigKey::LimitPerMinute => 20,
|
|
||||||
GroupConfigKey::LimitPerHour => 100,
|
|
||||||
GroupConfigKey::LimitPerDay => 300,
|
|
||||||
GroupConfigKey::LimitPerWeek => 600,
|
|
||||||
GroupConfigKey::LimitPerMonth => 999,
|
|
||||||
GroupConfigKey::AcceptedFileSuffixes => ['jpeg', 'jpg', 'png', 'gif', 'tif', 'bmp', 'ico', 'psd', 'webp'],
|
|
||||||
GroupConfigKey::PathNamingRule => '{Y}/{m}/{d}',
|
|
||||||
GroupConfigKey::FileNamingRule => '{uniqid}',
|
|
||||||
GroupConfigKey::ImageCacheTtl => 2626560,
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
|
'group' => [
|
||||||
|
GroupConfigKey::MaximumFileSize => 5120,
|
||||||
|
GroupConfigKey::ConcurrentUploadNum => 3,
|
||||||
|
GroupConfigKey::IsEnableScan => 0,
|
||||||
|
GroupConfigKey::IsEnableWatermark => 0,
|
||||||
|
GroupConfigKey::IsEnableOriginalProtection => 0,
|
||||||
|
GroupConfigKey::ScannedAction => 'mark', // in mark or delete
|
||||||
|
GroupConfigKey::ScanConfigs => [
|
||||||
|
'driver' => 'tencent',
|
||||||
|
'drivers' => [
|
||||||
|
'tencent' => [
|
||||||
|
TencentOption::Endpoint => 'ims.tencentcloudapi.com',
|
||||||
|
TencentOption::SecretId => '',
|
||||||
|
TencentOption::SecretKey => '',
|
||||||
|
TencentOption::Region => '',
|
||||||
|
TencentOption::BizType => ''
|
||||||
|
],
|
||||||
|
'aliyun' => [
|
||||||
|
AliyunOption::AccessKeyId => '',
|
||||||
|
AliyunOption::AccessKeySecret => '',
|
||||||
|
AliyunOption::RegionId => '',
|
||||||
|
AliyunOption::Scenes => ['porn'],
|
||||||
|
AliyunOption::BizType => '',
|
||||||
|
],
|
||||||
|
'nsfwjs' => [
|
||||||
|
NsfwJsOption::ApiUrl => '',
|
||||||
|
NsfwJsOption::AttrName => 'image',
|
||||||
|
NsfwJsOption::Threshold => 60,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
GroupConfigKey::WatermarkConfigs => [
|
||||||
|
'mode' => Mode::Overlay,
|
||||||
|
'driver' => 'font',
|
||||||
|
'drivers' => [
|
||||||
|
'font' => [
|
||||||
|
FontOption::Text => 'Lsky Pro',
|
||||||
|
FontOption::Position => 'bottom-right',
|
||||||
|
FontOption::Angle => 0,
|
||||||
|
FontOption::Size => 50,
|
||||||
|
FontOption::Font => '',
|
||||||
|
FontOption::Color => '#000000',
|
||||||
|
FontOption::X => 10,
|
||||||
|
FontOption::Y => 10,
|
||||||
|
],
|
||||||
|
'image' => [
|
||||||
|
ImageOption::Image => '',
|
||||||
|
ImageOption::Position => 'bottom-right',
|
||||||
|
ImageOption::Opacity => 100,
|
||||||
|
ImageOption::Rotate => 0,
|
||||||
|
ImageOption::Width => 0,
|
||||||
|
ImageOption::Height => 0,
|
||||||
|
ImageOption::X => 10,
|
||||||
|
ImageOption::Y => 10,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
GroupConfigKey::LimitPerMinute => 20,
|
||||||
|
GroupConfigKey::LimitPerHour => 100,
|
||||||
|
GroupConfigKey::LimitPerDay => 300,
|
||||||
|
GroupConfigKey::LimitPerWeek => 600,
|
||||||
|
GroupConfigKey::LimitPerMonth => 999,
|
||||||
|
GroupConfigKey::AcceptedFileSuffixes => ['jpeg', 'jpg', 'png', 'gif', 'tif', 'bmp', 'ico', 'psd', 'webp', 'svg'],
|
||||||
|
GroupConfigKey::ImageSaveFormat => '',
|
||||||
|
GroupConfigKey::ImageSaveQuality => 75,
|
||||||
|
GroupConfigKey::PathNamingRule => '{Y}/{m}/{d}',
|
||||||
|
GroupConfigKey::FileNamingRule => '{uniqid}',
|
||||||
|
GroupConfigKey::ImageCacheTtl => 2626560,
|
||||||
|
],
|
||||||
|
'user' => [
|
||||||
|
UserConfigKey::DefaultAlbum => 0,
|
||||||
|
UserConfigKey::DefaultStrategy => 0,
|
||||||
|
UserConfigKey::DefaultPermission => ImagePermission::Private,
|
||||||
|
UserConfigKey::PastedAction => PastedAction::Waiting,
|
||||||
|
UserConfigKey::IsAutoClearPreview => false,
|
||||||
|
]
|
||||||
];
|
];
|
||||||
|
|||||||
238
config/octane.php
Normal file
238
config/octane.php
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Laravel\Octane\Contracts\OperationTerminated;
|
||||||
|
use Laravel\Octane\Events\RequestHandled;
|
||||||
|
use Laravel\Octane\Events\RequestReceived;
|
||||||
|
use Laravel\Octane\Events\RequestTerminated;
|
||||||
|
use Laravel\Octane\Events\TaskReceived;
|
||||||
|
use Laravel\Octane\Events\TaskTerminated;
|
||||||
|
use Laravel\Octane\Events\TickReceived;
|
||||||
|
use Laravel\Octane\Events\TickTerminated;
|
||||||
|
use Laravel\Octane\Events\WorkerErrorOccurred;
|
||||||
|
use Laravel\Octane\Events\WorkerStarting;
|
||||||
|
use Laravel\Octane\Events\WorkerStopping;
|
||||||
|
use Laravel\Octane\Listeners\CollectGarbage;
|
||||||
|
use Laravel\Octane\Listeners\DisconnectFromDatabases;
|
||||||
|
use Laravel\Octane\Listeners\EnsureUploadedFilesAreValid;
|
||||||
|
use Laravel\Octane\Listeners\EnsureUploadedFilesCanBeMoved;
|
||||||
|
use Laravel\Octane\Listeners\FlushTemporaryContainerInstances;
|
||||||
|
use Laravel\Octane\Listeners\FlushUploadedFiles;
|
||||||
|
use Laravel\Octane\Listeners\ReportException;
|
||||||
|
use Laravel\Octane\Listeners\StopWorkerIfNecessary;
|
||||||
|
use Laravel\Octane\Octane;
|
||||||
|
use Swoole\Constant;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Octane Server
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value determines the default "server" that will be used by Octane
|
||||||
|
| when starting, restarting, or stopping your server via the CLI. You
|
||||||
|
| are free to change this to the supported server of your choosing.
|
||||||
|
|
|
||||||
|
| Supported: "roadrunner", "swoole"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'server' => env('OCTANE_SERVER', 'roadrunner'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Force HTTPS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When this configuration value is set to "true", Octane will inform the
|
||||||
|
| framework that all absolute links must be generated using the HTTPS
|
||||||
|
| protocol. Otherwise your links may be generated using plain HTTP.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'https' => env('OCTANE_HTTPS', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Octane Listeners
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| All of the event listeners for Octane's events are defined below. These
|
||||||
|
| listeners are responsible for resetting your application's state for
|
||||||
|
| the next request. You may even add your own listeners to the list.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'listeners' => [
|
||||||
|
WorkerStarting::class => [
|
||||||
|
EnsureUploadedFilesAreValid::class,
|
||||||
|
EnsureUploadedFilesCanBeMoved::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
RequestReceived::class => [
|
||||||
|
...Octane::prepareApplicationForNextOperation(),
|
||||||
|
...Octane::prepareApplicationForNextRequest(),
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
RequestHandled::class => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
RequestTerminated::class => [
|
||||||
|
// FlushUploadedFiles::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
TaskReceived::class => [
|
||||||
|
...Octane::prepareApplicationForNextOperation(),
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
TaskTerminated::class => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
TickReceived::class => [
|
||||||
|
...Octane::prepareApplicationForNextOperation(),
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
TickTerminated::class => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
OperationTerminated::class => [
|
||||||
|
FlushTemporaryContainerInstances::class,
|
||||||
|
// DisconnectFromDatabases::class,
|
||||||
|
// CollectGarbage::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
WorkerErrorOccurred::class => [
|
||||||
|
ReportException::class,
|
||||||
|
StopWorkerIfNecessary::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
WorkerStopping::class => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Warm / Flush Bindings
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The bindings listed below will either be pre-warmed when a worker boots
|
||||||
|
| or they will be flushed before every new request. Flushing a binding
|
||||||
|
| will force the container to resolve that binding again when asked.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'warm' => [
|
||||||
|
...Octane::defaultServicesToWarm(),
|
||||||
|
],
|
||||||
|
|
||||||
|
'flush' => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Octane Cache Table
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| While using Swoole, you may leverage the Octane cache, which is powered
|
||||||
|
| by a Swoole table. You may set the maximum number of rows as well as
|
||||||
|
| the number of bytes per row using the configuration options below.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'cache' => [
|
||||||
|
'rows' => 1000,
|
||||||
|
'bytes' => 10000,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Octane Swoole Tables
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| While using Swoole, you may define additional tables as required by the
|
||||||
|
| application. These tables can be used to store data that needs to be
|
||||||
|
| quickly accessed by other workers on the particular Swoole server.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'tables' => [
|
||||||
|
'example:1000' => [
|
||||||
|
'name' => 'string:1000',
|
||||||
|
'votes' => 'int',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| File Watching
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following list of files and directories will be watched when using
|
||||||
|
| the --watch option offered by Octane. If any of the directories and
|
||||||
|
| files are changed, Octane will automatically reload your workers.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'watch' => [
|
||||||
|
'app',
|
||||||
|
'bootstrap',
|
||||||
|
'config',
|
||||||
|
'database',
|
||||||
|
'public/**/*.php',
|
||||||
|
'resources/**/*.php',
|
||||||
|
'routes',
|
||||||
|
'composer.lock',
|
||||||
|
'.env',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Garbage Collection Threshold
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When executing long-lived PHP scripts such as Octane, memory can build
|
||||||
|
| up before being cleared by PHP. You can force Octane to run garbage
|
||||||
|
| collection if your application consumes this amount of megabytes.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'garbage' => 50,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Maximum Execution Time
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following setting configures the maximum execution time for requests
|
||||||
|
| being handled by Octane. You may set this value to 0 to indicate that
|
||||||
|
| there isn't a specific time limit on Octane request execution time.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'max_execution_time' => 0,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Swoole
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The Swoole options
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'swoole' => [
|
||||||
|
'options' => [
|
||||||
|
'max_request' => env('SWOOLE_MAX_REQUEST', 100000),
|
||||||
|
'package_max_length' => env('SWOOLE_PACKAGE_MAX_LENGTH', 50) * 1024 * 1024,
|
||||||
|
'buffer_output_size' => env('SWOOLE_BUFFER_OUTPUT_SIZE', 50) * 1024 * 1024,
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
];
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Config;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
class DatabaseSeeder extends Seeder
|
class DatabaseSeeder extends Seeder
|
||||||
@@ -13,6 +14,10 @@ class DatabaseSeeder extends Seeder
|
|||||||
*/
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
// $this->call([]);
|
// 初始化系统默认配置
|
||||||
|
foreach (config('convention.app') as $key => $value) {
|
||||||
|
$content = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
|
||||||
|
Config::query()->firstOrCreate(['name' => $key], ['value' => $content]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Enums\ConfigKey;
|
|
||||||
use App\Enums\StrategyKey;
|
use App\Enums\StrategyKey;
|
||||||
use App\Models\Group;
|
use App\Models\Group;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
@@ -19,9 +18,7 @@ class InstallSeeder extends Seeder
|
|||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
$date = Carbon::now()->format('Y-m-d H:i:s');
|
$date = Carbon::now()->format('Y-m-d H:i:s');
|
||||||
$array = collect(config('convention.app'))->except([
|
$array = collect(config('convention.app'))->transform(function ($value, $key) use ($date) {
|
||||||
ConfigKey::Group,
|
|
||||||
])->transform(function ($value, $key) use ($date) {
|
|
||||||
return [
|
return [
|
||||||
'name' => $key,
|
'name' => $key,
|
||||||
'value' => is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value,
|
'value' => is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value,
|
||||||
@@ -37,7 +34,7 @@ class InstallSeeder extends Seeder
|
|||||||
'name' => '系统默认组&游客组',
|
'name' => '系统默认组&游客组',
|
||||||
'is_default' => true,
|
'is_default' => true,
|
||||||
'is_guest' => true,
|
'is_guest' => true,
|
||||||
'configs' => config('convention.app.group'),
|
'configs' => config('convention.group'),
|
||||||
]);
|
]);
|
||||||
// 创建默认策略
|
// 创建默认策略
|
||||||
$group->strategies()->create([
|
$group->strategies()->create([
|
||||||
|
|||||||
5317
package-lock.json
generated
5317
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
|||||||
"@tailwindcss/forms": "^0.4.0",
|
"@tailwindcss/forms": "^0.4.0",
|
||||||
"alpinejs": "^3.4.2",
|
"alpinejs": "^3.4.2",
|
||||||
"autoprefixer": "^10.1.0",
|
"autoprefixer": "^10.1.0",
|
||||||
"axios": "^0.25",
|
"axios": "^1.8",
|
||||||
"blueimp-canvas-to-blob": "^3.29.0",
|
"blueimp-canvas-to-blob": "^3.29.0",
|
||||||
"blueimp-file-upload": "^10.32.0",
|
"blueimp-file-upload": "^10.32.0",
|
||||||
"blueimp-load-image": "^5.16.0",
|
"blueimp-load-image": "^5.16.0",
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"less-loader": "^10.2.0",
|
"less-loader": "^10.2.0",
|
||||||
"lodash": "^4.17.19",
|
"lodash": "^4.17.19",
|
||||||
"masonry-layout": "^4.2.2",
|
"masonry-layout": "^4.2.2",
|
||||||
"postcss": "^8.2.1",
|
"postcss": "^8.4.31",
|
||||||
"postcss-import": "^14.0.1",
|
"postcss-import": "^14.0.1",
|
||||||
"resolve-url-loader": "^4.0.0",
|
"resolve-url-loader": "^4.0.0",
|
||||||
"sweetalert2": "^11.3.3",
|
"sweetalert2": "^11.3.3",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/css/markdown-css/github-markdown-light.css
Normal file
1
public/css/markdown-css/github-markdown-light.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -20,5 +20,6 @@
|
|||||||
"/js/echarts/echarts.min.js": "/js/echarts/echarts.min.js",
|
"/js/echarts/echarts.min.js": "/js/echarts/echarts.min.js",
|
||||||
"/js/masonry/masonry.pkgd.min.js": "/js/masonry/masonry.pkgd.min.js",
|
"/js/masonry/masonry.pkgd.min.js": "/js/masonry/masonry.pkgd.min.js",
|
||||||
"/js/imagesloaded/imagesloaded.pkgd.min.js": "/js/imagesloaded/imagesloaded.pkgd.min.js",
|
"/js/imagesloaded/imagesloaded.pkgd.min.js": "/js/imagesloaded/imagesloaded.pkgd.min.js",
|
||||||
"/css/markdown-css/github-markdown.css": "/css/markdown-css/github-markdown.css"
|
"/css/markdown-css/github-markdown.css": "/css/markdown-css/github-markdown.css",
|
||||||
|
"/css/markdown-css/github-markdown-light.css": "/css/markdown-css/github-markdown-light.css"
|
||||||
}
|
}
|
||||||
|
|||||||
2
public/thumbnails/.gitignore
vendored
Normal file
2
public/thumbnails/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
@import '~toastr';
|
@import '~toastr';
|
||||||
|
|
||||||
|
[x-cloak] { display: none !important; }
|
||||||
|
|
||||||
.scrollbar-none::-webkit-scrollbar {
|
.scrollbar-none::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ require('./bootstrap');
|
|||||||
|
|
||||||
import Alpine from 'alpinejs';
|
import Alpine from 'alpinejs';
|
||||||
import Sidebar from './stores/sidebar';
|
import Sidebar from './stores/sidebar';
|
||||||
import Modal from './stores/modal'
|
import Modal from './stores/modal';
|
||||||
|
|
||||||
Alpine.store('sidebar', Sidebar);
|
Alpine.store('sidebar', Sidebar);
|
||||||
Alpine.store('modal', Modal)
|
Alpine.store('modal', Modal);
|
||||||
|
|
||||||
window.Alpine = Alpine;
|
window.Alpine = Alpine;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ window.utils = {
|
|||||||
|| navigator.userAgent.match(/BlackBerry/i)
|
|| navigator.userAgent.match(/BlackBerry/i)
|
||||||
|| navigator.userAgent.match(/Windows Phone/i)
|
|| navigator.userAgent.match(/Windows Phone/i)
|
||||||
) {
|
) {
|
||||||
return true;
|
return window.screen.width < 768;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
@@ -84,6 +84,7 @@ window.utils = {
|
|||||||
},
|
},
|
||||||
beforeSend() {
|
beforeSend() {
|
||||||
props.loading = true;
|
props.loading = true;
|
||||||
|
props.finished = false;
|
||||||
$btn.text(loadingText).addClass('disabled')
|
$btn.text(loadingText).addClass('disabled')
|
||||||
},
|
},
|
||||||
success(response) {
|
success(response) {
|
||||||
|
|||||||
@@ -1,8 +1,41 @@
|
|||||||
export default {
|
export default {
|
||||||
open: false,
|
state: {},
|
||||||
loading: false,
|
|
||||||
|
|
||||||
toggle() {
|
open(id) {
|
||||||
this.open = ! this.open;
|
this.setState(id, {open: true});
|
||||||
|
},
|
||||||
|
|
||||||
|
close(id) {
|
||||||
|
this.setState(id, {open: false});
|
||||||
|
},
|
||||||
|
|
||||||
|
isOpen(id) {
|
||||||
|
return this.getState(id).open;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle(id) {
|
||||||
|
let state = this.getState(id);
|
||||||
|
return this.setState(id, {open: state.open = ! state.open});
|
||||||
|
},
|
||||||
|
|
||||||
|
isLoading(id) {
|
||||||
|
return this.getState(id).loading ? true : false;
|
||||||
|
},
|
||||||
|
|
||||||
|
setLoading(id, loading) {
|
||||||
|
this.setState(id, loading);
|
||||||
|
},
|
||||||
|
|
||||||
|
setState(id, data) {
|
||||||
|
if (this.state[id] === undefined) {
|
||||||
|
this.state[id] = {};
|
||||||
|
}
|
||||||
|
for (let dataKey in data) {
|
||||||
|
this.state[id][dataKey] = data[dataKey];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getState(id) {
|
||||||
|
return this.state[id] || {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<div class="my-6 md:my-9">
|
<div class="my-6 md:my-9">
|
||||||
<p class="mb-3 font-semibold text-lg text-gray-700">概览</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">概览</p>
|
||||||
<div class="relative grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
<div class="relative grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
||||||
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden">
|
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden shadow-custom">
|
||||||
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
||||||
<p class="font-bold text-2xl text-red-700 truncate">
|
<p class="font-bold text-2xl text-red-700 truncate">
|
||||||
{{ \App\Utils::shortenNumber(\App\Models\Image::query()->count()) }}
|
{{ \App\Utils::shortenNumber(\App\Models\Image::query()->count()) }}
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<i class="fas fa-images text-red-600 text-2xl"></i>
|
<i class="fas fa-images text-red-600 text-2xl"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden">
|
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden shadow-custom">
|
||||||
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
||||||
<p class="font-bold text-2xl text-lime-700 truncate">
|
<p class="font-bold text-2xl text-lime-700 truncate">
|
||||||
{{ \App\Utils::shortenNumber(\App\Models\Album::query()->count()) }}
|
{{ \App\Utils::shortenNumber(\App\Models\Album::query()->count()) }}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<i class="fas fa-tags text-lime-600 text-2xl"></i>
|
<i class="fas fa-tags text-lime-600 text-2xl"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden">
|
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden shadow-custom">
|
||||||
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
||||||
<p class="font-bold text-2xl text-blue-700 truncate">
|
<p class="font-bold text-2xl text-blue-700 truncate">
|
||||||
{{ \App\Utils::shortenNumber(\App\Models\User::query()->count()) }}
|
{{ \App\Utils::shortenNumber(\App\Models\User::query()->count()) }}
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<i class="fas fa-users text-blue-600 text-2xl"></i>
|
<i class="fas fa-users text-blue-600 text-2xl"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden">
|
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden shadow-custom">
|
||||||
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
||||||
<p class="font-bold text-2xl text-cyan-700 truncate">
|
<p class="font-bold text-2xl text-cyan-700 truncate">
|
||||||
{{ \App\Utils::formatSize(\App\Models\Image::query()->sum('size') * 1024) }}
|
{{ \App\Utils::formatSize(\App\Models\Image::query()->sum('size') * 1024) }}
|
||||||
@@ -47,28 +47,28 @@
|
|||||||
<i class="fas fa-server text-cyan-600 text-2xl"></i>
|
<i class="fas fa-server text-cyan-600 text-2xl"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden">
|
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden shadow-custom">
|
||||||
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
||||||
<p class="font-bold text-2xl text-zinc-700 truncate">{{ \App\Utils::shortenNumber($numbers['today']) }}</p>
|
<p class="font-bold text-2xl text-zinc-700 truncate">{{ \App\Utils::shortenNumber($numbers['today']) }}</p>
|
||||||
<p class="text-md text-gray-600">今日上传</p>
|
<p class="text-md text-gray-600">今日上传</p>
|
||||||
</div>
|
</div>
|
||||||
<i class="fas fa-upload text-zinc-600 text-2xl"></i>
|
<i class="fas fa-upload text-zinc-600 text-2xl"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden">
|
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden shadow-custom">
|
||||||
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
||||||
<p class="font-bold text-2xl text-zinc-700 truncate">{{ \App\Utils::shortenNumber($numbers['yesterday']) }}</p>
|
<p class="font-bold text-2xl text-zinc-700 truncate">{{ \App\Utils::shortenNumber($numbers['yesterday']) }}</p>
|
||||||
<p class="text-md text-gray-600">昨日上传</p>
|
<p class="text-md text-gray-600">昨日上传</p>
|
||||||
</div>
|
</div>
|
||||||
<i class="fas fa-upload text-zinc-600 text-2xl"></i>
|
<i class="fas fa-upload text-zinc-600 text-2xl"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden">
|
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden shadow-custom">
|
||||||
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
||||||
<p class="font-bold text-2xl text-zinc-700 truncate">{{ \App\Utils::shortenNumber($numbers['week']) }}</p>
|
<p class="font-bold text-2xl text-zinc-700 truncate">{{ \App\Utils::shortenNumber($numbers['week']) }}</p>
|
||||||
<p class="text-md text-gray-600">本周上传</p>
|
<p class="text-md text-gray-600">本周上传</p>
|
||||||
</div>
|
</div>
|
||||||
<i class="fas fa-upload text-zinc-600 text-2xl"></i>
|
<i class="fas fa-upload text-zinc-600 text-2xl"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden">
|
<div class="flex justify-between rounded-md bg-white p-3 overflow-hidden shadow-custom">
|
||||||
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
<div class="flex flex-col justify-between space-y-2 w-[80%]">
|
||||||
<p class="font-bold text-2xl text-zinc-700 truncate">{{ \App\Utils::shortenNumber($numbers['month']) }}</p>
|
<p class="font-bold text-2xl text-zinc-700 truncate">{{ \App\Utils::shortenNumber($numbers['month']) }}</p>
|
||||||
<p class="text-md text-gray-600">本月上传</p>
|
<p class="text-md text-gray-600">本月上传</p>
|
||||||
@@ -78,12 +78,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mb-3 font-semibold text-lg text-gray-700">趋势</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">趋势</p>
|
||||||
<div class="relative p-4 rounded-md bg-white h-80 mb-8" id="chart">
|
<div class="relative p-4 rounded-md bg-white h-80 mb-8 shadow-custom" id="chart">
|
||||||
<canvas></canvas>
|
<canvas></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mb-3 font-semibold text-lg text-gray-700">系统情况</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">系统情况</p>
|
||||||
<div class="relative rounded-md bg-white mb-8 overflow-hidden">
|
<div class="relative rounded-md bg-white mb-8 overflow-hidden shadow-custom">
|
||||||
<dl>
|
<dl>
|
||||||
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium text-gray-500">操作系统</dt>
|
<dt class="text-sm font-medium text-gray-500">操作系统</dt>
|
||||||
@@ -119,7 +119,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mb-3 font-semibold text-lg text-gray-700">软件信息</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">软件信息</p>
|
||||||
<div class="relative rounded-md bg-white mb-8 overflow-hidden">
|
<div class="relative rounded-md bg-white mb-8 overflow-hidden shadow-custom">
|
||||||
<dl>
|
<dl>
|
||||||
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium text-gray-500">软件版本</dt>
|
<dt class="text-sm font-medium text-gray-500">软件版本</dt>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<form action="{{ route('admin.group.create') }}" method="POST">
|
<form action="{{ route('admin.group.create') }}" method="POST">
|
||||||
<div class="overflow-hidden rounded-md rounded-l-none">
|
<div class="overflow-hidden rounded-md rounded-l-none shadow-custom">
|
||||||
<div class="px-4 py-5 bg-white sm:p-6">
|
<div class="px-4 py-5 bg-white sm:p-6">
|
||||||
<div data-tab="basic" class="grid grid-cols-6 gap-6">
|
<div data-tab="basic" class="grid grid-cols-6 gap-6">
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="path_naming_rule" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>路径命名规则</label>
|
<label for="path_naming_rule" class="block text-sm font-medium text-gray-700">路径命名规则</label>
|
||||||
<x-input type="text" name="configs[path_naming_rule]" id="path_naming_rule" autocomplete="path_naming_rule" placeholder="请输入路径命名规则" value="{{ $default->get('path_naming_rule') }}" />
|
<x-input type="text" name="configs[path_naming_rule]" id="path_naming_rule" autocomplete="path_naming_rule" placeholder="请输入路径命名规则" value="{{ $default->get('path_naming_rule') }}" />
|
||||||
<a href="javascript:void(0)" class="mt-1 text-sm text-indigo-600" id="rename-rules"><i class="fas fa-pencil-alt text-xs"></i> 命名规则对照表</a>
|
<a href="javascript:void(0)" class="mt-1 text-sm text-indigo-600" id="rename-rules"><i class="fas fa-pencil-alt text-xs"></i> 命名规则对照表</a>
|
||||||
@include('admin.group.rules')
|
@include('admin.group.rules')
|
||||||
@@ -79,6 +79,21 @@
|
|||||||
<x-input type="text" name="configs[file_naming_rule]" id="file_naming_rule" autocomplete="file_naming_rule" placeholder="请输入文件命名规则" value="{{ $default->get('file_naming_rule') }}" />
|
<x-input type="text" name="configs[file_naming_rule]" id="file_naming_rule" autocomplete="file_naming_rule" placeholder="请输入文件命名规则" value="{{ $default->get('file_naming_rule') }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-6 sm:col-span-3">
|
||||||
|
<label for="image_save_quality" class="block text-sm font-medium text-gray-700">图片保存质量</label>
|
||||||
|
<x-input type="number" name="configs[image_save_quality]" id="image_save_quality" autocomplete="path_naming_rule" placeholder="请输入图片保存质量" value="{{ $default->get('image_save_quality', 100) }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-6 sm:col-span-3">
|
||||||
|
<label for="image_save_format" class="block text-sm font-medium text-gray-700">图片转换格式</label>
|
||||||
|
<x-select id="configs[image_save_format]" name="configs[image_save_format]" autocomplete="image_save_format">
|
||||||
|
<option value="">不转换格式</option>
|
||||||
|
@foreach($default->get('accepted_file_suffixes') as $extension)
|
||||||
|
<option value="{{ strtolower($extension) }}">{{ strtoupper($extension) }}</option>
|
||||||
|
@endforeach
|
||||||
|
</x-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<x-fieldset title="是否默认" faq="设置默认后,新用户注册以后将会属于该默认角色组,且默认组只能有一个。">
|
<x-fieldset title="是否默认" faq="设置默认后,新用户注册以后将会属于该默认角色组,且默认组只能有一个。">
|
||||||
<x-switch id="is_default" name="is_default" value="1"></x-switch>
|
<x-switch id="is_default" name="is_default" value="1"></x-switch>
|
||||||
@@ -116,9 +131,35 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 mb-4">
|
<div class="col-span-6 mb-4">
|
||||||
<x-fieldset title="审核驱动">
|
<x-fieldset title="审核驱动">
|
||||||
<x-fieldset-radio id="configs[scan_configs][driver]" name="configs[scan_configs][driver]" data-select="scan" value="aliyun" checked>阿里云</x-fieldset-radio>
|
<x-fieldset-radio id="configs[scan_configs][driver]_tencent" name="configs[scan_configs][driver]" data-select="scan" value="tencent" checked>腾讯云</x-fieldset-radio>
|
||||||
|
<x-fieldset-radio id="configs[scan_configs][driver]_aliyun" name="configs[scan_configs][driver]" data-select="scan" value="aliyun">阿里云</x-fieldset-radio>
|
||||||
|
<x-fieldset-radio id="configs[scan_configs][driver]_nsfwjs" name="configs[scan_configs][driver]" data-select="scan" value="nsfwjs">NsfwJs</x-fieldset-radio>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden mb-4" data-scan-driver="tencent">
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][endpoint]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Endpoint</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][tencent][endpoint]" id="configs[scan_configs][drivers][tencent][endpoint]" autocomplete="endpoint" placeholder="请输入 Endpoint" value="ims.tencentcloudapi.com" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][secret_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretId</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][tencent][secret_id]" id="configs[scan_configs][drivers][tencent][secret_id]" autocomplete="secret_id" placeholder="请输入 SecretId" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
||||||
|
<x-input type="password" name="configs[scan_configs][drivers][tencent][secret_key]" id="configs[scan_configs][drivers][tencent][secret_key]" autocomplete="secret_key" placeholder="请输入 SecretKey" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][region]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][tencent][region]" id="configs[scan_configs][drivers][tencent][region]" autocomplete="region" placeholder="请输入地域节点,例如:ap-beijing" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][biz_type]" class="block text-sm font-medium text-gray-700">场景名称</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][tencent][biz_type]" id="configs[scan_configs][drivers][tencent][biz_type]" autocomplete="biz_type" placeholder="业务场景名称,可为空" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="hidden mb-4" data-scan-driver="aliyun">
|
<div class="hidden mb-4" data-scan-driver="aliyun">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[scan_configs][drivers][aliyun][access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
<label for="configs[scan_configs][drivers][aliyun][access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
||||||
@@ -128,14 +169,14 @@
|
|||||||
<label for="configs[scan_configs][drivers][aliyun][access_key_secret]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeySecret</label>
|
<label for="configs[scan_configs][drivers][aliyun][access_key_secret]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeySecret</label>
|
||||||
<x-input type="password" name="configs[scan_configs][drivers][aliyun][access_key_secret]" id="configs[scan_configs][drivers][aliyun][access_key_secret]" autocomplete="access_key_id" placeholder="请输入 AccessKeySecret" />
|
<x-input type="password" name="configs[scan_configs][drivers][aliyun][access_key_secret]" id="configs[scan_configs][drivers][aliyun][access_key_secret]" autocomplete="access_key_id" placeholder="请输入 AccessKeySecret" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
|
||||||
<label for="configs[scan_configs][drivers][aliyun][biz_type]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>场景名称</label>
|
|
||||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][biz_type]" id="configs[scan_configs][drivers][aliyun][biz_type]" autocomplete="biz_type" placeholder="请输入业务场景名称" />
|
|
||||||
</div>
|
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[scan_configs][drivers][aliyun][region_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域节点</label>
|
<label for="configs[scan_configs][drivers][aliyun][region_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域节点</label>
|
||||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][region_id]" id="configs[scan_configs][drivers][aliyun][region_id]" autocomplete="region_id" placeholder="请输入地域节点,例如:cn-shanghai" />
|
<x-input type="text" name="configs[scan_configs][drivers][aliyun][region_id]" id="configs[scan_configs][drivers][aliyun][region_id]" autocomplete="region_id" placeholder="请输入地域节点,例如:cn-shanghai" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][aliyun][biz_type]" class="block text-sm font-medium text-gray-700">场景名称</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][aliyun][biz_type]" id="configs[scan_configs][drivers][aliyun][biz_type]" autocomplete="biz_type" placeholder="请输入业务场景名称" />
|
||||||
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<x-fieldset title="审核场景">
|
<x-fieldset title="审核场景">
|
||||||
@foreach($scenes as $key => $scene)
|
@foreach($scenes as $key => $scene)
|
||||||
@@ -144,6 +185,22 @@
|
|||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden mb-4" data-scan-driver="nsfwjs">
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][nsfwjs][api_url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>接口地址</label>
|
||||||
|
<x-input type="url" name="configs[scan_configs][drivers][nsfwjs][api_url]" id="configs[scan_configs][drivers][nsfwjs][api_url]" autocomplete="api_url" placeholder="请输入接口地址,http(s)://domain.com/classify" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][nsfwjs][attr_name]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>属性名称</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][nsfwjs][attr_name]" id="configs[scan_configs][drivers][nsfwjs][attr_name]" autocomplete="attr_name" placeholder="接口的表单文件属性名" value="image" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][nsfwjs][threshold]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>阈值</label>
|
||||||
|
<x-input type="number" name="configs[scan_configs][drivers][nsfwjs][threshold]" id="configs[scan_configs][drivers][nsfwjs][threshold]" autocomplete="threshold" placeholder="取值 1-100" value="60" />
|
||||||
|
<small class="text-gray-500"><i class="fas fa-exclamation-circle"></i> 阈值是指图片违规程度上限,取值 1-100 之间,数值越低审核越严格</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-tab="protection" class="hidden grid grid-cols-6 gap-6">
|
<div data-tab="protection" class="hidden grid grid-cols-6 gap-6">
|
||||||
@@ -162,9 +219,15 @@
|
|||||||
<div data-tab="watermark" class="hidden grid grid-cols-6 gap-6">
|
<div data-tab="watermark" class="hidden grid grid-cols-6 gap-6">
|
||||||
<p class="mb-3 text-red-600 text-sm"><i class="fas fa-exclamation"></i> 开启水印功能前请注意考虑图片版权问题。</p>
|
<p class="mb-3 text-red-600 text-sm"><i class="fas fa-exclamation"></i> 开启水印功能前请注意考虑图片版权问题。</p>
|
||||||
<div class="col-span-6 mb-4">
|
<div class="col-span-6 mb-4">
|
||||||
<x-fieldset title="开启水印" faq="请注意,水印功能仅在开启了「原图保护」功能的情况下生效。">
|
<x-fieldset title="开启水印" faq="请注意,水印模式为动态生成时,仅在开启了「原图保护」功能的情况下生效。">
|
||||||
<x-switch id="configs[is_enable_watermark]" name="configs[is_enable_watermark]" value="1"></x-switch>
|
<x-switch id="configs[is_enable_watermark]" name="configs[is_enable_watermark]" value="1"></x-switch>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
|
<div class="col-span-6 mt-4 mb-4">
|
||||||
|
<x-fieldset title="水印模式">
|
||||||
|
<x-fieldset-radio id="configs[watermark_configs][mode]_overlay" name="configs[watermark_configs][mode]" value="{{ \App\Enums\Watermark\Mode::Overlay }}" checked>覆盖原图</x-fieldset-radio>
|
||||||
|
<x-fieldset-radio id="configs[watermark_configs][mode]_dynamic" name="configs[watermark_configs][mode]" value="{{ \App\Enums\Watermark\Mode::Dynamic }}">动态生成</x-fieldset-radio>
|
||||||
|
</x-fieldset>
|
||||||
|
</div>
|
||||||
<div class="col-span-6 mt-4 mb-4">
|
<div class="col-span-6 mt-4 mb-4">
|
||||||
<x-fieldset title="水印类型">
|
<x-fieldset title="水印类型">
|
||||||
<x-fieldset-radio id="configs[watermark_configs][driver]_font" name="configs[watermark_configs][driver]" data-select="watermark" value="font" checked>文字水印</x-fieldset-radio>
|
<x-fieldset-radio id="configs[watermark_configs][driver]_font" name="configs[watermark_configs][driver]" data-select="watermark" value="font" checked>文字水印</x-fieldset-radio>
|
||||||
@@ -214,7 +277,7 @@
|
|||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][image]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印图片</label>
|
<label for="configs[watermark_configs][drivers][image][image]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印图片</label>
|
||||||
<x-input type="text" name="configs[watermark_configs][drivers][image][image]" id="configs[watermark_configs][drivers][image][image]" autocomplete="image" placeholder="请输入水印路径,例如:images/lsky.png" />
|
<x-input type="text" name="configs[watermark_configs][drivers][image][image]" id="configs[watermark_configs][drivers][image][image]" autocomplete="image" placeholder="请输入水印路径,例如:images/lsky.png" />
|
||||||
<small class="text-yellow-500">请将水印图片放置 {{ public_path() }} 目录下</small>
|
<small class="text-yellow-500">请将水印图片放置 {{ storage_path('app/public') }} 目录下</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][position]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印位置</label>
|
<label for="configs[watermark_configs][drivers][image][position]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印位置</label>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<form action="{{ route('admin.group.update', ['id' => $group->id]) }}" method="POST">
|
<form action="{{ route('admin.group.update', ['id' => $group->id]) }}" method="POST">
|
||||||
<div class="overflow-hidden rounded-md rounded-l-none">
|
<div class="overflow-hidden rounded-md rounded-l-none shadow-custom">
|
||||||
<div class="px-4 py-5 bg-white sm:p-6">
|
<div class="px-4 py-5 bg-white sm:p-6">
|
||||||
<div data-tab="basic" class="grid grid-cols-6 gap-6">
|
<div data-tab="basic" class="grid grid-cols-6 gap-6">
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
@@ -30,49 +30,64 @@
|
|||||||
|
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<label for="maximum_file_size" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>最大文件大小(KB)</label>
|
<label for="maximum_file_size" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>最大文件大小(KB)</label>
|
||||||
<x-input type="number" name="configs[maximum_file_size]" id="maximum_file_size" autocomplete="maximum_file_size" placeholder="请输入上传文件的最大限制,单位kb" value="{{ $group->configs['maximum_file_size'] }}" />
|
<x-input type="number" name="configs[maximum_file_size]" id="maximum_file_size" autocomplete="maximum_file_size" placeholder="请输入上传文件的最大限制,单位kb" value="{{ $group->configs->get('maximum_file_size') }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="concurrent_upload_num" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>并发上传限制</label>
|
<label for="concurrent_upload_num" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>并发上传限制</label>
|
||||||
<x-input type="number" name="configs[concurrent_upload_num]" id="concurrent_upload_num" autocomplete="concurrent_upload_num" placeholder="请输入并发上传数量" value="{{ $group->configs['concurrent_upload_num'] }}" />
|
<x-input type="number" name="configs[concurrent_upload_num]" id="concurrent_upload_num" autocomplete="concurrent_upload_num" placeholder="请输入并发上传数量" value="{{ $group->configs->get('concurrent_upload_num') }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="limit_per_minute" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每分钟上传限制</label>
|
<label for="limit_per_minute" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每分钟上传限制</label>
|
||||||
<x-input type="number" name="configs[limit_per_minute]" id="limit_per_minute" autocomplete="limit_per_minute" placeholder="请输入每分钟可以上传的图片数量" value="{{ $group->configs['limit_per_minute'] }}" />
|
<x-input type="number" name="configs[limit_per_minute]" id="limit_per_minute" autocomplete="limit_per_minute" placeholder="请输入每分钟可以上传的图片数量" value="{{ $group->configs->get('limit_per_minute') }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="limit_per_hour" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每小时上传限制</label>
|
<label for="limit_per_hour" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每小时上传限制</label>
|
||||||
<x-input type="number" name="configs[limit_per_hour]" id="limit_per_hour" autocomplete="limit_per_hour" placeholder="请输入每小时可以上传的图片数量" value="{{ $group->configs['limit_per_hour'] }}" />
|
<x-input type="number" name="configs[limit_per_hour]" id="limit_per_hour" autocomplete="limit_per_hour" placeholder="请输入每小时可以上传的图片数量" value="{{ $group->configs->get('limit_per_hour') }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="limit_per_day" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每天上传限制</label>
|
<label for="limit_per_day" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每天上传限制</label>
|
||||||
<x-input type="number" name="configs[limit_per_day]" id="limit_per_day" autocomplete="limit_per_day" placeholder="请输入每天可以上传的图片数量" value="{{ $group->configs['limit_per_day'] }}" />
|
<x-input type="number" name="configs[limit_per_day]" id="limit_per_day" autocomplete="limit_per_day" placeholder="请输入每天可以上传的图片数量" value="{{ $group->configs->get('limit_per_day') }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="limit_per_week" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每周上传限制</label>
|
<label for="limit_per_week" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每周上传限制</label>
|
||||||
<x-input type="number" name="configs[limit_per_week]" id="limit_per_week" autocomplete="limit_per_week" placeholder="请输入每周可以上传的图片数量" value="{{ $group->configs['limit_per_week'] }}" />
|
<x-input type="number" name="configs[limit_per_week]" id="limit_per_week" autocomplete="limit_per_week" placeholder="请输入每周可以上传的图片数量" value="{{ $group->configs->get('limit_per_week') }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="limit_per_month" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每月上传限制</label>
|
<label for="limit_per_month" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>每月上传限制</label>
|
||||||
<x-input type="number" name="configs[limit_per_month]" id="limit_per_month" autocomplete="limit_per_month" placeholder="请输入每月可以上传的图片数量" value="{{ $group->configs['limit_per_month'] }}" />
|
<x-input type="number" name="configs[limit_per_month]" id="limit_per_month" autocomplete="limit_per_month" placeholder="请输入每月可以上传的图片数量" value="{{ $group->configs->get('limit_per_month') }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="path_naming_rule" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>路径命名规则</label>
|
<label for="path_naming_rule" class="block text-sm font-medium text-gray-700">路径命名规则</label>
|
||||||
<x-input type="text" name="configs[path_naming_rule]" id="path_naming_rule" autocomplete="path_naming_rule" placeholder="请输入路径命名规则" value="{{ $group->configs['path_naming_rule'] }}" />
|
<x-input type="text" name="configs[path_naming_rule]" id="path_naming_rule" autocomplete="path_naming_rule" placeholder="请输入路径命名规则" value="{{ $group->configs->get('path_naming_rule') }}" />
|
||||||
<a href="javascript:void(0)" class="mt-1 text-sm text-indigo-600" id="rename-rules"><i class="fas fa-pencil-alt text-xs"></i> 命名规则对照表</a>
|
<a href="javascript:void(0)" class="mt-1 text-sm text-indigo-600" id="rename-rules"><i class="fas fa-pencil-alt text-xs"></i> 命名规则对照表</a>
|
||||||
@include('admin.group.rules')
|
@include('admin.group.rules')
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="file_naming_rule" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>文件命名规则</label>
|
<label for="file_naming_rule" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>文件命名规则</label>
|
||||||
<x-input type="text" name="configs[file_naming_rule]" id="file_naming_rule" autocomplete="file_naming_rule" placeholder="请输入文件命名规则" value="{{ $group->configs['file_naming_rule'] }}" />
|
<x-input type="text" name="configs[file_naming_rule]" id="file_naming_rule" autocomplete="file_naming_rule" placeholder="请输入文件命名规则" value="{{ $group->configs->get('file_naming_rule') }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-6 sm:col-span-3">
|
||||||
|
<label for="image_save_quality" class="block text-sm font-medium text-gray-700">图片保存质量</label>
|
||||||
|
<x-input type="number" name="configs[image_save_quality]" id="image_save_quality" autocomplete="path_naming_rule" placeholder="请输入图片保存质量" value="{{ $group->configs->get('image_save_quality', 100) }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-6 sm:col-span-3">
|
||||||
|
<label for="image_save_format" class="block text-sm font-medium text-gray-700">图片转换格式</label>
|
||||||
|
<x-select id="configs[image_save_format]" name="configs[image_save_format]" autocomplete="image_save_format">
|
||||||
|
<option value="">不转换格式</option>
|
||||||
|
@foreach($default->get('accepted_file_suffixes') as $extension)
|
||||||
|
<option value="{{ strtolower($extension) }}" @selected($group->configs->get('image_save_format') === $extension)>{{ strtoupper($extension) }}</option>
|
||||||
|
@endforeach
|
||||||
|
</x-select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
@@ -90,7 +105,7 @@
|
|||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<x-fieldset title="允许上传的图片类型">
|
<x-fieldset title="允许上传的图片类型">
|
||||||
@foreach($default['accepted_file_suffixes'] as $extension)
|
@foreach($default['accepted_file_suffixes'] as $extension)
|
||||||
<x-fieldset-checkbox id="configs[accepted_file_suffixes]_{{ $extension }}" name="configs[accepted_file_suffixes][]" value="{{ $extension }}" :checked="in_array($extension, $group->configs['accepted_file_suffixes'])">
|
<x-fieldset-checkbox id="configs[accepted_file_suffixes]_{{ $extension }}" name="configs[accepted_file_suffixes][]" value="{{ $extension }}" :checked="in_array($extension, $group->configs->get('accepted_file_suffixes'))">
|
||||||
{{ strtoupper($extension) }}
|
{{ strtoupper($extension) }}
|
||||||
</x-fieldset-checkbox>
|
</x-fieldset-checkbox>
|
||||||
@endforeach
|
@endforeach
|
||||||
@@ -101,57 +116,99 @@
|
|||||||
<div data-tab="review" class="hidden grid grid-cols-6 gap-6">
|
<div data-tab="review" class="hidden grid grid-cols-6 gap-6">
|
||||||
<div class="col-span-6 mb-4">
|
<div class="col-span-6 mb-4">
|
||||||
<x-fieldset title="图片审核" faq="设置上传是否需要应用第三方审查,违规的图片会被标记为不健康的图片,或直接被删除。">
|
<x-fieldset title="图片审核" faq="设置上传是否需要应用第三方审查,违规的图片会被标记为不健康的图片,或直接被删除。">
|
||||||
<x-switch id="configs[is_enable_scan]" name="configs[is_enable_scan]" value="1" :checked="(bool)$group->configs['is_enable_scan']"></x-switch>
|
<x-switch id="configs[is_enable_scan]" name="configs[is_enable_scan]" value="1" :checked="(bool)$group->configs->get('is_enable_scan')"></x-switch>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 mb-4">
|
<div class="col-span-6 mb-4">
|
||||||
<x-fieldset title="审核动作">
|
<x-fieldset title="审核动作">
|
||||||
<x-fieldset-radio id="configs[scanned_action]_mark" name="configs[scanned_action]" value="mark" :checked="$group->configs['scanned_action'] === 'mark'">标记为不健康</x-fieldset-radio>
|
<x-fieldset-radio id="configs[scanned_action]_mark" name="configs[scanned_action]" value="mark" :checked="$group->configs->get('scanned_action') === 'mark'">标记为不健康</x-fieldset-radio>
|
||||||
<x-fieldset-radio id="configs[scanned_action]_delete" name="configs[scanned_action]" value="delete" :checked="$group->configs['scanned_action'] === 'delete'">直接删除</x-fieldset-radio>
|
<x-fieldset-radio id="configs[scanned_action]_delete" name="configs[scanned_action]" value="delete" :checked="$group->configs->get('scanned_action') === 'delete'">直接删除</x-fieldset-radio>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 mb-4">
|
<div class="col-span-6 mb-4">
|
||||||
<x-fieldset title="审核驱动">
|
<x-fieldset title="审核驱动">
|
||||||
<x-fieldset-radio id="configs[scan_configs][driver]" name="configs[scan_configs][driver]" data-select="scan" value="aliyun" :checked="$group->configs['scan_configs']['driver'] === 'aliyun'">阿里云</x-fieldset-radio>
|
<x-fieldset-radio id="configs[scan_configs][driver]_tencent" name="configs[scan_configs][driver]" data-select="scan" value="tencent" :checked="($group->configs['scan_configs']['driver'] ?? '') === 'tencent'">腾讯云</x-fieldset-radio>
|
||||||
|
<x-fieldset-radio id="configs[scan_configs][driver]_aliyun" name="configs[scan_configs][driver]" data-select="scan" value="aliyun" :checked="($group->configs['scan_configs']['driver'] ?? '') === 'aliyun'">阿里云</x-fieldset-radio>
|
||||||
|
<x-fieldset-radio id="configs[scan_configs][driver]_nsfwjs" name="configs[scan_configs][driver]" data-select="scan" value="nsfwjs" :checked="($group->configs['scan_configs']['driver'] ?? '') === 'nsfwjs'">NsfwJs</x-fieldset-radio>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden mb-4" data-scan-driver="tencent">
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][endpoint]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Endpoint</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][tencent][endpoint]" id="configs[scan_configs][drivers][tencent][endpoint]" autocomplete="endpoint" placeholder="请输入 Endpoint" value="{{ $group->configs['scan_configs']['drivers']['tencent']['endpoint'] ?? '' }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][secret_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretId</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][tencent][secret_id]" id="configs[scan_configs][drivers][tencent][secret_id]" autocomplete="secret_id" placeholder="请输入 SecretId" value="{{ $group->configs['scan_configs']['drivers']['tencent']['secret_id'] ?? '' }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
||||||
|
<x-input type="password" name="configs[scan_configs][drivers][tencent][secret_key]" id="configs[scan_configs][drivers][tencent][secret_key]" autocomplete="secret_key" placeholder="请输入 SecretKey" value="{{ $group->configs['scan_configs']['drivers']['tencent']['secret_key'] ?? '' }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][region]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][tencent][region]" id="configs[scan_configs][drivers][tencent][region]" autocomplete="region" placeholder="请输入地域节点,例如:ap-beijing" value="{{ $group->configs['scan_configs']['drivers']['tencent']['region'] ?? '' }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][tencent][biz_type]" class="block text-sm font-medium text-gray-700">场景名称</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][tencent][biz_type]" id="configs[scan_configs][drivers][tencent][biz_type]" autocomplete="biz_type" placeholder="业务场景名称,可为空" value="{{ $group->configs['scan_configs']['drivers']['tencent']['biz_type'] ?? '' }}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="hidden mb-4" data-scan-driver="aliyun">
|
<div class="hidden mb-4" data-scan-driver="aliyun">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[scan_configs][drivers][aliyun][access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
<label for="configs[scan_configs][drivers][aliyun][access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
||||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][access_key_id]" id="configs[scan_configs][drivers][aliyun][access_key_id]" autocomplete="access_key_id" placeholder="请输入 AccessKeyId" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['access_key_id'] }}" />
|
<x-input type="text" name="configs[scan_configs][drivers][aliyun][access_key_id]" id="configs[scan_configs][drivers][aliyun][access_key_id]" autocomplete="access_key_id" placeholder="请输入 AccessKeyId" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['access_key_id'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[scan_configs][drivers][aliyun][access_key_secret]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeySecret</label>
|
<label for="configs[scan_configs][drivers][aliyun][access_key_secret]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeySecret</label>
|
||||||
<x-input type="password" name="configs[scan_configs][drivers][aliyun][access_key_secret]" id="configs[scan_configs][drivers][aliyun][access_key_secret]" autocomplete="access_key_id" placeholder="请输入 AccessKeySecret" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['access_key_secret'] }}" />
|
<x-input type="password" name="configs[scan_configs][drivers][aliyun][access_key_secret]" id="configs[scan_configs][drivers][aliyun][access_key_secret]" autocomplete="access_key_id" placeholder="请输入 AccessKeySecret" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['access_key_secret'] ?? '' }}" />
|
||||||
</div>
|
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
|
||||||
<label for="configs[scan_configs][drivers][aliyun][biz_type]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>场景名称</label>
|
|
||||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][biz_type]" id="configs[scan_configs][drivers][aliyun][biz_type]" autocomplete="biz_type" placeholder="请输入业务场景名称" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['biz_type'] }}" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[scan_configs][drivers][aliyun][region_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域节点</label>
|
<label for="configs[scan_configs][drivers][aliyun][region_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域节点</label>
|
||||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][region_id]" id="configs[scan_configs][drivers][aliyun][region_id]" autocomplete="region_id" placeholder="请输入地域节点,例如:cn-shanghai" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['region_id'] }}" />
|
<x-input type="text" name="configs[scan_configs][drivers][aliyun][region_id]" id="configs[scan_configs][drivers][aliyun][region_id]" autocomplete="region_id" placeholder="请输入地域节点,例如:cn-shanghai" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['region_id'] ?? '' }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][aliyun][biz_type]" class="block text-sm font-medium text-gray-700">场景名称</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][aliyun][biz_type]" id="configs[scan_configs][drivers][aliyun][biz_type]" autocomplete="biz_type" placeholder="请输入业务场景名称" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['biz_type'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<x-fieldset title="审核场景">
|
<x-fieldset title="审核场景">
|
||||||
@foreach($scenes as $key => $scene)
|
@foreach($scenes as $key => $scene)
|
||||||
<x-fieldset-checkbox id="configs[scan_configs][drivers][aliyun][scenes][]_{{ $key }}" name="configs[scan_configs][drivers][aliyun][scenes][]" value="{{ $key }}" :checked="in_array($key, $group->configs['scan_configs']['drivers']['aliyun']['scenes'])">{{ $scene }}</x-fieldset-checkbox>
|
<x-fieldset-checkbox id="configs[scan_configs][drivers][aliyun][scenes][]_{{ $key }}" name="configs[scan_configs][drivers][aliyun][scenes][]" value="{{ $key }}" :checked="in_array($key, ($group->configs['scan_configs']['drivers']['aliyun']['scenes'] ?? []))">{{ $scene }}</x-fieldset-checkbox>
|
||||||
@endforeach
|
@endforeach
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden mb-4" data-scan-driver="nsfwjs">
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][nsfwjs][api_url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>接口地址</label>
|
||||||
|
<x-input type="url" name="configs[scan_configs][drivers][nsfwjs][api_url]" id="configs[scan_configs][drivers][nsfwjs][api_url]" autocomplete="api_url" placeholder="请输入接口地址,http(s)://domain.com/classify" value="{{ $group->configs['scan_configs']['drivers']['nsfwjs']['api_url'] ?? '' }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][nsfwjs][attr_name]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>属性名称</label>
|
||||||
|
<x-input type="text" name="configs[scan_configs][drivers][nsfwjs][attr_name]" id="configs[scan_configs][drivers][nsfwjs][attr_name]" autocomplete="attr_name" placeholder="接口的表单文件属性名" value="{{ $group->configs['scan_configs']['drivers']['nsfwjs']['attr_name'] ?? '' }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[scan_configs][drivers][nsfwjs][threshold]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>阈值</label>
|
||||||
|
<x-input type="number" name="configs[scan_configs][drivers][nsfwjs][threshold]" id="configs[scan_configs][drivers][nsfwjs][threshold]" autocomplete="threshold" placeholder="取值 1-100" value="{{ $group->configs['scan_configs']['drivers']['nsfwjs']['threshold'] ?? '' }}" />
|
||||||
|
<small class="text-gray-500"><i class="fas fa-exclamation-circle"></i> 阈值是指图片违规程度上限,取值 1-100 之间,数值越低审核越严格</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-tab="protection" class="hidden grid grid-cols-6 gap-6">
|
<div data-tab="protection" class="hidden grid grid-cols-6 gap-6">
|
||||||
<div class="col-span-6 mb-4">
|
<div class="col-span-6 mb-4">
|
||||||
<x-fieldset title="原图保护" faq="设置该角色组下的用户上传的图片是否应用原图保护功能,开启后图片<b>不返回直链</b>">
|
<x-fieldset title="原图保护" faq="设置该角色组下的用户上传的图片是否应用原图保护功能,开启后图片<b>不返回直链</b>">
|
||||||
<x-switch id="configs[is_enable_original_protection]" name="configs[is_enable_original_protection]" value="1" :checked="(bool)$group->configs['is_enable_original_protection']"></x-switch>
|
<x-switch id="configs[is_enable_original_protection]" name="configs[is_enable_original_protection]" value="1" :checked="(bool)$group->configs->get('is_enable_original_protection')"></x-switch>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6 mb-4">
|
<div class="col-span-6 mb-4">
|
||||||
<label for="configs[image_cache_ttl]" class="block text-sm font-medium text-gray-700">图片缓存时间(秒)</label>
|
<label for="configs[image_cache_ttl]" class="block text-sm font-medium text-gray-700">图片缓存时间(秒)</label>
|
||||||
<x-input type="number" name="configs[image_cache_ttl]" id="configs[image_cache_ttl]" autocomplete="image_cache_ttl" placeholder="请输入受保护图片的缓存时间,不填或填0表示不缓存" value="{{ $group->configs['image_cache_ttl'] }}" />
|
<x-input type="number" name="configs[image_cache_ttl]" id="configs[image_cache_ttl]" autocomplete="image_cache_ttl" placeholder="请输入受保护图片的缓存时间,不填或填0表示不缓存" value="{{ $group->configs->get('image_cache_ttl') }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="javascript:void(0)" id="clear-cache" class="text-sm text-red-500">
|
<a href="javascript:void(0)" id="clear-cache" class="text-sm text-red-500">
|
||||||
@@ -162,91 +219,97 @@
|
|||||||
<div data-tab="watermark" class="hidden grid grid-cols-6 gap-6">
|
<div data-tab="watermark" class="hidden grid grid-cols-6 gap-6">
|
||||||
<p class="mb-3 text-red-600 text-sm"><i class="fas fa-exclamation"></i> 开启水印功能前请注意考虑图片版权问题。</p>
|
<p class="mb-3 text-red-600 text-sm"><i class="fas fa-exclamation"></i> 开启水印功能前请注意考虑图片版权问题。</p>
|
||||||
<div class="col-span-6 mb-4">
|
<div class="col-span-6 mb-4">
|
||||||
<x-fieldset title="开启水印" faq="请注意,水印功能仅在开启了「原图保护」功能的情况下生效。">
|
<x-fieldset title="开启水印" faq="请注意,水印模式为动态生成时,仅在开启了「原图保护」功能的情况下生效。">
|
||||||
<x-switch id="configs[is_enable_watermark]" name="configs[is_enable_watermark]" value="1" :checked="(bool)$group->configs['is_enable_watermark']"></x-switch>
|
<x-switch id="configs[is_enable_watermark]" name="configs[is_enable_watermark]" value="1" :checked="(bool)$group->configs->get('is_enable_watermark')"></x-switch>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
|
<div class="col-span-6 mt-4 mb-4">
|
||||||
|
<x-fieldset title="水印模式">
|
||||||
|
<x-fieldset-radio id="configs[watermark_configs][mode]_overlay" name="configs[watermark_configs][mode]" value="{{ \App\Enums\Watermark\Mode::Overlay }}" :checked="($group->configs['watermark_configs']['mode'] ?? '') == \App\Enums\Watermark\Mode::Overlay">覆盖原图</x-fieldset-radio>
|
||||||
|
<x-fieldset-radio id="configs[watermark_configs][mode]_dynamic" name="configs[watermark_configs][mode]" value="{{ \App\Enums\Watermark\Mode::Dynamic }}" :checked="($group->configs['watermark_configs']['mode'] ?? '') == \App\Enums\Watermark\Mode::Dynamic">动态生成</x-fieldset-radio>
|
||||||
|
</x-fieldset>
|
||||||
|
</div>
|
||||||
<div class="col-span-6 mt-4 mb-4">
|
<div class="col-span-6 mt-4 mb-4">
|
||||||
<x-fieldset title="水印类型">
|
<x-fieldset title="水印类型">
|
||||||
<x-fieldset-radio id="configs[watermark_configs][driver]_font" name="configs[watermark_configs][driver]" data-select="watermark" value="font" :checked="$group->configs['watermark_configs']['driver'] === 'font'">文字水印</x-fieldset-radio>
|
<x-fieldset-radio id="configs[watermark_configs][driver]_font" name="configs[watermark_configs][driver]" data-select="watermark" value="font" :checked="($group->configs['watermark_configs']['driver'] ?? '') === 'font'">文字水印</x-fieldset-radio>
|
||||||
<x-fieldset-radio id="configs[watermark_configs][driver]_image" name="configs[watermark_configs][driver]" data-select="watermark" value="image" :checked="$group->configs['watermark_configs']['driver'] === 'image'">图片水印</x-fieldset-radio>
|
<x-fieldset-radio id="configs[watermark_configs][driver]_image" name="configs[watermark_configs][driver]" data-select="watermark" value="image" :checked="($group->configs['watermark_configs']['driver'] ?? '') === 'image'">图片水印</x-fieldset-radio>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-4 hidden" data-watermark-driver="font">
|
<div class="mb-4 hidden" data-watermark-driver="font">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][font][font]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>字体文件</label>
|
<label for="configs[watermark_configs][drivers][font][font]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>字体文件</label>
|
||||||
<x-input type="text" name="configs[watermark_configs][drivers][font][font]" id="configs[watermark_configs][drivers][font][font]" autocomplete="text" placeholder="请输入字体文件路径,例如:fonts/lsky.ttf" value="{{ $group->configs['watermark_configs']['drivers']['font']['font'] }}" />
|
<x-input type="text" name="configs[watermark_configs][drivers][font][font]" id="configs[watermark_configs][drivers][font][font]" autocomplete="text" placeholder="请输入字体文件路径,例如:fonts/lsky.ttf" value="{{ $group->configs['watermark_configs']['drivers']['font']['font'] ?? '' }}" />
|
||||||
<small class="text-yellow-500">请将字体文件放置 {{ storage_path('app/public') }} 目录下</small>
|
<small class="text-yellow-500">请将字体文件放置 {{ storage_path('app/public') }} 目录下</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][font][position]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印位置</label>
|
<label for="configs[watermark_configs][drivers][font][position]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印位置</label>
|
||||||
<x-select id="configs[watermark_configs][drivers][font][position]" name="configs[watermark_configs][drivers][font][position]" autocomplete="position">
|
<x-select id="configs[watermark_configs][drivers][font][position]" name="configs[watermark_configs][drivers][font][position]" autocomplete="position">
|
||||||
@foreach($positions as $key => $position)
|
@foreach($positions as $key => $position)
|
||||||
<option value="{{ $key }}" {{ $group->configs['watermark_configs']['drivers']['font']['position'] === $key ? 'selected' : '' }}>{{ $position }}</option>
|
<option value="{{ $key }}" {{ ($group->configs['watermark_configs']['drivers']['font']['position'] ?? '') === $key ? 'selected' : '' }}>{{ $position }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</x-select>
|
</x-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][font][text]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印文字</label>
|
<label for="configs[watermark_configs][drivers][font][text]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印文字</label>
|
||||||
<x-input type="text" name="configs[watermark_configs][drivers][font][text]" id="configs[watermark_configs][drivers][font][text]" autocomplete="text" placeholder="请输入水印文字" value="{{ $group->configs['watermark_configs']['drivers']['font']['text'] }}" />
|
<x-input type="text" name="configs[watermark_configs][drivers][font][text]" id="configs[watermark_configs][drivers][font][text]" autocomplete="text" placeholder="请输入水印文字" value="{{ $group->configs['watermark_configs']['drivers']['font']['text'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][font][color]" class="block text-sm font-medium text-gray-700">字体颜色</label>
|
<label for="configs[watermark_configs][drivers][font][color]" class="block text-sm font-medium text-gray-700">字体颜色</label>
|
||||||
<x-input type="text" name="configs[watermark_configs][drivers][font][color]" id="configs[watermark_configs][drivers][font][color]" autocomplete="color" placeholder="请输入字体颜色,例如:#ffffff" value="{{ $group->configs['watermark_configs']['drivers']['font']['color'] }}" />
|
<x-input type="text" name="configs[watermark_configs][drivers][font][color]" id="configs[watermark_configs][drivers][font][color]" autocomplete="color" placeholder="请输入字体颜色,例如:#ffffff" value="{{ $group->configs['watermark_configs']['drivers']['font']['color'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][font][size]" class="block text-sm font-medium text-gray-700">字体大小</label>
|
<label for="configs[watermark_configs][drivers][font][size]" class="block text-sm font-medium text-gray-700">字体大小</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][font][size]" id="configs[watermark_configs][drivers][font][size]" autocomplete="size" placeholder="请输入字体大小,默认 14" value="{{ $group->configs['watermark_configs']['drivers']['font']['size'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][font][size]" id="configs[watermark_configs][drivers][font][size]" autocomplete="size" placeholder="请输入字体大小,默认 14" value="{{ $group->configs['watermark_configs']['drivers']['font']['size'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][font][angle]" class="block text-sm font-medium text-gray-700">旋转角度</label>
|
<label for="configs[watermark_configs][drivers][font][angle]" class="block text-sm font-medium text-gray-700">旋转角度</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][font][angle]" id="configs[watermark_configs][drivers][font][angle]" autocomplete="angle" placeholder="请输入旋转角度,默认 0,可以为" value="{{ $group->configs['watermark_configs']['drivers']['font']['angle'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][font][angle]" id="configs[watermark_configs][drivers][font][angle]" autocomplete="angle" placeholder="请输入旋转角度,默认 0,可以为" value="{{ $group->configs['watermark_configs']['drivers']['font']['angle'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][font][x]" class="block text-sm font-medium text-gray-700">X轴偏移量</label>
|
<label for="configs[watermark_configs][drivers][font][x]" class="block text-sm font-medium text-gray-700">X轴偏移量</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][font][x]" id="configs[watermark_configs][drivers][font][x]" autocomplete="x" placeholder="X轴偏移量" value="{{ $group->configs['watermark_configs']['drivers']['font']['x'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][font][x]" id="configs[watermark_configs][drivers][font][x]" autocomplete="x" placeholder="X轴偏移量" value="{{ $group->configs['watermark_configs']['drivers']['font']['x'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][font][y]" class="block text-sm font-medium text-gray-700">Y轴偏移量</label>
|
<label for="configs[watermark_configs][drivers][font][y]" class="block text-sm font-medium text-gray-700">Y轴偏移量</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][font][y]" id="configs[watermark_configs][drivers][font][y]" autocomplete="y" placeholder="Y轴偏移量" value="{{ $group->configs['watermark_configs']['drivers']['font']['y'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][font][y]" id="configs[watermark_configs][drivers][font][y]" autocomplete="y" placeholder="Y轴偏移量" value="{{ $group->configs['watermark_configs']['drivers']['font']['y'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-4 hidden" data-watermark-driver="image">
|
<div class="mb-4 hidden" data-watermark-driver="image">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][image]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印图片</label>
|
<label for="configs[watermark_configs][drivers][image][image]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印图片</label>
|
||||||
<x-input type="text" name="configs[watermark_configs][drivers][image][image]" id="configs[watermark_configs][drivers][image][image]" autocomplete="image" placeholder="请输入水印路径,例如:images/lsky.png" value="{{ $group->configs['watermark_configs']['drivers']['image']['image'] }}" />
|
<x-input type="text" name="configs[watermark_configs][drivers][image][image]" id="configs[watermark_configs][drivers][image][image]" autocomplete="image" placeholder="请输入水印路径,例如:images/lsky.png" value="{{ $group->configs['watermark_configs']['drivers']['image']['image'] ?? '' }}" />
|
||||||
<small class="text-yellow-500">请将水印图片放置 {{ public_path() }} 目录下</small>
|
<small class="text-yellow-500">请将水印图片放置 {{ storage_path('app/public') }} 目录下</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][position]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印位置</label>
|
<label for="configs[watermark_configs][drivers][image][position]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>水印位置</label>
|
||||||
<x-select id="configs[watermark_configs][drivers][image][position]" name="configs[watermark_configs][drivers][image][position]" autocomplete="position">
|
<x-select id="configs[watermark_configs][drivers][image][position]" name="configs[watermark_configs][drivers][image][position]" autocomplete="position">
|
||||||
@foreach($positions as $key => $position)
|
@foreach($positions as $key => $position)
|
||||||
<option value="{{ $key }}" {{ $group->configs['watermark_configs']['drivers']['image']['position'] === $key ? 'selected' : '' }}>{{ $position }}</option>
|
<option value="{{ $key }}" {{ ($group->configs['watermark_configs']['drivers']['image']['position'] ?? '') === $key ? 'selected' : '' }}>{{ $position }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</x-select>
|
</x-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][width]" class="block text-sm font-medium text-gray-700">图片宽度</label>
|
<label for="configs[watermark_configs][drivers][image][width]" class="block text-sm font-medium text-gray-700">图片宽度</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][image][width]" id="configs[watermark_configs][drivers][image][width]" autocomplete="width" placeholder="请输入水印图片宽度" value="{{ $group->configs['watermark_configs']['drivers']['image']['width'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][image][width]" id="configs[watermark_configs][drivers][image][width]" autocomplete="width" placeholder="请输入水印图片宽度" value="{{ $group->configs['watermark_configs']['drivers']['image']['width'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][height]" class="block text-sm font-medium text-gray-700">图片高度</label>
|
<label for="configs[watermark_configs][drivers][image][height]" class="block text-sm font-medium text-gray-700">图片高度</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][image][height]" id="configs[watermark_configs][drivers][image][height]" autocomplete="height" placeholder="请输入水印图片高度" value="{{ $group->configs['watermark_configs']['drivers']['image']['height'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][image][height]" id="configs[watermark_configs][drivers][image][height]" autocomplete="height" placeholder="请输入水印图片高度" value="{{ $group->configs['watermark_configs']['drivers']['image']['height'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][opacity]" class="block text-sm font-medium text-gray-700">不透明度</label>
|
<label for="configs[watermark_configs][drivers][image][opacity]" class="block text-sm font-medium text-gray-700">不透明度</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][image][opacity]" id="configs[watermark_configs][drivers][image][opacity]" autocomplete="opacity" placeholder="请输入不透明度,取值 0 - 100" value="{{ $group->configs['watermark_configs']['drivers']['image']['opacity'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][image][opacity]" id="configs[watermark_configs][drivers][image][opacity]" autocomplete="opacity" placeholder="请输入不透明度,取值 0 - 100" value="{{ $group->configs['watermark_configs']['drivers']['image']['opacity'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][rotate]" class="block text-sm font-medium text-gray-700">旋转角度</label>
|
<label for="configs[watermark_configs][drivers][image][rotate]" class="block text-sm font-medium text-gray-700">旋转角度</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][image][rotate]" id="configs[watermark_configs][drivers][image][rotate]" autocomplete="rotate" placeholder="请输入旋转角度,默认 0" value="{{ $group->configs['watermark_configs']['drivers']['image']['rotate'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][image][rotate]" id="configs[watermark_configs][drivers][image][rotate]" autocomplete="rotate" placeholder="请输入旋转角度,默认 0" value="{{ $group->configs['watermark_configs']['drivers']['image']['rotate'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][x]" class="block text-sm font-medium text-gray-700">X轴偏移量</label>
|
<label for="configs[watermark_configs][drivers][image][x]" class="block text-sm font-medium text-gray-700">X轴偏移量</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][image][x]" id="configs[watermark_configs][drivers][image][x]" autocomplete="x" placeholder="X轴偏移量" value="{{ $group->configs['watermark_configs']['drivers']['image']['x'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][image][x]" id="configs[watermark_configs][drivers][image][x]" autocomplete="x" placeholder="X轴偏移量" value="{{ $group->configs['watermark_configs']['drivers']['image']['x'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[watermark_configs][drivers][image][y]" class="block text-sm font-medium text-gray-700">Y轴偏移量</label>
|
<label for="configs[watermark_configs][drivers][image][y]" class="block text-sm font-medium text-gray-700">Y轴偏移量</label>
|
||||||
<x-input type="number" name="configs[watermark_configs][drivers][image][y]" id="configs[watermark_configs][drivers][image][y]" autocomplete="y" placeholder="Y轴偏移量" value="{{ $group->configs['watermark_configs']['drivers']['image']['y'] }}" />
|
<x-input type="number" name="configs[watermark_configs][drivers][image][y]" id="configs[watermark_configs][drivers][image][y]" autocomplete="y" placeholder="Y轴偏移量" value="{{ $group->configs['watermark_configs']['drivers']['image']['y'] ?? '' }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,18 +25,18 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $group->configs['is_enable_scan'] ? 'text-green-500' : 'text-rose-500' }}">
|
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $group->configs->get('is_enable_scan') ? 'text-green-500' : 'text-rose-500' }}">
|
||||||
<i class="text-lg fas fa-{{ $group->configs['is_enable_scan'] ? 'check-circle' : 'times-circle' }}"></i>
|
<i class="text-lg fas fa-{{ $group->configs->get('is_enable_scan') ? 'check-circle' : 'times-circle' }}"></i>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $group->configs['is_enable_original_protection'] ? 'text-green-500' : 'text-rose-500' }}">
|
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $group->configs->get('is_enable_original_protection') ? 'text-green-500' : 'text-rose-500' }}">
|
||||||
<i class="text-lg fas fa-{{ $group->configs['is_enable_original_protection'] ? 'check-circle' : 'times-circle' }}"></i>
|
<i class="text-lg fas fa-{{ $group->configs->get('is_enable_original_protection') ? 'check-circle' : 'times-circle' }}"></i>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $group->configs['is_enable_watermark'] ? 'text-green-500' : 'text-rose-500' }}">
|
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $group->configs->get('is_enable_watermark') ? 'text-green-500' : 'text-rose-500' }}">
|
||||||
<i class="text-lg fas fa-{{ $group->configs['is_enable_watermark'] ? 'check-circle' : 'times-circle' }}"></i>
|
<i class="text-lg fas fa-{{ $group->configs->get('is_enable_watermark') ? 'check-circle' : 'times-circle' }}"></i>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">{{ $group->users_count }}</td>
|
<td class="px-6 py-4 whitespace-nowrap">{{ $group->users_count }}</td>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<x-modal>
|
<x-modal id="rules-modal">
|
||||||
<div id="modal-content">
|
<div id="modal-content">
|
||||||
<table class="min-w-full divide-y divide-gray-200">
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
@push('scripts')
|
@push('scripts')
|
||||||
<script>
|
<script>
|
||||||
$('#rename-rules').click(function () {
|
$('#rename-rules').click(function () {
|
||||||
Alpine.store('modal').open = true;
|
Alpine.store('modal').open('rules-modal')
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|||||||
@@ -6,3 +6,6 @@
|
|||||||
<p class="bg-yellow-500 p-2 mb-2 rounded text-sm text-white">
|
<p class="bg-yellow-500 p-2 mb-2 rounded text-sm text-white">
|
||||||
<i class="fas fa-exclamation-circle"></i> 系统运行环境允许上传大小的最大值为 {{ ini_get('upload_max_filesize') }},最大 POST 数据大小为 {{ ini_get('post_max_size') }},上传文件大小不得超过这两项配置值。
|
<i class="fas fa-exclamation-circle"></i> 系统运行环境允许上传大小的最大值为 {{ ini_get('upload_max_filesize') }},最大 POST 数据大小为 {{ ini_get('post_max_size') }},上传文件大小不得超过这两项配置值。
|
||||||
</p>
|
</p>
|
||||||
|
<p class="bg-yellow-500 p-2 mb-2 rounded text-sm text-white">
|
||||||
|
<i class="fas fa-exclamation-circle"></i> 原图保护以及水印功能,原理是使用 PHP 接管图片请求,动态处理后缓存之后通过载入缓存到内存中输出图片,对服务器有着较高的要求,请谨慎使用。如果你使用第三方储存,兰空图床更推荐你使用第三方储存的图片处理规则。
|
||||||
|
</p>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<x-modal>
|
<x-modal id="content-modal">
|
||||||
<div id="modal-content"></div>
|
<div id="modal-content"></div>
|
||||||
</x-modal>
|
</x-modal>
|
||||||
|
|
||||||
@@ -194,8 +194,8 @@
|
|||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<div class="bg-gray-50 px-2 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="bg-gray-50 px-2 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium text-gray-500">剩余容量</dt>
|
<dt class="text-sm font-medium text-gray-500">已用容量</dt>
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2 truncate">__surplus_capacity__</dd>
|
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2 truncate">__used_capacity__</dd>
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
@@ -333,7 +333,7 @@
|
|||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
axios.delete(`/admin/images/${id}`).then(response => {
|
axios.delete(`/admin/images/${id}`).then(response => {
|
||||||
if (response.data.status) {
|
if (response.data.status) {
|
||||||
modal = false;
|
modal.close('content-modal')
|
||||||
toastr.success(response.data.message);
|
toastr.success(response.data.message);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
history.go(0);
|
history.go(0);
|
||||||
@@ -348,23 +348,24 @@
|
|||||||
|
|
||||||
$('#grammar').click(function () {
|
$('#grammar').click(function () {
|
||||||
$('#modal-content').html($('#search-grammar-tpl').html());
|
$('#modal-content').html($('#search-grammar-tpl').html());
|
||||||
modal.open = true;
|
modal.open('content-modal')
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.item').click(function () {
|
$('.item').click(function () {
|
||||||
let image = $(this).data('json');
|
let image = $(this).data('json');
|
||||||
|
let previewUrl = ['psd', 'tif'].indexOf(image.extension) === -1 ? image.url : image.thumb_url;
|
||||||
let html = $('#image-tpl').html()
|
let html = $('#image-tpl').html()
|
||||||
.replace(/__id__/g, image.id)
|
.replace(/__id__/g, image.id)
|
||||||
.replace(/__url__/g, image.url)
|
.replace(/__url__/g, previewUrl)
|
||||||
.replace(/__user_name__/g, image.user ? image.user.name+'('+image.user.email+')' : '游客')
|
.replace(/__user_name__/g, image.user ? image.user.name+'('+image.user.email+')' : '游客')
|
||||||
.replace(/__user_email__/g, image.user ? image.user.email : '-')
|
.replace(/__user_email__/g, image.user ? image.user.email : '-')
|
||||||
.replace(/__album_name__/g, image.album ? image.album.name : '-')
|
.replace(/__album_name__/g, image.album ? image.album.name : '-')
|
||||||
.replace(/__group_name__/g, image.group ? image.group.name : '-')
|
.replace(/__group_name__/g, image.group ? image.group.name : '-')
|
||||||
.replace(/__strategy_name__/g, image.strategy.name || '-')
|
.replace(/__strategy_name__/g, image.strategy ? image.strategy.name : '-')
|
||||||
.replace(/__name__/g, image.name)
|
.replace(/__name__/g, image.name)
|
||||||
.replace(/__origin_name__/g, image.origin_name)
|
.replace(/__origin_name__/g, image.origin_name)
|
||||||
.replace(/__pathname__/g, image.pathname)
|
.replace(/__pathname__/g, image.pathname)
|
||||||
.replace(/__size__/g, utils.formatSize(image.size))
|
.replace(/__size__/g, utils.formatSize(image.size * 1024))
|
||||||
.replace(/__mimetype__/g, image.mimetype)
|
.replace(/__mimetype__/g, image.mimetype)
|
||||||
.replace(/__md5__/g, image.md5)
|
.replace(/__md5__/g, image.md5)
|
||||||
.replace(/__sha1__/g, image.sha1)
|
.replace(/__sha1__/g, image.sha1)
|
||||||
@@ -377,7 +378,7 @@
|
|||||||
|
|
||||||
$('#modal-content').html(html);
|
$('#modal-content').html(html);
|
||||||
|
|
||||||
modal.open = true;
|
modal.open('content-modal')
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.item-user').click(function (e) {
|
$('.item-user').click(function (e) {
|
||||||
@@ -388,7 +389,7 @@
|
|||||||
.replace(/__name__/g, user.name)
|
.replace(/__name__/g, user.name)
|
||||||
.replace(/__email__/g, user.email)
|
.replace(/__email__/g, user.email)
|
||||||
.replace(/__capacity__/g, utils.formatSize(user.capacity * 1024))
|
.replace(/__capacity__/g, utils.formatSize(user.capacity * 1024))
|
||||||
.replace(/__surplus_capacity__/g, utils.formatSize(user.images_sum_size * 1024))
|
.replace(/__used_capacity__/g, utils.formatSize(user.images_sum_size * 1024))
|
||||||
.replace(/__image_num__/g, user.image_num)
|
.replace(/__image_num__/g, user.image_num)
|
||||||
.replace(/__album_num__/g, user.album_num)
|
.replace(/__album_num__/g, user.album_num)
|
||||||
.replace(/__registered_ip__/g, user.registered_ip || '-')
|
.replace(/__registered_ip__/g, user.registered_ip || '-')
|
||||||
@@ -398,7 +399,7 @@
|
|||||||
|
|
||||||
$('#modal-content').html(html);
|
$('#modal-content').html(html);
|
||||||
|
|
||||||
modal.open = true;
|
modal.open('content-modal')
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.item .delete').click(function (e) {
|
$('.item .delete').click(function (e) {
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
@section('title', '系统设置')
|
@section('title', '系统设置')
|
||||||
|
|
||||||
@push('styles')
|
@push('styles')
|
||||||
<link rel="stylesheet" href="{{ asset('css/markdown-css/github-markdown.css') }}">
|
<link rel="stylesheet" href="{{ asset('css/markdown-css/github-markdown-light.css') }}">
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
<x-app-layout>
|
<x-app-layout>
|
||||||
<div class="my-6 md:my-9">
|
<div class="my-6 md:my-9">
|
||||||
<p class="mb-3 font-semibold text-lg text-gray-700">通用</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">通用</p>
|
||||||
<form action="{{ route('admin.settings.save') }}">
|
<form action="{{ route('admin.settings.save') }}">
|
||||||
<div class="relative p-4 rounded-md bg-white mb-8 space-y-4">
|
<div class="relative p-4 rounded-md bg-white mb-8 space-y-4 shadow-custom">
|
||||||
<div>
|
<div>
|
||||||
<label for="app_name" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>应用名称</label>
|
<label for="app_name" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>应用名称</label>
|
||||||
<x-input type="text" name="app_name" id="app_name" value="{{ $configs['app_name'] }}" placeholder="请输入应用名称"/>
|
<x-input type="text" name="app_name" id="app_name" value="{{ $configs->get('app_name') }}" placeholder="请输入应用名称"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="site_keywords" class="block text-sm font-medium text-gray-700">网站关键字</label>
|
<label for="site_keywords" class="block text-sm font-medium text-gray-700">网站关键字</label>
|
||||||
<x-textarea type="text" name="site_keywords" id="site_keywords" placeholder="请输入网站关键字">{{ $configs['site_keywords'] }}</x-textarea>
|
<x-textarea type="text" name="site_keywords" id="site_keywords" placeholder="请输入网站关键字">{{ $configs->get('site_keywords') }}</x-textarea>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="site_description" class="block text-sm font-medium text-gray-700">网站描述</label>
|
<label for="site_description" class="block text-sm font-medium text-gray-700">网站描述</label>
|
||||||
<x-textarea type="text" name="site_description" id="site_description" placeholder="请输入网站描述">{{ $configs['site_description'] }}</x-textarea>
|
<x-textarea type="text" name="site_description" id="site_description" placeholder="请输入网站描述">{{ $configs->get('site_description') }}</x-textarea>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="icp_no" class="block text-sm font-medium text-gray-700">备案号</label>
|
<label for="icp_no" class="block text-sm font-medium text-gray-700">备案号</label>
|
||||||
<x-input type="text" name="icp_no" id="icp_no" value="{{ $configs['icp_no'] }}" placeholder="请输入备案号"/>
|
<x-input type="text" name="icp_no" id="icp_no" value="{{ $configs->get('icp_no') }}" placeholder="请输入备案号"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="site_notice" class="block text-sm font-medium text-gray-700">网站公告</label>
|
<label for="site_notice" class="block text-sm font-medium text-gray-700">网站公告</label>
|
||||||
<x-textarea type="text" name="site_notice" id="site_notice" placeholder="首页弹出公告,支持 Markdown,不设置请留空。" rows="7">{{ $configs['site_notice'] }}</x-textarea>
|
<x-textarea type="text" name="site_notice" id="site_notice" placeholder="首页弹出公告,支持 Markdown,不设置请留空。" rows="7">{{ $configs->get('site_notice') }}</x-textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
@@ -38,21 +38,21 @@
|
|||||||
|
|
||||||
<p class="mb-3 font-semibold text-lg text-gray-700">控制</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">控制</p>
|
||||||
<form action="{{ route('admin.settings.save') }}">
|
<form action="{{ route('admin.settings.save') }}">
|
||||||
<div class="relative p-4 rounded-md bg-white mb-8 space-y-4">
|
<div class="relative p-4 rounded-md bg-white mb-8 space-y-4 shadow-custom">
|
||||||
<x-fieldset title="是否启用注册" faq="启用或关闭系统注册功能">
|
<x-fieldset title="是否启用注册" faq="启用或关闭系统注册功能">
|
||||||
<x-switch name="is_enable_registration" value="1" :checked="(bool) $configs['is_enable_registration']" />
|
<x-switch name="is_enable_registration" value="1" :checked="(bool) $configs->get('is_enable_registration')" />
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
<x-fieldset title="是否启用画廊" faq="启用或关闭画廊功能,画廊只有已登录的用户可见,画廊中的图片均为所有用户公开的图片。">
|
<x-fieldset title="是否启用画廊" faq="启用或关闭画廊功能,画廊只有已登录的用户可见,画廊中的图片均为所有用户公开的图片。">
|
||||||
<x-switch name="is_enable_gallery" value="1" :checked="(bool) $configs['is_enable_gallery']" />
|
<x-switch name="is_enable_gallery" value="1" :checked="(bool) $configs->get('is_enable_gallery')" />
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
<x-fieldset title="是否启用接口" faq="启用或关闭接口功能,关闭后将无法通过接口上传图片、管理图片等操作。">
|
<x-fieldset title="是否启用接口" faq="启用或关闭接口功能,关闭后将无法通过接口上传图片、管理图片等操作。">
|
||||||
<x-switch name="is_enable_api" value="1" :checked="(bool) $configs['is_enable_api']" />
|
<x-switch name="is_enable_api" value="1" :checked="(bool) $configs->get('is_enable_api')" />
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
<x-fieldset title="是否允许游客上传" faq="启用或关闭游客上传功能,游客上传受「系统默认组」控制。">
|
<x-fieldset title="是否允许游客上传" faq="启用或关闭游客上传功能,游客上传受「系统默认组」控制。">
|
||||||
<x-switch name="is_allow_guest_upload" value="1" :checked="(bool) $configs['is_allow_guest_upload']" />
|
<x-switch name="is_allow_guest_upload" value="1" :checked="(bool) $configs->get('is_allow_guest_upload')" />
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
<x-fieldset title="账号验证" faq="是否强制用户验证邮箱,开启后用户必须经过验证邮箱后才能上传图片,请确保邮件配置正常。">
|
<x-fieldset title="账号验证" faq="是否强制用户验证邮箱,开启后用户必须经过验证邮箱后才能上传图片,请确保邮件配置正常。">
|
||||||
<x-switch name="is_user_need_verify" value="1" :checked="(bool) $configs['is_user_need_verify']" />
|
<x-switch name="is_user_need_verify" value="1" :checked="(bool) $configs->get('is_user_need_verify')" />
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
<x-button type="submit">保存更改</x-button>
|
<x-button type="submit">保存更改</x-button>
|
||||||
@@ -62,10 +62,10 @@
|
|||||||
|
|
||||||
<p class="mb-3 font-semibold text-lg text-gray-700">用户</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">用户</p>
|
||||||
<form action="{{ route('admin.settings.save') }}">
|
<form action="{{ route('admin.settings.save') }}">
|
||||||
<div class="relative p-4 rounded-md bg-white mb-8 space-y-4">
|
<div class="relative p-4 rounded-md bg-white mb-8 space-y-4 shadow-custom">
|
||||||
<div>
|
<div>
|
||||||
<label for="user_initial_capacity" class="block text-sm font-medium text-gray-700">用户初始容量(kb)</label>
|
<label for="user_initial_capacity" class="block text-sm font-medium text-gray-700">用户初始容量(kb)</label>
|
||||||
<x-input type="number" name="user_initial_capacity" id="user_initial_capacity" step="0.01" value="{{ $configs['user_initial_capacity'] }}" placeholder="请输入用户初始容量(kb)"/>
|
<x-input type="number" name="user_initial_capacity" id="user_initial_capacity" step="0.01" value="{{ $configs->get('user_initial_capacity') }}" placeholder="请输入用户初始容量(kb)"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p class="mb-3 font-semibold text-lg text-gray-700">邮件配置</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">邮件配置</p>
|
||||||
<div class="relative p-4 rounded-md bg-white mb-8 space-y-4">
|
<div class="relative p-4 rounded-md bg-white mb-8 space-y-4 shadow-custom">
|
||||||
<x-fieldset title="发信驱动">
|
<x-fieldset title="发信驱动">
|
||||||
<x-fieldset-radio id="mail[default]" name="mail[default]" data-select="mailer" value="smtp" checked>SMTP</x-fieldset-radio>
|
<x-fieldset-radio id="mail[default]" name="mail[default]" data-select="mailer" value="smtp" checked>SMTP</x-fieldset-radio>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
@@ -84,27 +84,27 @@
|
|||||||
<form action="{{ route('admin.settings.save') }}" class="space-y-4">
|
<form action="{{ route('admin.settings.save') }}" class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label for="mail[mailers][smtp][host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
<label for="mail[mailers][smtp][host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
||||||
<x-input type="text" name="mail[mailers][smtp][host]" id="mail[mailers][smtp][host]" value="{{ $configs['mail']['mailers']['smtp']['host'] }}" placeholder="请输入 SMTP 主机地址"/>
|
<x-input type="text" name="mail[mailers][smtp][host]" id="mail[mailers][smtp][host]" value="{{ $configs['mail']['mailers']['smtp']['host'] ?? '' }}" placeholder="请输入 SMTP 主机地址"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="mail[mailers][smtp][port]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接端口</label>
|
<label for="mail[mailers][smtp][port]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接端口</label>
|
||||||
<x-input type="number" name="mail[mailers][smtp][port]" id="mail[mailers][smtp][port]" value="{{ $configs['mail']['mailers']['smtp']['port'] }}" placeholder="请输入 SMTP 主机连接端口"/>
|
<x-input type="number" name="mail[mailers][smtp][port]" id="mail[mailers][smtp][port]" value="{{ $configs['mail']['mailers']['smtp']['port'] ?? 587 }}" placeholder="请输入 SMTP 主机连接端口"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="mail[mailers][smtp][username]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>用户名</label>
|
<label for="mail[mailers][smtp][username]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>用户名</label>
|
||||||
<x-input type="text" name="mail[mailers][smtp][username]" id="mail[mailers][smtp][username]" value="{{ $configs['mail']['mailers']['smtp']['username'] }}" placeholder="请输入用户名"/>
|
<x-input type="text" name="mail[mailers][smtp][username]" id="mail[mailers][smtp][username]" value="{{ $configs['mail']['mailers']['smtp']['username'] ?? '' }}" placeholder="请输入用户名"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="mail[mailers][smtp][password]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>密码</label>
|
<label for="mail[mailers][smtp][password]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>密码</label>
|
||||||
<x-input type="password" name="mail[mailers][smtp][password]" id="mail[mailers][smtp][password]" value="{{ $configs['mail']['mailers']['smtp']['password'] }}" placeholder="请输入密码"/>
|
<x-input type="password" name="mail[mailers][smtp][password]" id="mail[mailers][smtp][password]" value="{{ $configs['mail']['mailers']['smtp']['password'] ?? '' }}" placeholder="请输入密码"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="mail[mailers][smtp][encryption]" class="block text-sm font-medium text-gray-700">加密方式</label>
|
<label for="mail[mailers][smtp][encryption]" class="block text-sm font-medium text-gray-700">加密方式</label>
|
||||||
<x-input type="text" name="mail[mailers][smtp][encryption]" id="mail[mailers][smtp][encryption]" value="{{ $configs['mail']['mailers']['smtp']['encryption'] }}" placeholder="请输入加密方式(ssl, tls)"/>
|
<x-input type="text" name="mail[mailers][smtp][encryption]" id="mail[mailers][smtp][encryption]" value="{{ $configs['mail']['mailers']['smtp']['encryption'] ?? '' }}" placeholder="请输入加密方式(ssl, tls)"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="mail[mailers][smtp][timeout]" class="block text-sm font-medium text-gray-700">连接超时时间(秒)</label>
|
<label for="mail[mailers][smtp][timeout]" class="block text-sm font-medium text-gray-700">连接超时时间(秒)</label>
|
||||||
<x-input type="number" name="mail[mailers][smtp][timeout]" id="mail[mailers][smtp][timeout]" value="{{ $configs['mail']['mailers']['smtp']['timeout'] }}" placeholder="请输入连接超时时间(秒)"/>
|
<x-input type="number" name="mail[mailers][smtp][timeout]" id="mail[mailers][smtp][timeout]" value="{{ $configs['mail']['mailers']['smtp']['timeout'] ?? 10 }}" placeholder="请输入连接超时时间(秒)"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="mail[mailers][smtp][from_address]" class="block text-sm font-medium text-gray-700">发件人地址</label>
|
<label for="mail[mailers][smtp][from_address]" class="block text-sm font-medium text-gray-700">发件人地址</label>
|
||||||
@@ -127,7 +127,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mb-3 font-semibold text-lg text-gray-700">系统升级</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">系统升级</p>
|
||||||
<div class="relative p-4 rounded-md bg-white mb-8">
|
<div class="relative p-4 rounded-md bg-white mb-8 shadow-custom">
|
||||||
<p id="check-update" class="text-gray-600 text-center p-4" style="display: none">
|
<p id="check-update" class="text-gray-600 text-center p-4" style="display: none">
|
||||||
<i class="fas fa-cog animate-spin"></i> 正在检查更新...
|
<i class="fas fa-cog animate-spin"></i> 正在检查更新...
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<div class="md:mt-0 md:col-span-2">
|
<div class="md:mt-0 md:col-span-2">
|
||||||
<form action="{{ route('admin.strategy.create') }}" method="POST">
|
<form action="{{ route('admin.strategy.create') }}" method="POST">
|
||||||
<div class="overflow-hidden rounded-md">
|
<div class="overflow-hidden rounded-md">
|
||||||
<div class="px-4 py-5 bg-white sm:p-6 space-y-4">
|
<div class="px-4 py-5 bg-white sm:p-6 space-y-4 shadow-custom">
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<label class="block">
|
<label class="block">
|
||||||
<span class="text-gray-700">选择角色组</span>
|
<span class="text-gray-700">选择角色组</span>
|
||||||
@@ -46,6 +46,10 @@
|
|||||||
本地储存的访问网址必须有根路径,例如:https://www.lsky.pro/uploads 中的 uploads 就是根路径,且根路径不能和其他策略重复。修改根路径直接影响已经上传并已使用的链接的访问。
|
本地储存的访问网址必须有根路径,例如:https://www.lsky.pro/uploads 中的 uploads 就是根路径,且根路径不能和其他策略重复。修改根路径直接影响已经上传并已使用的链接的访问。
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[root]" class="block text-sm font-medium text-gray-700">储存路径</label>
|
<label for="configs[root]" class="block text-sm font-medium text-gray-700">储存路径</label>
|
||||||
@@ -60,6 +64,10 @@
|
|||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
<label for="configs[access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
||||||
<x-input type="text" name="configs[access_key_id]" id="configs[access_key_id]" placeholder="请输入 AccessKeyId" />
|
<x-input type="text" name="configs[access_key_id]" id="configs[access_key_id]" placeholder="请输入 AccessKeyId" />
|
||||||
@@ -68,6 +76,10 @@
|
|||||||
<label for="configs[secret_access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretAccessKey</label>
|
<label for="configs[secret_access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretAccessKey</label>
|
||||||
<x-input type="password" name="configs[secret_access_key]" id="configs[secret_access_key]" placeholder="请输入 SecretAccessKey" />
|
<x-input type="password" name="configs[secret_access_key]" id="configs[secret_access_key]" placeholder="请输入 SecretAccessKey" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[endpoint]" class="block text-sm font-medium text-gray-700">连接地址</label>
|
||||||
|
<x-input type="url" name="configs[endpoint]" id="configs[endpoint]" placeholder="请输入连接地址" />
|
||||||
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[region]" class="block text-sm font-medium text-gray-700">区域(region)</label>
|
<label for="configs[region]" class="block text-sm font-medium text-gray-700">区域(region)</label>
|
||||||
<x-input type="text" name="configs[region]" id="configs[region]" placeholder="请输入区域,例如:us-east-1" />
|
<x-input type="text" name="configs[region]" id="configs[region]" placeholder="请输入区域,例如:us-east-1" />
|
||||||
@@ -83,6 +95,10 @@
|
|||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
<label for="configs[access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
||||||
<x-input type="text" name="configs[access_key_id]" id="configs[access_key_id]" placeholder="请输入 AccessKeyId" />
|
<x-input type="text" name="configs[access_key_id]" id="configs[access_key_id]" placeholder="请输入 AccessKeyId" />
|
||||||
@@ -106,6 +122,10 @@
|
|||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[app_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AppId</label>
|
<label for="configs[app_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AppId</label>
|
||||||
<x-input type="text" name="configs[app_id]" id="configs[app_id]" placeholder="请输入 AppId" />
|
<x-input type="text" name="configs[app_id]" id="configs[app_id]" placeholder="请输入 AppId" />
|
||||||
@@ -125,6 +145,7 @@
|
|||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>储存桶名称</label>
|
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>储存桶名称</label>
|
||||||
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入储存桶名称" />
|
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入储存桶名称" />
|
||||||
|
<small class="text-gray-500"><i class="fas fa-exclamation-circle"></i> 腾讯云储存桶名称由 名称+appid 组合,例如:test-125146xxxx,此处应该填写 test</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -133,6 +154,10 @@
|
|||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKey</label>
|
<label for="configs[access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKey</label>
|
||||||
<x-input type="text" name="configs[access_key]" id="configs[access_key]" placeholder="请输入 AccessKey" />
|
<x-input type="text" name="configs[access_key]" id="configs[access_key]" placeholder="请输入 AccessKey" />
|
||||||
@@ -152,6 +177,10 @@
|
|||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[service]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>服务名称</label>
|
<label for="configs[service]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>服务名称</label>
|
||||||
<x-input type="text" name="configs[service]" id="configs[service]" placeholder="请输入服务名称" />
|
<x-input type="text" name="configs[service]" id="configs[service]" placeholder="请输入服务名称" />
|
||||||
@@ -171,11 +200,13 @@
|
|||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
<label for="configs[root]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>根目录</label>
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="请输入根目录路径" value="/" />
|
</div>
|
||||||
</div>
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[root]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>根目录</label>
|
||||||
|
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="请输入根目录路径" value="/" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
<label for="configs[host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
||||||
@@ -217,11 +248,13 @@
|
|||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
<label for="configs[root]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>根目录</label>
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="请输入根目录路径" value="/" />
|
</div>
|
||||||
</div>
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[root]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>根目录</label>
|
||||||
|
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="请输入根目录路径" value="/" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
<label for="configs[host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
||||||
@@ -255,10 +288,26 @@
|
|||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[base_uri]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接地址</label>
|
<label for="configs[base_uri]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接地址</label>
|
||||||
<x-input type="url" name="configs[base_uri]" id="configs[base_uri]" placeholder="请输入连接地址" />
|
<x-input type="url" name="configs[base_uri]" id="configs[base_uri]" placeholder="请输入连接地址" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="webdav-configs[auth_type]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>认证方式</label>
|
||||||
|
<x-select id="webdav-auth-type" name="configs[auth_type]" select2>
|
||||||
|
@foreach(\App\Models\Strategy::WEBDAV_AUTH_TYPES as $key => $type)
|
||||||
|
<option value="{{ $key }}" {{ $loop->first ? 'selected' : '' }}>{{ $type }}</option>
|
||||||
|
@endforeach
|
||||||
|
</x-select>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="webdav-configs[prefix]" class="block text-sm font-medium text-gray-700">路径前缀</label>
|
||||||
|
<x-input type="text" name="configs[prefix]" id="webdav-configs[prefix]" placeholder="请输入路径前缀"></x-input>
|
||||||
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[username]" class="block text-sm font-medium text-gray-700">用户名</label>
|
<label for="configs[username]" class="block text-sm font-medium text-gray-700">用户名</label>
|
||||||
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" />
|
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" />
|
||||||
@@ -275,8 +324,8 @@
|
|||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[endpoint]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接地址</label>
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
<x-input type="url" name="configs[endpoint]" id="configs[endpoint]" placeholder="请输入连接地址" />
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKey</label>
|
<label for="configs[access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKey</label>
|
||||||
@@ -286,10 +335,23 @@
|
|||||||
<label for="configs[secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
<label for="configs[secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
||||||
<x-input type="password" name="configs[secret_key]" id="configs[secret_key]" placeholder="请输入 SecretKey" />
|
<x-input type="password" name="configs[secret_key]" id="configs[secret_key]" placeholder="请输入 SecretKey" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[endpoint]" class="block text-sm font-medium text-gray-700">连接地址</label>
|
||||||
|
<x-input type="url" name="configs[endpoint]" id="configs[endpoint]" placeholder="请输入连接地址" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[region]" class="block text-sm font-medium text-gray-700">区域(region)</label>
|
||||||
|
<x-input type="text" name="configs[region]" id="configs[region]" placeholder="请输入区域,例如:us-east-1" />
|
||||||
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Bucket 名称</label>
|
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Bucket 名称</label>
|
||||||
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket 名称" />
|
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket 名称" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-6">
|
||||||
|
<label for="configs[bucket_endpoint]" class="block text-sm font-medium mb-2 text-gray-700">BucketEndpoint</label>
|
||||||
|
<x-switch id="configs[bucket_endpoint]" name="configs[bucket_endpoint]" value="1"></x-switch>
|
||||||
|
<p><small class="text-gray-500"><i class="fas fa-exclamation-circle"></i> 开启此选项后将会直接以「连接地址」作为数据交互传输域名,否则可能会以桶名称拼接域名(例如:http://桶名称.连接地址.com)</small></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
|
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<div class="md:mt-0 md:col-span-2">
|
<div class="md:mt-0 md:col-span-2">
|
||||||
<form action="{{ route('admin.strategy.update', ['id' => $strategy->id]) }}" method="POST">
|
<form action="{{ route('admin.strategy.update', ['id' => $strategy->id]) }}" method="POST">
|
||||||
<div class="overflow-hidden rounded-md">
|
<div class="overflow-hidden rounded-md">
|
||||||
<div class="px-4 py-5 bg-white sm:p-6 space-y-4">
|
<div class="px-4 py-5 bg-white sm:p-6 space-y-4 shadow-custom">
|
||||||
|
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<label class="block">
|
<label class="block">
|
||||||
@@ -45,15 +45,19 @@
|
|||||||
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Local }}">
|
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Local }}">
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问网址</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问网址</label>
|
||||||
<x-input type="text" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名,需要加 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="text" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名,需要加 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
<small class="text-orange-500"><i class="fas fa-exclamation"></i>
|
<small class="text-orange-500"><i class="fas fa-exclamation"></i>
|
||||||
本地储存的访问网址必须有根路径,例如:https://www.lsky.pro/uploads 中的 uploads 就是根路径,且根路径不能和其他策略重复。修改根路径直接影响已经上传并已使用的链接的访问。
|
本地储存的访问网址必须有根路径,例如:https://www.lsky.pro/uploads 中的 uploads 就是根路径,且根路径不能和其他策略重复。修改根路径直接影响已经上传并已使用的链接的访问。
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
<label for="configs[root]" class="block text-sm font-medium text-gray-700">储存路径</label>
|
<label for="configs[root]" class="block text-sm font-medium text-gray-700">储存路径</label>
|
||||||
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="图片保存位置,默认:{{ config('filesystems.disks.uploads.root') }}" value="{{ $strategy->configs['root'] }}" />
|
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="图片保存位置,默认:{{ config('filesystems.disks.uploads.root') }}" value="{{ $strategy->configs->get('root') }}" />
|
||||||
<small class="text-orange-500"><i class="fas fa-exclamation"></i> 储存路径为绝对路径,设置错误或没有读写权限可能会导致图片保存失败。如果储存路径与其他策略相同,那么请注意使用角色组的路径命名规则、文件命名规则来区分不同文件夹,否则可能会因为名称重复而导致图片物理文件被覆盖。</small>
|
<small class="text-orange-500"><i class="fas fa-exclamation"></i> 储存路径为绝对路径,设置错误或没有读写权限可能会导致图片保存失败。如果储存路径与其他策略相同,那么请注意使用角色组的路径命名规则、文件命名规则来区分不同文件夹,否则可能会因为名称重复而导致图片物理文件被覆盖。</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,23 +68,31 @@
|
|||||||
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::S3 }}">
|
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::S3 }}">
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
<label for="configs[access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
||||||
<x-input type="text" name="configs[access_key_id]" id="configs[access_key_id]" placeholder="请输入 AccessKeyId" value="{{ $strategy->configs['access_key_id'] }}" />
|
<x-input type="text" name="configs[access_key_id]" id="configs[access_key_id]" placeholder="请输入 AccessKeyId" value="{{ $strategy->configs->get('access_key_id') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[secret_access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretAccessKey</label>
|
<label for="configs[secret_access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretAccessKey</label>
|
||||||
<x-input type="password" name="configs[secret_access_key]" id="configs[secret_access_key]" placeholder="请输入 SecretAccessKey" value="{{ $strategy->configs['secret_access_key'] }}" />
|
<x-input type="password" name="configs[secret_access_key]" id="configs[secret_access_key]" placeholder="请输入 SecretAccessKey" value="{{ $strategy->configs->get('secret_access_key') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[endpoint]" class="block text-sm font-medium text-gray-700">连接地址</label>
|
||||||
|
<x-input type="url" name="configs[endpoint]" id="configs[endpoint]" placeholder="请输入连接地址" value="{{ $strategy->configs->get('endpoint') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[region]" class="block text-sm font-medium text-gray-700">区域(region)</label>
|
<label for="configs[region]" class="block text-sm font-medium text-gray-700">区域(region)</label>
|
||||||
<x-input type="text" name="configs[region]" id="configs[region]" placeholder="请输入区域,例如:us-east-1" value="{{ $strategy->configs['region'] }}" />
|
<x-input type="text" name="configs[region]" id="configs[region]" placeholder="请输入区域,例如:us-east-1" value="{{ $strategy->configs->get('region') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>储存桶名称</label>
|
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>储存桶名称</label>
|
||||||
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket 名称" value="{{ $strategy->configs['bucket'] }}" />
|
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket 名称" value="{{ $strategy->configs->get('bucket') }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -89,23 +101,27 @@
|
|||||||
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Oss }}">
|
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Oss }}">
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
<label for="configs[access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
||||||
<x-input type="text" name="configs[access_key_id]" id="configs[access_key_id]" placeholder="请输入 AccessKeyId" value="{{ $strategy->configs['access_key_id'] }}" />
|
<x-input type="text" name="configs[access_key_id]" id="configs[access_key_id]" placeholder="请输入 AccessKeyId" value="{{ $strategy->configs->get('access_key_id') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[access_key_secret]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeySecret</label>
|
<label for="configs[access_key_secret]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeySecret</label>
|
||||||
<x-input type="password" name="configs[access_key_secret]" id="configs[access_key_secret]" placeholder="请输入 AccessKeySecret" value="{{ $strategy->configs['access_key_secret'] }}" />
|
<x-input type="password" name="configs[access_key_secret]" id="configs[access_key_secret]" placeholder="请输入 AccessKeySecret" value="{{ $strategy->configs->get('access_key_secret') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[endpoint]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域节点(Endpoint)</label>
|
<label for="configs[endpoint]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域节点(Endpoint)</label>
|
||||||
<x-input type="text" name="configs[endpoint]" id="configs[endpoint]" placeholder="请输入所属地域节点,例如:oss-cn-beijing.aliyuncs.com" value="{{ $strategy->configs['endpoint'] }}" />
|
<x-input type="text" name="configs[endpoint]" id="configs[endpoint]" placeholder="请输入所属地域节点,例如:oss-cn-beijing.aliyuncs.com" value="{{ $strategy->configs->get('endpoint') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Bucket 名称</label>
|
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Bucket 名称</label>
|
||||||
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket 名称" value="{{ $strategy->configs['bucket'] }}" />
|
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket 名称" value="{{ $strategy->configs->get('bucket') }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -114,27 +130,32 @@
|
|||||||
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Cos }}">
|
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Cos }}">
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[app_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AppId</label>
|
<label for="configs[app_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AppId</label>
|
||||||
<x-input type="text" name="configs[app_id]" id="configs[app_id]" placeholder="请输入 AppId" value="{{ $strategy->configs['app_id'] }}" />
|
<x-input type="text" name="configs[app_id]" id="configs[app_id]" placeholder="请输入 AppId" value="{{ $strategy->configs->get('app_id') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[secret_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretId</label>
|
<label for="configs[secret_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretId</label>
|
||||||
<x-input type="text" name="configs[secret_id]" id="configs[secret_id]" placeholder="请输入 SecretId" value="{{ $strategy->configs['secret_id'] }}" />
|
<x-input type="text" name="configs[secret_id]" id="configs[secret_id]" placeholder="请输入 SecretId" value="{{ $strategy->configs->get('secret_id') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
<label for="configs[secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
||||||
<x-input type="password" name="configs[secret_key]" id="configs[secret_key]" placeholder="请输入 SecretKey" value="{{ $strategy->configs['secret_key'] }}" />
|
<x-input type="password" name="configs[secret_key]" id="configs[secret_key]" placeholder="请输入 SecretKey" value="{{ $strategy->configs->get('secret_key') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[region]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>所属地域</label>
|
<label for="configs[region]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>所属地域</label>
|
||||||
<x-input type="text" name="configs[region]" id="configs[region]" placeholder="请输入所属地域,例如:ap-chengdu" value="{{ $strategy->configs['region'] }}" />
|
<x-input type="text" name="configs[region]" id="configs[region]" placeholder="请输入所属地域,例如:ap-chengdu" value="{{ $strategy->configs->get('region') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>储存桶名称</label>
|
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>储存桶名称</label>
|
||||||
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入储存桶名称" value="{{ $strategy->configs['bucket'] }}" />
|
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入储存桶名称" value="{{ $strategy->configs->get('bucket') }}" />
|
||||||
|
<small class="text-gray-500"><i class="fas fa-exclamation-circle"></i> 腾讯云储存桶名称由 名称+appid 组合,例如:test-125146xxxx,此处应该填写 test</>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -143,19 +164,23 @@
|
|||||||
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Kodo }}">
|
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Kodo }}">
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKey</label>
|
<label for="configs[access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKey</label>
|
||||||
<x-input type="text" name="configs[access_key]" id="configs[access_key]" placeholder="请输入 AccessKey" value="{{ $strategy->configs['access_key'] }}" />
|
<x-input type="text" name="configs[access_key]" id="configs[access_key]" placeholder="请输入 AccessKey" value="{{ $strategy->configs->get('access_key') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
<label for="configs[secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
||||||
<x-input type="password" name="configs[secret_key]" id="configs[secret_key]" placeholder="请输入 SecretKey" value="{{ $strategy->configs['secret_key'] }}" />
|
<x-input type="password" name="configs[secret_key]" id="configs[secret_key]" placeholder="请输入 SecretKey" value="{{ $strategy->configs->get('secret_key') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Bucket</label>
|
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Bucket</label>
|
||||||
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket" value="{{ $strategy->configs['bucket'] }}" />
|
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket" value="{{ $strategy->configs->get('bucket') }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -164,19 +189,23 @@
|
|||||||
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Uss }}">
|
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Uss }}">
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[service]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>服务名称</label>
|
<label for="configs[service]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>服务名称</label>
|
||||||
<x-input type="text" name="configs[service]" id="configs[service]" placeholder="请输入服务名称" value="{{ $strategy->configs['service'] }}" />
|
<x-input type="text" name="configs[service]" id="configs[service]" placeholder="请输入服务名称" value="{{ $strategy->configs->get('service') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[operator]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>操作员名称</label>
|
<label for="configs[operator]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>操作员名称</label>
|
||||||
<x-input type="text" name="configs[operator]" id="configs[operator]" placeholder="请输入操作员名称" value="{{ $strategy->configs['operator'] }}" />
|
<x-input type="text" name="configs[operator]" id="configs[operator]" placeholder="请输入操作员名称" value="{{ $strategy->configs->get('operator') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[password]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>操作员密码</label>
|
<label for="configs[password]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>操作员密码</label>
|
||||||
<x-input type="password" name="configs[password]" id="configs[password]" placeholder="请输入操作员密码" value="{{ $strategy->configs['password'] }}" />
|
<x-input type="password" name="configs[password]" id="configs[password]" placeholder="请输入操作员密码" value="{{ $strategy->configs->get('password') }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -185,41 +214,43 @@
|
|||||||
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Sftp }}">
|
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Sftp }}">
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
<label for="configs[root]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>根目录</label>
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="请输入根目录路径" value="{{ $strategy->configs['root'] }}" />
|
</div>
|
||||||
</div>
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[root]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>根目录</label>
|
||||||
|
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="请输入根目录路径" value="{{ $strategy->configs->get('root') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
<label for="configs[host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
||||||
<x-input type="text" name="configs[host]" id="configs[host]" placeholder="请输入主机地址,例如:127.0.0.1" value="{{ $strategy->configs['host'] }}" />
|
<x-input type="text" name="configs[host]" id="configs[host]" placeholder="请输入主机地址,例如:127.0.0.1" value="{{ $strategy->configs->get('host') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[port]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接端口</label>
|
<label for="configs[port]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接端口</label>
|
||||||
<x-input type="number" name="configs[port]" id="configs[port]" placeholder="请输入连接端口" value="{{ $strategy->configs['port'] }}" />
|
<x-input type="number" name="configs[port]" id="configs[port]" placeholder="请输入连接端口" value="{{ $strategy->configs->get('port') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[username]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>用户名</label>
|
<label for="configs[username]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>用户名</label>
|
||||||
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" value="{{ $strategy->configs['username'] }}" />
|
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" value="{{ $strategy->configs->get('username') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[password]" class="block text-sm font-medium text-gray-700"><span class="text-yellow-500">*</span>密码</label>
|
<label for="configs[password]" class="block text-sm font-medium text-gray-700"><span class="text-yellow-500">*</span>密码</label>
|
||||||
<x-input type="password" name="configs[password]" id="configs[password]" placeholder="如果使用私钥连接,可为空" value="{{ $strategy->configs['password'] }}" />
|
<x-input type="password" name="configs[password]" id="configs[password]" placeholder="如果使用私钥连接,可为空" value="{{ $strategy->configs->get('password') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[private_key]" class="block text-sm font-medium text-gray-700"><span class="text-yellow-500">*</span>私钥</label>
|
<label for="configs[private_key]" class="block text-sm font-medium text-gray-700"><span class="text-yellow-500">*</span>私钥</label>
|
||||||
<x-textarea name="configs[private_key]" id="configs[private_key]" placeholder="输入私钥文本内容,如果使用密码连接,可为空">{{ $strategy->configs['private_key'] }}</x-textarea>
|
<x-textarea name="configs[private_key]" id="configs[private_key]" placeholder="输入私钥文本内容,如果使用密码连接,可为空">{{ $strategy->configs->get('private_key') }}</x-textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[passphrase]" class="block text-sm font-medium text-gray-700">私钥口令</label>
|
<label for="configs[passphrase]" class="block text-sm font-medium text-gray-700">私钥口令</label>
|
||||||
<x-input type="password" name="configs[passphrase]" id="configs[passphrase]" placeholder="如果未设置私钥或私钥未设置口令,可为空" value="{{ $strategy->configs['passphrase'] }}" />
|
<x-input type="password" name="configs[passphrase]" id="configs[passphrase]" placeholder="如果未设置私钥或私钥未设置口令,可为空" value="{{ $strategy->configs->get('passphrase') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<label for="configs[use_agent]" class="block text-sm font-medium mb-2 text-gray-700">是否使用代理</label>
|
<label for="configs[use_agent]" class="block text-sm font-medium mb-2 text-gray-700">是否使用代理</label>
|
||||||
<x-switch id="configs[use_agent]" name="configs[use_agent]" value="1" :checked="(bool)$strategy->configs['use_agent']"></x-switch>
|
<x-switch id="configs[use_agent]" name="configs[use_agent]" value="1" :checked="(bool)$strategy->configs->get('use_agent')"></x-switch>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -233,38 +264,40 @@
|
|||||||
@endif
|
@endif
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
<label for="configs[root]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>根目录</label>
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="请输入根目录路径" value="{{ $strategy->configs['root'] }}" />
|
</div>
|
||||||
</div>
|
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||||
|
<label for="configs[root]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>根目录</label>
|
||||||
|
<x-input type="text" name="configs[root]" id="configs[root]" autocomplete="text" placeholder="请输入根目录路径" value="{{ $strategy->configs->get('root') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
<label for="configs[host]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>主机地址</label>
|
||||||
<x-input type="text" name="configs[host]" id="configs[host]" placeholder="请输入主机地址,例如:127.0.0.1" value="{{ $strategy->configs['host'] }}" />
|
<x-input type="text" name="configs[host]" id="configs[host]" placeholder="请输入主机地址,例如:127.0.0.1" value="{{ $strategy->configs->get('host') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[port]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接端口</label>
|
<label for="configs[port]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接端口</label>
|
||||||
<x-input type="number" name="configs[port]" id="configs[port]" placeholder="请输入连接端口 21/20" value="20" value="{{ $strategy->configs['port'] }}" />
|
<x-input type="number" name="configs[port]" id="configs[port]" placeholder="请输入连接端口 21/20" value="20" value="{{ $strategy->configs->get('port') }}" />
|
||||||
<small class="text-gray-500"><i class="fas fa-exclamation-circle"></i> 通常情况下,FTP 的被动模式连接端口为 21,主动模式为 20</small>
|
<small class="text-gray-500"><i class="fas fa-exclamation-circle"></i> 通常情况下,FTP 的被动模式连接端口为 21,主动模式为 20</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[username]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>用户名</label>
|
<label for="configs[username]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>用户名</label>
|
||||||
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" value="{{ $strategy->configs['username'] }}" />
|
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" value="{{ $strategy->configs->get('username') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[password]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>密码</label>
|
<label for="configs[password]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>密码</label>
|
||||||
<x-input type="password" name="configs[password]" id="configs[password]" placeholder="请输入密码" value="{{ $strategy->configs['password'] }}" />
|
<x-input type="password" name="configs[password]" id="configs[password]" placeholder="请输入密码" value="{{ $strategy->configs->get('password') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<label for="configs[ssl]" class="block text-sm font-medium mb-2 text-gray-700">加密连接</label>
|
<label for="configs[ssl]" class="block text-sm font-medium mb-2 text-gray-700">加密连接</label>
|
||||||
<x-switch id="configs[ssl]" name="configs[ssl]" value="1" :checked="(bool)$strategy->configs['ssl']"></x-switch>
|
<x-switch id="configs[ssl]" name="configs[ssl]" value="1" :checked="(bool)$strategy->configs->get('ssl')"></x-switch>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<label for="configs[passive]" class="block text-sm font-medium my-2 text-gray-700">被动模式</label>
|
<label for="configs[passive]" class="block text-sm font-medium my-2 text-gray-700">被动模式</label>
|
||||||
<x-switch id="configs[passive]" name="configs[passive]" value="1" :checked="(bool)$strategy->configs['passive']"></x-switch>
|
<x-switch id="configs[passive]" name="configs[passive]" value="1" :checked="(bool)$strategy->configs->get('passive')"></x-switch>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -273,19 +306,35 @@
|
|||||||
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Webdav }}">
|
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Webdav }}">
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[base_uri]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接地址</label>
|
<label for="configs[base_uri]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接地址</label>
|
||||||
<x-input type="url" name="configs[base_uri]" id="configs[base_uri]" placeholder="请输入连接地址" value="{{ $strategy->configs['base_uri'] }}" />
|
<x-input type="url" name="configs[base_uri]" id="configs[base_uri]" placeholder="请输入连接地址" value="{{ $strategy->configs->get('base_uri') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="webdav-configs[auth_type]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>认证方式</label>
|
||||||
|
<x-select id="webdav-auth-type" name="configs[auth_type]" select2>
|
||||||
|
@foreach(\App\Models\Strategy::WEBDAV_AUTH_TYPES as $key => $type)
|
||||||
|
<option value="{{ $key }}" {{ $key == $strategy->configs->get('auth_type') ? 'selected' : '' }}>{{ $type }}</option>
|
||||||
|
@endforeach
|
||||||
|
</x-select>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="webdav-configs[prefix]" class="block text-sm font-medium text-gray-700">路径前缀</label>
|
||||||
|
<x-input type="text" name="configs[prefix]" id="webdav-configs[prefix]" placeholder="请输入路径前缀" value="{{ $strategy->configs->get('prefix') }}"></x-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[username]" class="block text-sm font-medium text-gray-700">用户名</label>
|
<label for="configs[username]" class="block text-sm font-medium text-gray-700">用户名</label>
|
||||||
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" value="{{ $strategy->configs['username'] }}" />
|
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" value="{{ $strategy->configs->get('username') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[password]" class="block text-sm font-medium text-gray-700">密码</label>
|
<label for="configs[password]" class="block text-sm font-medium text-gray-700">密码</label>
|
||||||
<x-input type="password" name="configs[password]" id="configs[password]" placeholder="请输入密码" value="{{ $strategy->configs['password'] }}" />
|
<x-input type="password" name="configs[password]" id="configs[password]" placeholder="请输入密码" value="{{ $strategy->configs->get('password') }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -294,23 +343,36 @@
|
|||||||
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Minio }}">
|
<div class="col-span-6 mb-4" data-driver="{{ \App\Enums\StrategyKey::Minio }}">
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
<label for="configs[url]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>访问域名</label>
|
||||||
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs['url'] }}" />
|
<x-input type="url" name="configs[url]" id="configs[url]" placeholder="请输入图片访问域名 http(s)://" value="{{ $strategy->configs->get('url') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[endpoint]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接地址</label>
|
<label for="configs[queries]" class="block text-sm font-medium text-gray-700">URL Queries</label>
|
||||||
<x-input type="url" name="configs[endpoint]" id="configs[endpoint]" placeholder="请输入连接地址" value="{{ $strategy->configs['endpoint'] }}" />
|
<x-input type="text" name="configs[queries]" id="configs[queries]" placeholder="请输入 url 额外参数" value="{{ $strategy->configs->get('queries') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKey</label>
|
<label for="configs[access_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKey</label>
|
||||||
<x-input type="text" name="configs[access_key]" id="configs[access_key]" placeholder="请输入 AccessKey" value="{{ $strategy->configs['access_key'] }}" />
|
<x-input type="text" name="configs[access_key]" id="configs[access_key]" placeholder="请输入 AccessKey" value="{{ $strategy->configs->get('access_key') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
<label for="configs[secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
||||||
<x-input type="password" name="configs[secret_key]" id="configs[secret_key]" placeholder="请输入 SecretKey" value="{{ $strategy->configs['secret_key'] }}" />
|
<x-input type="password" name="configs[secret_key]" id="configs[secret_key]" placeholder="请输入 SecretKey" value="{{ $strategy->configs->get('secret_key') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[endpoint]" class="block text-sm font-medium text-gray-700">连接地址</label>
|
||||||
|
<x-input type="url" name="configs[endpoint]" id="configs[endpoint]" placeholder="请输入连接地址" value="{{ $strategy->configs->get('endpoint') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
|
<label for="configs[region]" class="block text-sm font-medium text-gray-700">区域(region)</label>
|
||||||
|
<x-input type="text" name="configs[region]" id="configs[region]" placeholder="请输入区域,例如:us-east-1" value="{{ $strategy->configs->get('region') }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||||
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>储存桶名称</label>
|
<label for="configs[bucket]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>储存桶名称</label>
|
||||||
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket 名称" value="{{ $strategy->configs['bucket'] }}" />
|
<x-input type="text" name="configs[bucket]" id="configs[bucket]" placeholder="请输入 Bucket 名称" value="{{ $strategy->configs->get('bucket') }}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6">
|
||||||
|
<label for="configs[bucket_endpoint]" class="block text-sm font-medium mb-2 text-gray-700">BucketEndpoint</label>
|
||||||
|
<x-switch id="configs[bucket_endpoint]" name="configs[bucket_endpoint]" value="1" :checked="(bool)$strategy->configs->get('bucket_endpoint')"></x-switch>
|
||||||
|
<p><small class="text-gray-500"><i class="fas fa-exclamation-circle"></i> 开启此选项后将会直接以「连接地址」作为数据交互传输域名,否则可能会以桶名称拼接域名(例如:http://桶名称.连接地址.com)</small></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<div class="mt-5 md:mt-0 md:col-span-2">
|
<div class="mt-5 md:mt-0 md:col-span-2">
|
||||||
<form action="{{ route('admin.user.update', ['id' => $user->id ?: '0']) }}" method="POST">
|
<form action="{{ route('admin.user.update', ['id' => $user->id ?: '0']) }}" method="POST">
|
||||||
<div class="overflow-hidden rounded-md">
|
<div class="overflow-hidden rounded-md shadow-custom">
|
||||||
<div class="px-4 py-5 bg-white sm:p-6">
|
<div class="px-4 py-5 bg-white sm:p-6">
|
||||||
<div class="grid grid-cols-6 gap-6">
|
<div class="grid grid-cols-6 gap-6">
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<x-modal>
|
<x-modal id="user-modal">
|
||||||
<div id="modal-content"></div>
|
<div id="modal-content"></div>
|
||||||
</x-modal>
|
</x-modal>
|
||||||
|
|
||||||
@@ -135,11 +135,11 @@
|
|||||||
|
|
||||||
$('#modal-content').html(html);
|
$('#modal-content').html(html);
|
||||||
|
|
||||||
modal.open = true;
|
modal.open('user-modal')
|
||||||
});
|
});
|
||||||
$('[data-operate="delete"]').click(function () {
|
$('[data-operate="delete"]').click(function () {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: `确认删除用户【${$(this).closest('tr').find('td.name').text()}】吗?`,
|
title: `确认删除用户【${$(this).closest('tr').data('json').name}】吗?`,
|
||||||
text: "⚠️注意,删除后不可恢复,且该用户的图片将会变成游客身份!",
|
text: "⚠️注意,删除后不可恢复,且该用户的图片将会变成游客身份!",
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
|
|||||||
@@ -40,16 +40,26 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-end mt-4">
|
<div class="flex items-center justify-between mt-4">
|
||||||
@if (Route::has('password.request'))
|
<div class="flex items-center text-sm">
|
||||||
<a class="underline text-sm text-gray-600 hover:text-gray-900" href="{{ route('password.request') }}">
|
@if(\App\Utils::config(\App\Enums\ConfigKey::IsEnableRegistration))
|
||||||
{{ __('Forgot your password?') }}
|
没有账号?
|
||||||
</a>
|
<a class="underline text-gray-600 hover:text-gray-900" href="{{ route('register') }}">
|
||||||
@endif
|
注册
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
@if (Route::has('password.request'))
|
||||||
|
<a class="underline text-sm text-gray-600 hover:text-gray-900" href="{{ route('password.request') }}">
|
||||||
|
{{ __('Forgot your password?') }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
|
||||||
<x-button class="ml-3">
|
<x-button class="ml-3">
|
||||||
{{ __('Log in') }}
|
{{ __('Log in') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</x-auth-card>
|
</x-auth-card>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<x-app-layout>
|
<x-app-layout>
|
||||||
<div class="my-6 md:my-9">
|
<div class="my-6 md:my-9">
|
||||||
<p class="text-xl mb-2 text-gray-800 font-semibold">接口说明</p>
|
<p class="text-xl mb-2 text-gray-800 font-semibold">接口说明</p>
|
||||||
<div class="space-y-4 bg-white p-3 rounded-md mb-10">
|
<div class="space-y-4 bg-white p-3 rounded-md mb-10 shadow-custom">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-lg text-gray-700 font-semibold">接口URL</p>
|
<p class="text-lg text-gray-700 font-semibold">接口URL</p>
|
||||||
<x-code>{{ request()->getSchemeAndHttpHost() }}/api/v1</x-code>
|
<x-code>{{ request()->getSchemeAndHttpHost() }}/api/v1</x-code>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="text-lg text-gray-700 font-semibold">验证方式</p>
|
<p class="text-lg text-gray-700 font-semibold">验证方式</p>
|
||||||
<div class="my-2 text-sm bg-white rounded-md p-4 overflow-x-auto">
|
<div class="my-2 text-sm bg-white rounded-md p-4 overflow-x-auto">
|
||||||
当前版本接口采用 「HTTP 基本验证」的方式验证授权,获取到 token 后,通过设置请求 header 标头来验证请求,例如:
|
当前版本接口采用 「HTTP 基本验证」的方式验证授权,获取到 token 后,通过设置请求 header 标头来验证请求(Bearer Token),例如:
|
||||||
<b class="block my-2 text-gray-600 text-sm">"Authorization": "Bearer 1|1bJbwlqBfnggmOMEZqXT5XusaIwqiZjCDs7r1Ob5"</b>
|
<b class="block my-2 text-gray-600 text-sm">"Authorization": "Bearer 1|1bJbwlqBfnggmOMEZqXT5XusaIwqiZjCDs7r1Ob5"</b>
|
||||||
<p class="text-sm">如果未设置 Authorization 的情况下请求上传接口,将会被视为游客上传。</p>
|
<p class="text-sm">如果未设置 Authorization 的情况下请求上传接口,将会被视为游客上传。</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-xl mb-2 text-gray-800 font-semibold">授权相关</p>
|
<p class="text-xl mb-2 text-gray-800 font-semibold">授权相关</p>
|
||||||
<div class="space-y-4 bg-white p-3 rounded-md mb-10">
|
<div class="space-y-4 bg-white p-3 rounded-md mb-10 shadow-custom">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-lg text-gray-700 font-semibold">生成 Token</p>
|
<p class="text-lg text-gray-700 font-semibold">生成 Token</p>
|
||||||
<x-code><span class="text-green-500 select-none">POST </span>/tokens</x-code>
|
<x-code><span class="text-green-500 select-none">POST </span>/tokens</x-code>
|
||||||
@@ -319,7 +319,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-xl mb-2 text-gray-800 font-semibold">策略相关</p>
|
<p class="text-xl mb-2 text-gray-800 font-semibold">策略相关</p>
|
||||||
<div class="space-y-4 bg-white p-3 rounded-md mb-10">
|
<div class="space-y-4 bg-white p-3 rounded-md mb-10 shadow-custom">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-lg text-gray-700 font-semibold">策略列表</p>
|
<p class="text-lg text-gray-700 font-semibold">策略列表</p>
|
||||||
<x-code><span class="text-sky-500 select-none">GET </span>/strategies</x-code>
|
<x-code><span class="text-sky-500 select-none">GET </span>/strategies</x-code>
|
||||||
@@ -404,7 +404,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-xl mb-2 text-gray-800 font-semibold">图片相关</p>
|
<p class="text-xl mb-2 text-gray-800 font-semibold">图片相关</p>
|
||||||
<div class="space-y-4 bg-white p-3 rounded-md mb-10">
|
<div class="space-y-4 bg-white p-3 rounded-md mb-10 shadow-custom">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-lg text-gray-700 font-semibold">上传图片</p>
|
<p class="text-lg text-gray-700 font-semibold">上传图片</p>
|
||||||
<x-code><span class="text-green-500 select-none">POST </span>/upload</x-code>
|
<x-code><span class="text-green-500 select-none">POST </span>/upload</x-code>
|
||||||
@@ -822,7 +822,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-xl mb-2 text-gray-800 font-semibold">相册相关</p>
|
<p class="text-xl mb-2 text-gray-800 font-semibold">相册相关</p>
|
||||||
<div class="space-y-4 bg-white p-3 rounded-md mb-10">
|
<div class="space-y-4 bg-white p-3 rounded-md mb-10 shadow-custom">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-lg text-gray-700 font-semibold">相册列表</p>
|
<p class="text-lg text-gray-700 font-semibold">相册列表</p>
|
||||||
<x-code><span class="text-sky-500 select-none">GET </span>/albums</x-code>
|
<x-code><span class="text-sky-500 select-none">GET </span>/albums</x-code>
|
||||||
|
|||||||
28
resources/views/common/notice.blade.php
Normal file
28
resources/views/common/notice.blade.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
@if($_is_notice)
|
||||||
|
|
||||||
|
<x-modal id="notice-modal">
|
||||||
|
<div class="markdown-body">
|
||||||
|
{!! (new Parsedown())->parse(\App\Utils::config(\App\Enums\ConfigKey::SiteNotice)) !!}
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 w-full text-right">
|
||||||
|
<x-button type="button" @click="$store.modal.close('notice-modal');">OK</x-button>
|
||||||
|
</div>
|
||||||
|
</x-modal>
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
let noticeHash = "{{ md5(\App\Utils::config(\App\Enums\ConfigKey::SiteNotice)) }}";
|
||||||
|
|
||||||
|
let openNotice = function () {
|
||||||
|
Alpine.store('modal').open('notice-modal');
|
||||||
|
localStorage.setItem('notice-hash', noticeHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localStorage.getItem('notice-hash') !== noticeHash) {
|
||||||
|
setTimeout(function () {
|
||||||
|
openNotice();
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
@endif
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
{{ $logo }}
|
{{ $logo }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white overflow-hidden sm:rounded-lg">
|
<div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white overflow-hidden sm:rounded-lg shadow-custom">
|
||||||
{{ $slot }}
|
{{ $slot }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="rounded w-full overflow-hidden">
|
<div class="rounded w-full overflow-hidden shadow-custom">
|
||||||
<div class="px-4 py-3 bg-slate-50 text-gray-800 text-md truncate">{{ $title }}</div>
|
<div class="px-4 py-3 bg-slate-50 text-gray-800 text-md truncate">{{ $title }}</div>
|
||||||
<div class="bg-white w-full">
|
<div class="bg-white w-full">
|
||||||
{{ $content }}
|
{{ $content }}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-500 hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500']) }}>
|
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex justify-center py-2 px-4 text-sm font-medium rounded-md text-gray-600 bg-black/10 hover:bg-black/20 hover:text-gray-700']) }}>
|
||||||
{{ $slot }}
|
{{ $slot }}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<a {{$attributes->merge(['class' => 'block px-4 py-2 active:bg-gray-100 text-sm text-gray-700', 'role' => 'menuitem', 'tabindex' => '-1']) }}>{{ $slot }}</a>
|
<a {{$attributes->merge(['class' => 'block px-4 py-2 active:bg-gray-100 text-sm text-gray-700 truncate hover:bg-sky-500 hover:text-white', 'role' => 'menuitem', 'tabindex' => '-1']) }}>{{ $slot }}</a>
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
|
|
||||||
<div x-show="open"
|
<div x-show="open"
|
||||||
x-transition:enter="transition ease-out duration-200"
|
x-transition:enter="transition ease-out duration-200"
|
||||||
x-transition:enter-start="transform opacity-0 scale-95"
|
x-transition:enter-start="transform opacity-0 translate-y-9"
|
||||||
x-transition:enter-end="transform opacity-100 scale-100"
|
x-transition:enter-end="transform opacity-100 translate-y-0"
|
||||||
x-transition:leave="transition ease-in duration-75"
|
x-transition:leave="transition ease-in duration-75"
|
||||||
x-transition:leave-start="transform opacity-100 scale-100"
|
x-transition:leave-start="transform opacity-100 translate-y-0"
|
||||||
x-transition:leave-end="transform opacity-0 scale-95"
|
x-transition:leave-end="transform opacity-0 translate-y-9"
|
||||||
class="absolute z-[9] {{ $classes[$direction] }} mt-2 w-48 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
|
class="absolute z-[9] {{ $classes[$direction] }} mt-2 w-48 rounded-md shadow-[10px_0px_50px_-15px_rgba(0,0,0,0.25)] py-1 bg-white "
|
||||||
role="menu"
|
role="menu"
|
||||||
aria-orientation="vertical"
|
aria-orientation="vertical"
|
||||||
aria-labelledby="user-menu-button"
|
aria-labelledby="user-menu-button"
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
<div {{ $attributes->merge(['class' => "fixed z-10 inset-0 overflow-y-auto"]) }} role="dialog" aria-modal="true" x-data x-cloak x-show="$store.modal.open">
|
@props(['id' => 'modal'])
|
||||||
|
|
||||||
|
<div {{ $attributes->merge(['id' => $id, 'class' => "fixed z-10 inset-0 overflow-y-auto"]) }} role="dialog" aria-modal="true" x-data x-cloak x-show="$store.modal.isOpen('{{ $id }}')">
|
||||||
<div class="flex min-h-screen text-center md:block md:px-2 lg:px-4" style="font-size: 0">
|
<div class="flex min-h-screen text-center md:block md:px-2 lg:px-4" style="font-size: 0">
|
||||||
<div x-transition:enter="transition ease-out duration-300"
|
<div x-transition:enter="transition ease-out duration-300"
|
||||||
x-transition:enter-start="transform opacity-0"
|
x-transition:enter-start="transform opacity-0"
|
||||||
@@ -6,8 +8,8 @@
|
|||||||
x-transition:leave="transition ease-in duration-200"
|
x-transition:leave="transition ease-in duration-200"
|
||||||
x-transition:leave-start="transform opacity-100"
|
x-transition:leave-start="transform opacity-100"
|
||||||
x-transition:leave-end="transform opacity-0"
|
x-transition:leave-end="transform opacity-0"
|
||||||
x-show="$store.modal.open"
|
x-show="$store.modal.isOpen('{{ $id }}')"
|
||||||
@click="$store.modal.open = false"
|
@click="$store.modal.close('{{ $id }}')"
|
||||||
class="hidden fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity md:block"
|
class="hidden fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity md:block"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
@@ -20,22 +22,22 @@
|
|||||||
x-transition:leave="transition ease-in duration-200"
|
x-transition:leave="transition ease-in duration-200"
|
||||||
x-transition:leave-start="transform opacity-100 translate-y-0 md:scale-100"
|
x-transition:leave-start="transform opacity-100 translate-y-0 md:scale-100"
|
||||||
x-transition:leave-end="transform opacity-0 translate-y-4 md:translate-y-0 md:scale-95"
|
x-transition:leave-end="transform opacity-0 translate-y-4 md:translate-y-0 md:scale-95"
|
||||||
x-show="$store.modal.open"
|
x-show="$store.modal.isOpen('{{ $id }}')"
|
||||||
class="flex text-base text-left transform transition w-full md:inline-block md:max-w-2xl md:px-4 md:my-8 md:align-middle lg:max-w-4xl"
|
class="flex text-base text-left transform transition w-full md:inline-block md:max-w-2xl md:px-4 md:my-8 md:align-middle lg:max-w-4xl"
|
||||||
>
|
>
|
||||||
<div class="w-full relative flex bg-white px-4 pt-14 pb-8 overflow-hidden shadow-lg sm:px-6 sm:pt-8 md:p-6 lg:p-8 md:rounded-sm">
|
<div class="w-full relative flex bg-white px-4 pt-14 pb-8 overflow-hidden shadow-lg sm:px-6 sm:pt-8 md:p-6 lg:p-8 md:rounded-sm">
|
||||||
<button type="button" class="absolute top-2 right-2 text-gray-400 hover:text-gray-500 sm:top-4 sm:right-4 md:top-3 md:right-3 lg:top-4 lg:right-4" @click="Alpine.store('modal').toggle()">
|
<button type="button" class="absolute top-2 right-2 text-gray-400 hover:text-gray-500 sm:top-4 sm:right-4 md:top-3 md:right-3 lg:top-4 lg:right-4" @click="$store.modal.close('{{ $id }}')">
|
||||||
<span class="sr-only">Close</span>
|
<span class="sr-only">Close</span>
|
||||||
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="flex items-center justify-center h-24 w-full" x-show="$store.modal.loading">
|
<div class="flex items-center justify-center h-24 w-full" x-show="$store.modal.isLoading('{{ $id }}')">
|
||||||
<x-loading-spin />
|
<x-loading-spin />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full" x-show="! $store.modal.loading">
|
<div class="w-full" x-show="! $store.modal.isLoading('{{ $id }}')">
|
||||||
{{ $slot ?? '' }}
|
{{ $slot ?? '' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="-my-2 sm:-mx-6 lg:-mx-8">
|
<div class="-my-2 sm:-mx-6 lg:-mx-8">
|
||||||
<div class="py-2 align-middle inline-block w-full sm:px-6 lg:px-8">
|
<div class="py-2 align-middle inline-block w-full sm:px-6 lg:px-8">
|
||||||
<div class="overflow-x-auto sm:rounded-lg bg-white w-full">
|
<div class="overflow-x-auto sm:rounded-lg bg-white w-full shadow-custom">
|
||||||
<table class="min-w-full w-full divide-y divide-gray-200">
|
<table class="min-w-full w-full divide-y divide-gray-200">
|
||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -45,6 +45,12 @@
|
|||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6 text-sm text-gray-500">
|
||||||
|
<p><i class="fas fa-exclamation-circle"></i> 请确保<b>数据库版本</b>达到要求。</p>
|
||||||
|
<p><i class="fas fa-exclamation-circle"></i> 请确保程序<b>目录、文件的权限</b>设置正确。</p>
|
||||||
|
<p><i class="fas fa-exclamation-circle"></i> 出现安装拓展、启用函数后未生效,请尝试<b>重启 PHP</b>。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-6 text-right">
|
<div class="mt-6 text-right">
|
||||||
@if($status)
|
@if($status)
|
||||||
<a href="javascript:void(0)" id="next" class="rounded-md px-4 py-2 bg-blue-500 text-white">下一步</a>
|
<a href="javascript:void(0)" id="next" class="rounded-md px-4 py-2 bg-blue-500 text-white">下一步</a>
|
||||||
|
|||||||
@@ -15,11 +15,8 @@
|
|||||||
@stack('styles')
|
@stack('styles')
|
||||||
|
|
||||||
<!-- Styles -->
|
<!-- Styles -->
|
||||||
<link rel="stylesheet" href="{{ asset('css/common.css') }}">
|
<link rel="stylesheet" href="{{ asset('css/common.css') }}?t=20220817">
|
||||||
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
|
<link rel="stylesheet" href="{{ asset('css/app.css') }}?t=20220817">
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
<script src="{{ asset('js/app.js') }}"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body class="font-sans antialiased overflow-hidden">
|
<body class="font-sans antialiased overflow-hidden">
|
||||||
<div class="min-h-screen bg-gray-100" x-data x-cloak>
|
<div class="min-h-screen bg-gray-100" x-data x-cloak>
|
||||||
@@ -46,6 +43,9 @@
|
|||||||
</x-container>
|
</x-container>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script src="{{ asset('js/app.js') }}?t=20220817"></script>
|
||||||
|
@include('common.notice')
|
||||||
<script>
|
<script>
|
||||||
// 开关组件默认值
|
// 开关组件默认值
|
||||||
let setSwitch = function (e) {
|
let setSwitch = function (e) {
|
||||||
|
|||||||
@@ -15,17 +15,16 @@
|
|||||||
@stack('styles')
|
@stack('styles')
|
||||||
|
|
||||||
<!-- Styles -->
|
<!-- Styles -->
|
||||||
<link rel="stylesheet" href="{{ asset('css/common.css') }}">
|
<link rel="stylesheet" href="{{ asset('css/common.css') }}?t=20220817">
|
||||||
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
|
<link rel="stylesheet" href="{{ asset('css/app.css') }}?t=20220817">
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
<script src="{{ asset('js/app.js') }}"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body class="font-sans antialiased">
|
<body class="font-sans antialiased">
|
||||||
<div class="min-h-screen text-gray-900 bg-gray-100">
|
<div class="min-h-screen text-gray-900 bg-gray-100">
|
||||||
{{ $slot }}
|
{{ $slot }}
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script src="{{ asset('js/app.js') }}?t=20220817"></script>
|
||||||
@if(file_exists(public_path('js/custom.js')))
|
@if(file_exists(public_path('js/custom.js')))
|
||||||
<script src="{{ asset('js/custom.js') }}"></script>
|
<script src="{{ asset('js/custom.js') }}"></script>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<header class="transition-all duration-300 w-full h-14 bg-gray-700 text-white flex justify-center fixed top-0 z-[9]">
|
<header class="transition-all duration-300 w-full h-14 bg-gray-700 text-white flex justify-center fixed top-0 z-[9] shadow-[0_15px_10px_-15px_rgba(0,0,0,0.3)]">
|
||||||
<x-container class="w-full px-6 flex justify-between items-center">
|
<x-container class="w-full px-6 flex justify-between items-center">
|
||||||
<div class="flex justify-start items-center max-w-[70%]">
|
<div class="flex justify-start items-center max-w-[70%]">
|
||||||
<a href="javascript:void(0)" @click="$store.sidebar.toggle()" class="w-6 h-6 p-4 rounded-full sm:hidden -ml-1 mr-4 flex justify-center items-center">
|
<a href="javascript:void(0)" @click="$store.sidebar.toggle()" class="w-6 h-6 p-4 rounded-full sm:hidden -ml-1 mr-4 flex justify-center items-center">
|
||||||
@@ -7,9 +7,8 @@
|
|||||||
<a href="" class="text-xl truncate" id="header-title">@yield('title', \App\Utils::config(\App\Enums\ConfigKey::AppName))</a>
|
<a href="" class="text-xl truncate" id="header-title">@yield('title', \App\Utils::config(\App\Enums\ConfigKey::AppName))</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end items-center space-x-4">
|
<div class="flex justify-end items-center space-x-4">
|
||||||
@if($_group->strategies->isNotEmpty())
|
@includeWhen($_is_notice, 'layouts.notice')
|
||||||
@include('layouts.strategies')
|
@includeWhen($_group->strategies->isNotEmpty(), 'layouts.strategies')
|
||||||
@endif
|
|
||||||
@include('layouts.user-nav')
|
@include('layouts.user-nav')
|
||||||
</div>
|
</div>
|
||||||
</x-container>
|
</x-container>
|
||||||
|
|||||||
15
resources/views/layouts/notice.blade.php
Normal file
15
resources/views/layouts/notice.blade.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
@if($_is_notice)
|
||||||
|
<button type="button" class="bg-gray-800 flex items-center text-sm rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white" id="open-notice" aria-expanded="false" aria-haspopup="true">
|
||||||
|
<div class="h-8 w-8 rounded-full flex items-center justify-center bg-white">
|
||||||
|
<i class="fas fa-envelope text-gray-900"></i>
|
||||||
|
</div>
|
||||||
|
<span class="px-2 sm:block hidden">公告</span>
|
||||||
|
</button>
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
$('#open-notice').click(function () {
|
||||||
|
openNotice();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
@endif
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<nav class="transition-all duration-300 -left-64 sm:left-0 h-screen sm:w-64 bg-white fixed z-10 shadow-lg sm:shadow-none" :class="{
|
<nav class="transition-all duration-300 -left-[600px] sm:left-0 w-3/4 sm:w-64 h-screen bg-white fixed z-10 shadow-custom" :class="{
|
||||||
'-left-64': ! $store.sidebar.open,
|
'-left-[600px]': ! $store.sidebar.open,
|
||||||
'left-0': $store.sidebar.open,
|
'left-0': $store.sidebar.open
|
||||||
'w-3/4': $store.sidebar.open
|
|
||||||
}">
|
}">
|
||||||
<div class="px-6 h-14 flex justify-between sm:justify-center items-center bg-gray-600 text-white text-xl">
|
<div class="px-6 h-14 flex justify-between sm:justify-center items-center bg-gray-600 text-white text-xl">
|
||||||
<a href="/" class="truncate">{{ \App\Utils::config(\App\Enums\ConfigKey::AppName) }}</a>
|
<a href="/" class="truncate">{{ \App\Utils::config(\App\Enums\ConfigKey::AppName) }}</a>
|
||||||
@@ -41,7 +40,7 @@
|
|||||||
</x-nav-link>
|
</x-nav-link>
|
||||||
@endif
|
@endif
|
||||||
@if(\App\Utils::config(\App\Enums\ConfigKey::IsEnableApi))
|
@if(\App\Utils::config(\App\Enums\ConfigKey::IsEnableApi))
|
||||||
<x-nav-link :href="route('api')" :active="request()->routeIs('apis')">
|
<x-nav-link :href="route('api')" :active="request()->routeIs('api')">
|
||||||
<x-slot name="icon"><i class="fas fa-link text-blue-500"></i></x-slot>
|
<x-slot name="icon"><i class="fas fa-link text-blue-500"></i></x-slot>
|
||||||
<x-slot name="name">接口</x-slot>
|
<x-slot name="name">接口</x-slot>
|
||||||
</x-nav-link>
|
</x-nav-link>
|
||||||
@@ -81,9 +80,9 @@
|
|||||||
|
|
||||||
<div id="capacity-progress" class="flex flex-col space-y-2 mb-5 px-5 w-full mt-10">
|
<div id="capacity-progress" class="flex flex-col space-y-2 mb-5 px-5 w-full mt-10">
|
||||||
<p class="text-gray-700 text-sm">容量使用</p>
|
<p class="text-gray-700 text-sm">容量使用</p>
|
||||||
<progress class="w-full h-1.5" value="{{ Auth::user()->images->sum('size') }}" max="{{ Auth::user()->capacity }}"></progress>
|
<progress class="w-full h-1.5" value="{{ Auth::user()->use_capacity }}" max="{{ Auth::user()->capacity }}"></progress>
|
||||||
<p class="text-gray-700 text-sm truncate">
|
<p class="text-gray-700 text-sm truncate">
|
||||||
<span class="used">{{ \App\Utils::formatSize(Auth::user()->images->sum('size') * 1024) }}</span>
|
<span class="used">{{ \App\Utils::formatSize(Auth::user()->use_capacity * 1024) }}</span>
|
||||||
/
|
/
|
||||||
<span class="total">{{ \App\Utils::formatSize(Auth::user()->capacity * 1024) }}</span>
|
<span class="total">{{ \App\Utils::formatSize(Auth::user()->capacity * 1024) }}</span>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="h-8 w-8 rounded-full flex items-center justify-center bg-white">
|
<div class="h-8 w-8 rounded-full flex items-center justify-center bg-white">
|
||||||
<i class="fas fa-server text-gray-900"></i>
|
<i class="fas fa-server text-gray-900"></i>
|
||||||
</div>
|
</div>
|
||||||
<span class="px-2 sm:block hidden" id="strategy-selected">获取中...</span>
|
<span class="px-2 sm:block hidden" id="strategy-selected" data-id="0">获取中...</span>
|
||||||
</button>
|
</button>
|
||||||
</x-slot>
|
</x-slot>
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
@push('scripts')
|
@push('scripts')
|
||||||
<script>
|
<script>
|
||||||
let defaultStrategy = {{ Auth::check() ? Auth::user()->configs[\App\Enums\UserConfigKey::DefaultStrategy] : 0 }} || (localStorage.getItem('strategy') || 0);
|
let defaultStrategy = {{ Auth::check() ? Auth::user()->configs->get('default_strategy') : 0 }} || (localStorage.getItem('strategy') || 0);
|
||||||
let setStrategy = function (id) {
|
let setStrategy = function (id) {
|
||||||
let isSelected = false;
|
let isSelected = false;
|
||||||
$('#strategies a').each(function () {
|
$('#strategies a').each(function () {
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
if (! isSelected) {
|
if (! isSelected) {
|
||||||
let $first = $('#strategies a:first-child');
|
let $first = $('#strategies a:first-child');
|
||||||
localStorage.setItem('strategy', $first.data('id'))
|
localStorage.setItem('strategy', $first.data('id'))
|
||||||
$('#strategy-selected').text($first.text());
|
$('#strategy-selected').text($first.text()).data('id', $first.data('id'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,28 +3,28 @@
|
|||||||
<x-app-layout>
|
<x-app-layout>
|
||||||
<div class="my-6 md:my-9">
|
<div class="my-6 md:my-9">
|
||||||
<div class="space-y-6 md:space-y-0 md:grid md:grid-cols-2 xl:grid-cols-4 md:gap-x-4 xl:gap-x-8 md:gap-y-4 xl:gap-y-8">
|
<div class="space-y-6 md:space-y-0 md:grid md:grid-cols-2 xl:grid-cols-4 md:gap-x-4 xl:gap-x-8 md:gap-y-4 xl:gap-y-8">
|
||||||
<div class="flex bg-white rounded p-4 space-x-4">
|
<div class="flex bg-white rounded p-4 space-x-4 shadow-custom">
|
||||||
<i class="fas fa-images text-amber-500 text-5xl"></i>
|
<i class="fas fa-images text-amber-500 text-5xl"></i>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<p class="text-gray-700 text-sm">图片数量</p>
|
<p class="text-gray-700 text-sm">图片数量</p>
|
||||||
<p class="text-gray-800 font-semibold text-xl">{{ $user->image_num }}</p>
|
<p class="text-gray-800 font-semibold text-xl">{{ $user->image_num }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex bg-white rounded p-4 space-x-4">
|
<div class="flex bg-white rounded p-4 space-x-4 shadow-custom">
|
||||||
<i class="fas fa-hdd text-red-500 text-5xl"></i>
|
<i class="fas fa-hdd text-red-500 text-5xl"></i>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<p class="text-gray-700 text-sm">可用储存</p>
|
<p class="text-gray-700 text-sm">可用储存</p>
|
||||||
<p class="text-gray-800 font-semibold text-xl">{{ \App\Utils::formatSize(($user->capacity - $user->images->sum('size')) * 1024) }}</p>
|
<p class="text-gray-800 font-semibold text-xl">{{ \App\Utils::formatSize(($user->capacity - $user->use_capacity) * 1024) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex bg-white rounded p-4 space-x-4">
|
<div class="flex bg-white rounded p-4 space-x-4 shadow-custom">
|
||||||
<i class="fas fa-hdd text-green-500 text-5xl"></i>
|
<i class="fas fa-hdd text-green-500 text-5xl"></i>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<p class="text-gray-700 text-sm">使用储存</p>
|
<p class="text-gray-700 text-sm">使用储存</p>
|
||||||
<p class="text-gray-800 font-semibold text-xl">{{ \App\Utils::formatSize($user->images->sum('size') * 1024) }}</p>
|
<p class="text-gray-800 font-semibold text-xl">{{ \App\Utils::formatSize($user->use_capacity * 1024) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex bg-white rounded p-4 space-x-4">
|
<div class="flex bg-white rounded p-4 space-x-4 shadow-custom">
|
||||||
<i class="fas fa-hdd text-emerald-500 text-5xl"></i>
|
<i class="fas fa-hdd text-emerald-500 text-5xl"></i>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<p class="text-gray-700 text-sm">总储存</p>
|
<p class="text-gray-700 text-sm">总储存</p>
|
||||||
|
|||||||
@@ -116,8 +116,8 @@
|
|||||||
<form class="w-full space-y-2" action="/user/albums">
|
<form class="w-full space-y-2" action="/user/albums">
|
||||||
<input type="text" class="w-full rounded px-2.5 py-1.5 text-sm border-0 bg-gray-200" name="name" placeholder="请输入名称">
|
<input type="text" class="w-full rounded px-2.5 py-1.5 text-sm border-0 bg-gray-200" name="name" placeholder="请输入名称">
|
||||||
<textarea class="w-full resize-y rounded-md text-sm border-0 bg-gray-200" name="intro" placeholder="请输入简介"></textarea>
|
<textarea class="w-full resize-y rounded-md text-sm border-0 bg-gray-200" name="intro" placeholder="请输入简介"></textarea>
|
||||||
|
<button class="w-full py-1 px-2 bg-indigo-500 text-white text-sm text-center tracking-wider font-semibold rounded-md">创建相册</button>
|
||||||
</form>
|
</form>
|
||||||
<a href="javascript:void(0)" class="w-full py-1 px-2 bg-indigo-500 text-white text-sm text-center tracking-wider font-semibold rounded-md">创建相册</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
@@ -139,8 +139,8 @@
|
|||||||
<form class="w-full space-y-2" action="/user/albums/__id__">
|
<form class="w-full space-y-2" action="/user/albums/__id__">
|
||||||
<input type="text" class="w-full rounded px-2.5 py-1.5 text-sm border-0 bg-gray-200" placeholder="请输入名称" name="name" value="__name__">
|
<input type="text" class="w-full rounded px-2.5 py-1.5 text-sm border-0 bg-gray-200" placeholder="请输入名称" name="name" value="__name__">
|
||||||
<textarea class="w-full resize-y rounded-md text-sm border-0 bg-gray-200" name="intro" placeholder="请输入简介">__intro__</textarea>
|
<textarea class="w-full resize-y rounded-md text-sm border-0 bg-gray-200" name="intro" placeholder="请输入简介">__intro__</textarea>
|
||||||
|
<button class="w-full py-1 px-2 bg-indigo-500 text-white text-sm text-center tracking-wider font-semibold rounded-md">确认修改</button>
|
||||||
</form>
|
</form>
|
||||||
<a href="javascript:void(0)" class="w-full py-1 px-2 bg-indigo-500 text-white text-sm text-center tracking-wider font-semibold rounded-md">确认修改</a>
|
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -269,14 +269,14 @@
|
|||||||
for (const i in images) {
|
for (const i in images) {
|
||||||
html += $('#images-item-tpl').html()
|
html += $('#images-item-tpl').html()
|
||||||
.replace(/__id__/g, images[i].id)
|
.replace(/__id__/g, images[i].id)
|
||||||
.replace(/__name__/g, images[i].filename)
|
.replace(/__name__/g, images[i].filename.replace(/\$/g, '$$$$'))
|
||||||
.replace(/__human_date__/g, images[i].human_date)
|
.replace(/__human_date__/g, images[i].human_date)
|
||||||
.replace(/__date__/g, images[i].date)
|
.replace(/__date__/g, images[i].date)
|
||||||
.replace(/__url__/g, images[i].url)
|
.replace(/__url__/g, images[i].url)
|
||||||
.replace(/__thumb_url__/g, images[i].thumb_url)
|
.replace(/__thumb_url__/g, images[i].thumb_url)
|
||||||
.replace(/__width__/g, images[i].width)
|
.replace(/__width__/g, images[i].width)
|
||||||
.replace(/__height__/g, images[i].height)
|
.replace(/__height__/g, images[i].height)
|
||||||
.replace(/__json__/g, JSON.stringify(images[i]))
|
.replace(/__json__/g, JSON.stringify(images[i]).replace(/\$/g, '$$$$'))
|
||||||
}
|
}
|
||||||
|
|
||||||
$photos.append(html);
|
$photos.append(html);
|
||||||
@@ -410,8 +410,9 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// confirm create
|
// confirm create
|
||||||
$albums.off('click', CREATE_ID + ' a').on('click', CREATE_ID + ' a', function (e) {
|
$albums.off('submit', CREATE_ID + ' form').on('submit', CREATE_ID + ' form', function (e) {
|
||||||
let $form = $(this).siblings('form');
|
e.preventDefault();
|
||||||
|
let $form = $(this);
|
||||||
axios.post($form.attr('action'), $form.serialize()).then(response => {
|
axios.post($form.attr('action'), $form.serialize()).then(response => {
|
||||||
let $errorMessage = $albums.find(CREATE_ID + ' .error-message').html('').hide();
|
let $errorMessage = $albums.find(CREATE_ID + ' .error-message').html('').hide();
|
||||||
if (response.data.status) {
|
if (response.data.status) {
|
||||||
@@ -424,8 +425,9 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// confirm update
|
// confirm update
|
||||||
$albums.off('click', UPDATE_ID + ' a').on('click', UPDATE_ID + ' a', function (e) {
|
$albums.off('submit', UPDATE_ID + ' form').on('submit', UPDATE_ID + ' form', function (e) {
|
||||||
let $form = $(this).siblings('form');
|
e.preventDefault();
|
||||||
|
let $form = $(this);
|
||||||
axios.put($form.attr('action'), $form.serialize()).then(response => {
|
axios.put($form.attr('action'), $form.serialize()).then(response => {
|
||||||
let $errorMessage = $albums.find(UPDATE_ID + ' .error-message').html('').hide();
|
let $errorMessage = $albums.find(UPDATE_ID + ' .error-message').html('').hide();
|
||||||
if (response.data.status) {
|
if (response.data.status) {
|
||||||
@@ -672,9 +674,6 @@
|
|||||||
} else {
|
} else {
|
||||||
toastr.warning(response.data.message);
|
toastr.warning(response.data.message);
|
||||||
}
|
}
|
||||||
}).finally(_ => {
|
|
||||||
$photos.addClass('reset').html('').justifiedGallery('destroy');
|
|
||||||
ds.clearSelection();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -686,9 +685,9 @@
|
|||||||
let image = response.data.data.image;
|
let image = response.data.data.image;
|
||||||
let content = $('#image-detail-tpl').html()
|
let content = $('#image-detail-tpl').html()
|
||||||
.replace(/__album_name__/g, image.album ? image.album.name : '-')
|
.replace(/__album_name__/g, image.album ? image.album.name : '-')
|
||||||
.replace(/__strategy_name__/g, image.strategy.name || '-')
|
.replace(/__strategy_name__/g, image.strategy ? image.strategy.name : '-')
|
||||||
.replace(/__filename__/g, image.filename)
|
.replace(/__filename__/g, image.filename.replace(/\$/g, '$$$$'))
|
||||||
.replace(/__origin_name__/g, image.origin_name)
|
.replace(/__origin_name__/g, image.origin_name.replace(/\$/g, '$$$$'))
|
||||||
.replace(/__size__/g, utils.formatSize(image.size * 1024))
|
.replace(/__size__/g, utils.formatSize(image.size * 1024))
|
||||||
.replace(/__mimetype__/g, image.mimetype)
|
.replace(/__mimetype__/g, image.mimetype)
|
||||||
.replace(/__width__/g, image.width)
|
.replace(/__width__/g, image.width)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<p class="mb-3 font-semibold text-lg text-gray-700">基础设置</p>
|
<p class="mb-3 font-semibold text-lg text-gray-700">基础设置</p>
|
||||||
<form action="{{ route('settings.update') }}" method="POST">
|
<form action="{{ route('settings.update') }}" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
<div class="overflow-hidden sm:rounded-md">
|
<div class="overflow-hidden sm:rounded-md shadow-custom">
|
||||||
<div class="px-3 py-4 bg-white sm:p-6">
|
<div class="px-3 py-4 bg-white sm:p-6">
|
||||||
<div class="grid grid-cols-6 gap-6">
|
<div class="grid grid-cols-6 gap-6">
|
||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
@if(Auth::user()->group)
|
@if(Auth::user()->group)
|
||||||
<option value="0">未选择</option>
|
<option value="0">未选择</option>
|
||||||
@foreach(Auth::user()->group->strategies as $strategy)
|
@foreach(Auth::user()->group->strategies as $strategy)
|
||||||
<option value="{{ $strategy->id }}" @selected(Auth::user()->configs->get(\App\Enums\UserConfigKey::DefaultStrategy) == $strategy->id)>{{ $strategy->name }}</option>
|
<option value="{{ $strategy->id }}" @selected(Auth::user()->configs->get('default_strategy') == $strategy->id)>{{ $strategy->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
@else
|
@else
|
||||||
<option value="0">系统默认</option>
|
<option value="0">系统默认</option>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
@if(Auth::user()->albums->isNotEmpty())
|
@if(Auth::user()->albums->isNotEmpty())
|
||||||
<option value="0">未选择</option>
|
<option value="0">未选择</option>
|
||||||
@foreach(Auth::user()->albums as $album)
|
@foreach(Auth::user()->albums as $album)
|
||||||
<option value="{{ $album->id }}" @selected(Auth::user()->configs->get(\App\Enums\UserConfigKey::DefaultAlbum) == $album->id)>{{ $album->name }}</option>
|
<option value="{{ $album->id }}" @selected(Auth::user()->configs->get('default_album') == $album->id)>{{ $album->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
@else
|
@else
|
||||||
<option value="0">没有可用相册</option>
|
<option value="0">没有可用相册</option>
|
||||||
@@ -53,20 +53,27 @@
|
|||||||
|
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<label for="password" class="block text-sm font-medium text-gray-700">密码</label>
|
<label for="password" class="block text-sm font-medium text-gray-700">密码</label>
|
||||||
<x-input type="password" name="password" id="password" placeholder="不修改请留空" autocomplete="password" />
|
<x-input type="password" name="password" id="password" placeholder="不修改请留空" autocomplete="new-password" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<x-fieldset title="是否自动清除预览" faq="设置上传时,文件上传完成以后是否自动清除预览图片">
|
<x-fieldset title="是否自动清除预览" faq="设置上传时,文件上传完成以后是否自动清除预览图片">
|
||||||
<x-fieldset-radio id="is_auto_clear_preview_yes" name="configs[is_auto_clear_preview]" value="1" :checked="Auth::user()->configs->get(\App\Enums\UserConfigKey::IsAutoClearPreview)">是</x-fieldset-radio>
|
<x-fieldset-radio id="is_auto_clear_preview_yes" name="configs[is_auto_clear_preview]" value="1" :checked="Auth::user()->configs->get('is_auto_clear_preview')">是</x-fieldset-radio>
|
||||||
<x-fieldset-radio id="is_auto_clear_preview_no" name="configs[is_auto_clear_preview]" value="0" :checked="! Auth::user()->configs->get(\App\Enums\UserConfigKey::IsAutoClearPreview)">否</x-fieldset-radio>
|
<x-fieldset-radio id="is_auto_clear_preview_no" name="configs[is_auto_clear_preview]" value="0" :checked="! Auth::user()->configs->get('is_auto_clear_preview')">否</x-fieldset-radio>
|
||||||
|
</x-fieldset>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-6">
|
||||||
|
<x-fieldset title="图片粘贴后动作" faq="设置上传页面粘贴图片后的动作">
|
||||||
|
<x-fieldset-radio id="pasted_action_upload" name="configs[pasted_action]" value="{{ \App\Enums\PastedAction::Upload }}" :checked="Auth::user()->configs->get('pasted_action') == \App\Enums\PastedAction::Upload">直接上传</x-fieldset-radio>
|
||||||
|
<x-fieldset-radio id="pasted_action_waiting" name="configs[pasted_action]" value="{{ \App\Enums\PastedAction::Waiting }}" :checked="Auth::user()->configs->get('pasted_action') == \App\Enums\PastedAction::Waiting">等待上传</x-fieldset-radio>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-6">
|
<div class="col-span-6">
|
||||||
<x-fieldset title="图片默认权限" faq="设置上传的图片默认的权限(公开还是私有,公开的图片将会出现在画廊中,你也可以通过图片管理单独设置权限)">
|
<x-fieldset title="图片默认权限" faq="设置上传的图片默认的权限(公开还是私有,公开的图片将会出现在画廊中,你也可以通过图片管理单独设置权限)">
|
||||||
<x-fieldset-radio id="private" name="configs[default_permission]" value="{{ \App\Enums\ImagePermission::Private }}" :checked="Auth::user()->configs->get(\App\Enums\UserConfigKey::DefaultPermission) == \App\Enums\ImagePermission::Private">私有</x-fieldset-radio>
|
<x-fieldset-radio id="default_permission_private" name="configs[default_permission]" value="{{ \App\Enums\ImagePermission::Private }}" :checked="Auth::user()->configs->get('default_permission') == \App\Enums\ImagePermission::Private">私有</x-fieldset-radio>
|
||||||
<x-fieldset-radio id="public" name="configs[default_permission]" value="{{ \App\Enums\ImagePermission::Public }}" :checked="Auth::user()->configs->get(\App\Enums\UserConfigKey::DefaultPermission) == \App\Enums\ImagePermission::Public">公开</x-fieldset-radio>
|
<x-fieldset-radio id="default_permission_public" name="configs[default_permission]" value="{{ \App\Enums\ImagePermission::Public }}" :checked="Auth::user()->configs->get('default_permission') == \App\Enums\ImagePermission::Public">公开</x-fieldset-radio>
|
||||||
</x-fieldset>
|
</x-fieldset>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@push('styles')
|
@push('styles')
|
||||||
<link rel="stylesheet" href="{{ asset('css/markdown-css/github-markdown.css') }}">
|
<link rel="stylesheet" href="{{ asset('css/markdown-css/github-markdown-light.css') }}">
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
<x-guest-layout>
|
<x-guest-layout>
|
||||||
@@ -10,9 +10,8 @@
|
|||||||
<a href="{{ route('/') }}" class="text-white text-xl truncate">{{ \App\Utils::config(\App\Enums\ConfigKey::AppName) }}</a>
|
<a href="{{ route('/') }}" class="text-white text-xl truncate">{{ \App\Utils::config(\App\Enums\ConfigKey::AppName) }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end items-center space-x-4">
|
<div class="flex justify-end items-center space-x-4">
|
||||||
@if($_group->strategies->isNotEmpty())
|
@includeWhen($_is_notice, 'layouts.notice')
|
||||||
@include('layouts.strategies')
|
@includeWhen($_group->strategies->isNotEmpty(), 'layouts.strategies')
|
||||||
@endif
|
|
||||||
|
|
||||||
@if(Auth::check())
|
@if(Auth::check())
|
||||||
@include('layouts.user-nav')
|
@include('layouts.user-nav')
|
||||||
@@ -29,27 +28,12 @@
|
|||||||
<x-upload/>
|
<x-upload/>
|
||||||
</div>
|
</div>
|
||||||
<footer class="absolute bottom-0 left-0 right-0 w-full bg-gray-200">
|
<footer class="absolute bottom-0 left-0 right-0 w-full bg-gray-200">
|
||||||
<p class="container mx-auto py-2 px-5 sm:px-10 md:px-10 lg:px-10 xl:px-10 2xl:px-60 flex items-center text-gray-500 text-sm">
|
<p class="container mx-auto py-2 px-5 sm:px-10 md:px-10 lg:px-10 xl:px-10 2xl:px-60 text-gray-500 text-sm">
|
||||||
Copyright © 2018 - present Lsky Pro. All rights reserved. 请勿上传违反中国大陆和香港法律的图片,违者后果自负。
|
Copyright © 2018 - present Lsky Pro. All rights reserved. <a href="https://beian.miit.gov.cn/" target="_blank" rel="noreferrer">{{ \App\Utils::config(\App\Enums\ConfigKey::IcpNo) }}</a> 请勿上传违反中国大陆和香港法律的图片,违者后果自负。
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if(\App\Utils::config(\App\Enums\ConfigKey::SiteNotice))
|
@include('common.notice')
|
||||||
<x-modal>
|
|
||||||
<div class="markdown-body">
|
|
||||||
{!! (new Parsedown())->parse(\App\Utils::config(\App\Enums\ConfigKey::SiteNotice)) !!}
|
|
||||||
</div>
|
|
||||||
</x-modal>
|
|
||||||
|
|
||||||
@push('scripts')
|
|
||||||
<script>
|
|
||||||
if (! sessionStorage.getItem('noticed')) {
|
|
||||||
Alpine.store('modal').open = true;
|
|
||||||
sessionStorage.setItem('noticed', '1');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@endpush
|
|
||||||
@endif
|
|
||||||
|
|
||||||
</x-guest-layout>
|
</x-guest-layout>
|
||||||
|
|||||||
@@ -8,15 +8,16 @@ use App\Http\Controllers\Auth\NewPasswordController;
|
|||||||
use App\Http\Controllers\Auth\PasswordResetLinkController;
|
use App\Http\Controllers\Auth\PasswordResetLinkController;
|
||||||
use App\Http\Controllers\Auth\RegisteredUserController;
|
use App\Http\Controllers\Auth\RegisteredUserController;
|
||||||
use App\Http\Controllers\Auth\VerifyEmailController;
|
use App\Http\Controllers\Auth\VerifyEmailController;
|
||||||
|
use App\Http\Middleware\CheckIsEnableRegistration;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::get('/register', [
|
Route::get('/register', [
|
||||||
RegisteredUserController::class, 'create'
|
RegisteredUserController::class, 'create'
|
||||||
])->middleware('guest')->name('register');
|
])->middleware('guest')->middleware(CheckIsEnableRegistration::class)->name('register');
|
||||||
|
|
||||||
Route::post('/register', [
|
Route::post('/register', [
|
||||||
RegisteredUserController::class, 'store'
|
RegisteredUserController::class, 'store'
|
||||||
])->middleware('guest');
|
])->middleware('guest')->middleware(CheckIsEnableRegistration::class);
|
||||||
|
|
||||||
Route::get('/login', [
|
Route::get('/login', [
|
||||||
AuthenticatedSessionController::class, 'create',
|
AuthenticatedSessionController::class, 'create',
|
||||||
|
|||||||
@@ -5,13 +5,10 @@ use Illuminate\Support\Facades\Route;
|
|||||||
use App\Enums\GroupConfigKey;
|
use App\Enums\GroupConfigKey;
|
||||||
use App\Enums\ConfigKey;
|
use App\Enums\ConfigKey;
|
||||||
|
|
||||||
$extensions = config('convention.app.'.ConfigKey::Group)[GroupConfigKey::AcceptedFileSuffixes];
|
$extensions = config('convention.group.accepted_file_suffixes');
|
||||||
Route::middleware('cache.headers:public;max_age=2628000;etag')->group(function () use ($extensions) {
|
Route::middleware('cache.headers:public;max_age=2628000;etag')->group(function () use ($extensions) {
|
||||||
$extensions = array_merge(array_map('strtoupper', $extensions), array_map('strtolower', $extensions));
|
$extensions = array_merge(array_map('strtoupper', $extensions), array_map('strtolower', $extensions));
|
||||||
Route::any('{key}.{extension}', [
|
Route::any('{key}.{extension}', [
|
||||||
Controller::class, 'output',
|
Controller::class, 'output',
|
||||||
])->where('extension', implode('|', $extensions));
|
])->where('extension', implode('|', $extensions));
|
||||||
Route::any('{key}.{extension}!thumbnail', [
|
|
||||||
Controller::class, 'thumbnail',
|
|
||||||
])->where('extension', implode('|', $extensions));
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use App\Http\Middleware\CheckIsEnableApi;
|
||||||
|
use App\Http\Middleware\CheckIsEnableGallery;
|
||||||
use App\Http\Middleware\CheckIsEnableGuestUpload;
|
use App\Http\Middleware\CheckIsEnableGuestUpload;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Http\Middleware\CheckIsInstalled;
|
use App\Http\Middleware\CheckIsInstalled;
|
||||||
@@ -37,7 +39,7 @@ Route::any('install', [Controller::class, 'install'])->name('install');
|
|||||||
Route::post('upload', [Controller::class, 'upload']);
|
Route::post('upload', [Controller::class, 'upload']);
|
||||||
Route::group(['middleware' => ['auth']], function () {
|
Route::group(['middleware' => ['auth']], function () {
|
||||||
Route::get('dashboard', [UserController::class, 'dashboard'])->name('dashboard');
|
Route::get('dashboard', [UserController::class, 'dashboard'])->name('dashboard');
|
||||||
Route::get('gallery', [GalleryController::class, 'index'])->name('gallery');
|
Route::get('gallery', [GalleryController::class, 'index'])->middleware(CheckIsEnableGallery::class)->name('gallery');
|
||||||
|
|
||||||
Route::prefix('settings')->group(function () {
|
Route::prefix('settings')->group(function () {
|
||||||
Route::get('', [UserController::class, 'settings'])->name('settings');
|
Route::get('', [UserController::class, 'settings'])->name('settings');
|
||||||
@@ -45,7 +47,10 @@ Route::group(['middleware' => ['auth']], function () {
|
|||||||
Route::put('set-strategy', [UserController::class, 'setStrategy'])->name('settings.strategy.set');
|
Route::put('set-strategy', [UserController::class, 'setStrategy'])->name('settings.strategy.set');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group(['prefix' => 'api'], function () {
|
Route::group([
|
||||||
|
'prefix' => 'api',
|
||||||
|
'middleware' => CheckIsEnableApi::class
|
||||||
|
], function () {
|
||||||
Route::get('', [ApiController::class, 'index'])->name('api');
|
Route::get('', [ApiController::class, 'index'])->name('api');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ module.exports = {
|
|||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: ['Nunito', ...defaultTheme.fontFamily.sans],
|
sans: ['Nunito', ...defaultTheme.fontFamily.sans],
|
||||||
},
|
},
|
||||||
|
boxShadow: {
|
||||||
|
custom: '0px 4px 6px -1px rgba(0, 0, 0, 0.04)',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user