From ea6c9ce9cda81902ae6a3133a2fe36104e59070c Mon Sep 17 00:00:00 2001
From: liangjiami <2249412933@qq.com>
Date: Fri, 25 Jul 2025 13:47:37 +0800
Subject: [PATCH 1/9] =?UTF-8?q?=E6=96=87=E7=AB=A0=E8=AF=A6=E6=83=85?=
=?UTF-8?q?=E6=A0=B7=E5=BC=8F=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/index/view/pc/article/detail.html | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/app/index/view/pc/article/detail.html b/app/index/view/pc/article/detail.html
index 1be36565..d4809b85 100644
--- a/app/index/view/pc/article/detail.html
+++ b/app/index/view/pc/article/detail.html
@@ -24,7 +24,9 @@
{$detail.release_time|date_format_i18n}
- {$detail.content|raw}
+
+
{$detail.content|raw}
+
{notempty name="comments"}
From 49e5a9b8c7cb2e50c2832e0ae27b27a6e798ec1a Mon Sep 17 00:00:00 2001
From: jsasg <735273025@qq.com>
Date: Thu, 24 Jul 2025 18:03:41 +0800
Subject: [PATCH 2/9] =?UTF-8?q?refactor:=20=E4=B8=83=E7=89=9B=E4=BA=91?=
=?UTF-8?q?=E4=B8=8A=E4=BC=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.example.env | 7 +
app/admin/controller/v1/Upload.php | 61 ++++-
app/common.php | 46 ++++
app/index/controller/Attachment.php | 15 +-
composer.json | 2 +-
config/filesystem.php | 54 ++++
extend/filesystem/adapter/QiniuAdapter.php | 295 +++++++++++++++++++++
extend/filesystem/driver/Qiniu.php | 56 ++++
extend/uploader/Qiniu.php | 157 -----------
9 files changed, 519 insertions(+), 174 deletions(-)
create mode 100644 extend/filesystem/adapter/QiniuAdapter.php
create mode 100644 extend/filesystem/driver/Qiniu.php
delete mode 100644 extend/uploader/Qiniu.php
diff --git a/.example.env b/.example.env
index 898b7ea9..aba84550 100644
--- a/.example.env
+++ b/.example.env
@@ -47,6 +47,13 @@ REFRESH_TOKEN_LIFETIME = 1209600; # 刷新令牌有效期
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
+# 七牛云存储配置
+[QINUI]
+BUCKET = orico
+BASE_URL = http://local.orico.com
+ACCESS_KEY = 1234567890
+SECRET_KEY = 1234567890
+
# 前台视图模板规则配置
[INDEX_VIEW_TPL]
# 视图目录
diff --git a/app/admin/controller/v1/Upload.php b/app/admin/controller/v1/Upload.php
index 231337f5..52c0f079 100644
--- a/app/admin/controller/v1/Upload.php
+++ b/app/admin/controller/v1/Upload.php
@@ -9,6 +9,7 @@ use app\admin\model\v1\SysAttachmentUploadRecordModel;
use Intervention\Image\ImageManager;
use Intervention\Image\Typography\FontFactory;
use think\facade\Filesystem;
+use filesystem\Qiniu;
/**
* 文件上传控制器
@@ -153,8 +154,8 @@ class Upload
$image_model = new SysImageUploadRecordModel();
$image_model->language_id = request()->lang_id;
$image_model->module = $param['module'];
- $image_model->image_path = $filename;
- $image_model->image_thumb = $thumb_filename;
+ $image_model->image_path = $storage . '/' . $filename;
+ $image_model->image_thumb = $storage . '/' . $thumb_filename;
$image_model->file_size = $file_size;
$image_model->file_type = $mime_type;
$image_model->file_md5 = $filemd5;
@@ -165,8 +166,8 @@ class Upload
}
return success('操作成功', [
- 'path' => $storage . '/' . $image_model->image_path,
- 'thumb_path' => $storage . '/' . $image_model->image_thumb,
+ 'path' => $image_model->image_path,
+ 'thumb_path' => $image_model->image_thumb,
'filemd5' => $image_model->file_md5,
'filesha1' => $image_model->file_sha1
]);
@@ -226,6 +227,7 @@ class Upload
'filename_keep' => (int)data_get($options, 'filename_keep.value', 0) == 1,
'filemd5_unique' => (int)data_get($options, 'filemd5_unique.value', 0) == 1,
'filetype_to' => data_get($options, 'filetype_to.value', 'original'),
+ 'save_to' => data_get($options, 'save_to.value', 'local'),
];
}
/**
@@ -345,20 +347,35 @@ class Upload
// 获取视频上传配置
list(
'filename_keep' => $filename_keep,
- 'filemd5_unique' => $filemd5_unique
+ 'filemd5_unique' => $filemd5_unique,
+ 'save_to' => $save_to,
) = $this->getUploadOptions('upload_video');
// 是否需要根据文件MD5值检查文件是否已存在
$video = $filemd5_unique ? SysVideoUploadRecordModel::md5($filemd5)->find() : null;
if (is_null($video)) {
+ // 保存位置配置 key
+ $disk = 'video';
// 检查是否需要保留原文件名
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
- $filename = Filesystem::disk('video')->putFile($param['module'], $file, $name_rule());
+
+ // 保存到七牛云
+ if ($save_to == 'qiniu_cloud') {
+ $disk = 'video_qiniu';
+ $storage = config('filesystem.disks.video_qiniu.path_prefix');
+ }
+ $filename = Filesystem::disk($disk)->putFile($param['module'], $file, $name_rule());
+
+ // 组装视频路径
+ $video_path = $storage . '/' . $filename;
+ if ($save_to == 'qiniu_cloud') {
+ $video_path = Filesystem::disk($disk)->url($filename);
+ }
// 保存视频
$video = new SysVideoUploadRecordModel();
$video->language_id = request()->lang_id;
$video->module = $param['module'];
- $video->video_path = $filename;
+ $video->video_path = $video_path;
$video->file_size = $file->getSize();
$video->file_type = $file->getOriginalMime();
$video->file_md5 = $filemd5;
@@ -369,7 +386,7 @@ class Upload
}
return success('上传成功', [
- 'path' => $storage . '/' . $video->video_path,
+ 'path' => $video->video_path,
'file_md5' => $video->file_md5,
'file_sha1' => $video->file_sha1
]);
@@ -399,25 +416,42 @@ class Upload
return error($validate->getError());
}
+ $storage = config('filesystem.disks.public.url');
+
$filemd5 = $file->md5();
$filesha1 = $file->sha1();
// 获取附件上传配置
list(
'filename_keep' => $filename_keep,
- 'filemd5_unique' => $filemd5_unique
+ 'filemd5_unique' => $filemd5_unique,
+ 'save_to' => $save_to
) = $this->getUploadOptions('upload_attachment');
// 是否需要根据文件MD5值检查文件是否已存在
$attachment = $filemd5_unique ? SysAttachmentUploadRecordModel::md5($filemd5)->find() : null;
if (is_null($attachment)) {
+ // 保存位置配置 key
+ $disk = 'public';
// 检查是否需要保留原文件名
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
- $filename = Filesystem::disk('public')->putFile('attachments', $file, $name_rule());
- // 保存视频
+ // 保存到七牛云
+ if ($save_to == 'qiniu_cloud') {
+ $disk = 'public_qiniu';
+ $storage = config('filesystem.disks.public_qiniu.path_prefix');
+ }
+ $filename = Filesystem::disk($disk)->putFile('attachments', $file, $name_rule());
+
+ // 组装附件路径
+ $attachment_path = $storage . '/' . $filename;
+ if ($save_to == 'qiniu_cloud') {
+ $attachment_path = Filesystem::disk($disk)->url($filename);
+ }
+
+ // 保存附件
$attachment = new SysAttachmentUploadRecordModel();
$attachment->language_id = request()->lang_id;
- $attachment->attachment_path = $filename;
+ $attachment->attachment_path = $attachment_path;
$attachment->file_size = $file->getSize();
$attachment->file_type = $file->getOriginalMime();
$attachment->file_md5 = $filemd5;
@@ -427,9 +461,8 @@ class Upload
}
}
- $storage = config('filesystem.disks.public.url');
return success('上传成功', [
- 'path' => $storage . '/' . $attachment->attachment_path,
+ 'path' => $attachment->attachment_path,
'file_md5' => $attachment->file_md5,
'file_sha1' => $attachment->file_sha1
]);
diff --git a/app/common.php b/app/common.php
index 1fa13ee4..8418474f 100644
--- a/app/common.php
+++ b/app/common.php
@@ -144,4 +144,50 @@ if (!function_exists('thumb')) {
return mb_substr($url, 0, $idx, 'utf-8') . '_thumb' . mb_substr($url, $idx, $len - $idx, 'utf-8');
}
+}
+
+if (!function_exists('get_filesystem_url')) {
+ /**
+ * 获取文件系统的访问 URL
+ * @param string $url 文件地址
+ * @param string $disk 磁盘配置 key
+ * @return string
+ */
+ function get_filesystem_url(string $url, string $disk): string
+ {
+ if (\think\helper\Str::startsWith($url, ['http://', 'https://'])) {
+ return $url;
+ }
+ if (empty($disk)) {
+ return '';
+ }
+ return \think\facade\Filesystem::disk($disk)->url($url);
+ }
+}
+
+if (!function_exists('url_filesystem_detect')) {
+ /**
+ * 检测文件地址并根据情况转换为文件系统地址
+ * @param string $url 文件地址
+ * @return string
+ */
+ function url_filesystem_detect(string $url): string
+ {
+ $idx = strrpos($url, '.');
+ if ($idx === false) {
+ return $url;
+ }
+
+ $disks = [
+ 'public_qiniu' => '_' . base64_encode('public_qiniu'),
+ 'video_qiniu' => '_' . base64_encode('video_qiniu')
+ ];
+ foreach ($disks as $disk => $marker) {
+ if (str_ends_with(mb_substr($url, 0, $idx), $marker)) {
+ return get_filesystem_url($url, $disk);
+ }
+ }
+
+ return $url;
+ }
}
\ No newline at end of file
diff --git a/app/index/controller/Attachment.php b/app/index/controller/Attachment.php
index fc267249..02a7ae5f 100644
--- a/app/index/controller/Attachment.php
+++ b/app/index/controller/Attachment.php
@@ -26,8 +26,6 @@ class Attachment extends Common
'size/d' => 12,
]);
-
-
// 获取附件分类
$categorys = AttachmentCategoryModel::field([
'id',
@@ -61,6 +59,16 @@ class Attachment extends Common
'id' => $param['id']??null
]
]);
+ if (!$attachements->isEmpty()) {
+ $attachements->each(function($item) {
+ if (is_array($item->attach)) {
+ $item->attach = array_map(function($v) {
+ $v['file_path'] = url_filesystem_detect($v['file_path']);
+ return $v;
+ }, $item->attach);
+ }
+ });
+ }
View::assign('attachements', $attachements);
View::assign('page', $attachements->render());
@@ -124,6 +132,9 @@ class Attachment extends Common
]);
if (!$videos->isEmpty()) {
+ $videos->each(function($item) {
+ $item->video = url_filesystem_detect($item->video);
+ });
$videos->setCollection($videos->getCollection()->chunk(2));
}
View::assign('videos', $videos);
diff --git a/composer.json b/composer.json
index f1bc0ce0..2fc3329d 100644
--- a/composer.json
+++ b/composer.json
@@ -23,7 +23,7 @@
"php": ">=8.0.0",
"topthink/framework": "^8.0",
"topthink/think-orm": "v3.0.34",
- "topthink/think-filesystem": "^2.0",
+ "topthink/think-filesystem": "^3.0",
"topthink/think-multi-app": "^1.1",
"topthink/think-migration": "^3.1",
"topthink/think-view": "^2.0",
diff --git a/config/filesystem.php b/config/filesystem.php
index 67e5f44a..8f2708c3 100644
--- a/config/filesystem.php
+++ b/config/filesystem.php
@@ -39,6 +39,60 @@ return [
// 可见性
'visibility' => 'public',
],
+ 'public_qiniu' => [
+ // 磁盘类型
+ 'type' => \filesystem\driver\Qiniu::class,
+ // bucker 名称
+ 'bucket' => 'orico-official-website',
+ // 访问密钥
+ 'access_key' => 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms',
+ // 密钥
+ 'secret_key' => 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q',
+ // 外部URL
+ 'base_url' => '//szw73dlk3.hn-bkt.clouddn.com',
+ // 路径
+ 'path_prefix' => '/storage',
+ // 文件名称回调,可为文件名添加特定标志,以便可以在后续识别
+ 'filename_generator' => function (\think\file\UploadedFile $file, callable $context_generator = null): callable {
+ return function() use ($file, $context_generator) {
+ // 为文件名称添加配置名,以为后续可能根据文件名识别文件所属存储配置信息
+ $marker = '_' . base64_encode('public_qiniu');
+ $filename = $context_generator ? $context_generator($file) : null;
+ if ($filename == null) {
+ return date('Ymd') . '/' . md5(microtime(true) . $file->getPathname()) . $marker;
+ }
+
+ return $filename . $marker;
+ };
+ },
+ ],
+ 'video_qiniu' => [
+ // 磁盘类型
+ 'type' => \filesystem\driver\Qiniu::class,
+ // bucker 名称
+ 'bucket' => 'orico-official-website',
+ // 访问密钥
+ 'access_key' => 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms',
+ // 密钥
+ 'secret_key' => 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q',
+ // 外部URL
+ 'base_url' => '//szw73dlk3.hn-bkt.clouddn.com',
+ // 路径
+ 'path_prefix' => '/storage/videos',
+ // 文件名称回调,可为文件名添加特定标志,以便可以在后续识别
+ 'filename_generator' => function (\think\file\UploadedFile $file, callable $context_generator = null): callable {
+ return function() use ($file, $context_generator) {
+ // 为文件名称添加配置名,以为后续可能根据文件名识别文件所属存储配置信息
+ $marker = '_' . base64_encode('video_qiniu');
+ $filename = $context_generator ? $context_generator() : null;
+ if ($filename == null) {
+ return date('Ymd') . '/' . md5(microtime(true) . $file->getPathname()) . $marker;
+ }
+
+ return $filename . $marker;
+ };
+ },
+ ]
// 更多的磁盘配置信息
],
];
diff --git a/extend/filesystem/adapter/QiniuAdapter.php b/extend/filesystem/adapter/QiniuAdapter.php
new file mode 100644
index 00000000..271cd9b5
--- /dev/null
+++ b/extend/filesystem/adapter/QiniuAdapter.php
@@ -0,0 +1,295 @@
+authMgr ?? new Auth($this->access_key, $this->secret_key);
+ }
+
+ private function getUploadMgr(): UploadManager
+ {
+ return $this->uploadMgr ?? new UploadManager();
+ }
+
+ private function getBucketMgr(): BucketManager
+ {
+ return $this->bucketMgr ?? new BucketManager($this->authMgr);
+ }
+
+ private function getPathPrefix(): string
+ {
+ $path = ltrim($this->path, '\\/');
+ if ($path !== '' && !str_ends_with($path, '/')) {
+ $path = $path . '/';
+ }
+
+ return $path;
+ }
+
+ private function applyPathPrefix(string $path): string
+ {
+ $path = ltrim($path, '\\/');
+ return $this->getPathPrefix() . $path;
+ }
+
+ private static function parseUrl($url): array
+ {
+ $result = [];
+
+ // Build arrays of values we need to decode before parsing
+ $entities = [
+ '%21',
+ '%2A',
+ '%27',
+ '%28',
+ '%29',
+ '%3B',
+ '%3A',
+ '%40',
+ '%26',
+ '%3D',
+ '%24',
+ '%2C',
+ '%2F',
+ '%3F',
+ '%23',
+ '%5B',
+ '%5D',
+ '%5C'
+ ];
+ $replacements = ['!', '*', "'", '(', ')', ';', ':', '@', '&', '=', '$', ',', '/', '?', '#', '[', ']', '/'];
+
+ // Create encoded URL with special URL characters decoded so it can be parsed
+ // All other characters will be encoded
+ $encodedURL = str_replace($entities, $replacements, urlencode($url));
+
+ // Parse the encoded URL
+ $encodedParts = parse_url($encodedURL);
+
+ // Now, decode each value of the resulting array
+ if ($encodedParts) {
+ foreach ($encodedParts as $key => $value) {
+ $result[$key] = urldecode(str_replace($replacements, $entities, $value));
+ }
+ }
+
+ return $result;
+ }
+
+ private function normalizeHost($domain): string
+ {
+ if (0 !== stripos($domain, 'https://') && 0 !== stripos($domain, 'http://')) {
+ $domain = "http://{$domain}";
+ }
+
+ return rtrim($domain, '/') . '/';
+ }
+
+ private function getUrl(string $path): string
+ {
+ $segments = $this->parseUrl($path);
+ $query = empty($segments['query']) ? '' : '?' . $segments['query'];
+
+ return $this->normalizeHost($this->base_url) . ltrim(implode('/', array_map('rawurlencode', explode('/', $segments['path']))), '/') . $query;
+ }
+
+ private function privateDownloadUrl(string $path, int $expires = 3600): string
+ {
+ return $this->getAuthMgr()->privateDownloadUrl($this->getUrl($path), $expires);
+ }
+
+ private function getMetadata($path): FileAttributes|array
+ {
+ $result = $this->getBucketMgr()->stat($this->bucket, $path);
+ $result[0]['key'] = $path;
+
+ return $this->normalizeFileInfo($result[0]);
+ }
+
+ private function normalizeFileInfo(array $stats): FileAttributes
+ {
+ return new FileAttributes(
+ $stats['key'],
+ $stats['fsize'] ?? null,
+ null,
+ isset($stats['putTime']) ? floor($stats['putTime'] / 10000000) : null,
+ $stats['mimeType'] ?? null
+ );
+ }
+
+ public function fileExists(string $path): bool
+ {
+ [, $error] = $this->getBucketMgr()->stat($this->bucket, $this->applyPathPrefix($path));
+ return is_null($error);
+ }
+
+ public function directoryExists(string $path): bool
+ {
+ return $this->fileExists($path);
+ }
+
+ public function write(string $path, string $contents, Config $config): void
+ {
+ $mime = $config->get('mime', 'application/octet-stream');
+
+ /**
+ * @var Error|null $error
+ */
+ [, $error] = $this->getUploadMgr()->put(
+ $this->getAuthMgr()->uploadToken($this->bucket),
+ $this->applyPathPrefix($path),
+ $contents,
+ null,
+ $mime,
+ $path
+ );
+
+ if ($error) {
+ throw UnableToWriteFile::atLocation($path, $error->message());
+ }
+ }
+
+ public function writeStream(string $path, $resource, Config $config): void
+ {
+ $data = '';
+
+ while (!feof($resource)) {
+ $data .= fread($resource, 1024);
+ }
+
+ $this->write($path, $data, $config);
+ }
+
+ public function read(string $path): string
+ {
+ try {
+ $result = file_get_contents($this->privateDownloadUrl($path));
+ } catch (\Exception $th) {
+ throw UnableToReadFile::fromLocation($path);
+ }
+
+ if (false === $result) {
+ throw UnableToReadFile::fromLocation($path);
+ }
+
+ return $result;
+ }
+
+ public function readStream(string $path)
+ {
+ if (ini_get('allow_url_fopen')) {
+ if ($result = fopen($this->privateDownloadUrl($path), 'r')) {
+ return $result;
+ }
+ }
+
+ throw UnableToReadFile::fromLocation($path);
+ }
+
+ public function delete(string $path): void
+ {
+ [, $error] = $this->getBucketMgr()->delete($this->bucket, $this->applyPathPrefix($path));
+ if (!is_null($error)) {
+ throw UnableToDeleteFile::atLocation($path);
+ }
+ }
+
+ public function deleteDirectory(string $path): void
+ {
+ $this->delete($path);
+ }
+
+ public function createDirectory(string $path, Config $config): void
+ {
+ }
+
+ public function setVisibility(string $path, string $visibility): void
+ {
+ throw UnableToSetVisibility::atLocation($path);
+ }
+
+ public function visibility(string $path): FileAttributes
+ {
+ throw UnableToRetrieveMetadata::visibility($path);
+ }
+
+ public function mimeType(string $path): FileAttributes
+ {
+ $meta = $this->getMetadata($path);
+
+ if ($meta->mimeType() === null) {
+ throw UnableToRetrieveMetadata::mimeType($path);
+ }
+
+ return $meta;
+ }
+
+ public function lastModified(string $path): FileAttributes
+ {
+ $meta = $this->getMetadata($path);
+
+ if ($meta->lastModified() === null) {
+ throw UnableToRetrieveMetadata::lastModified($path);
+ }
+ return $meta;
+ }
+
+ public function fileSize(string $path): FileAttributes
+ {
+ $meta = $this->getMetadata($path);
+
+ if ($meta->fileSize() === null) {
+ throw UnableToRetrieveMetadata::fileSize($path);
+ }
+ return $meta;
+ }
+
+ public function listContents(string $path, bool $deep): iterable
+ {
+ $result = $this->getBucketMgr()->listFiles($this->bucket, $path);
+
+ foreach ($result[0]['items'] ?? [] as $files) {
+ yield $this->normalizeFileInfo($files);
+ }
+ }
+
+ public function move(string $source, string $destination, Config $config): void
+ {
+ [, $error] = $this->getBucketMgr()->rename($this->bucket, $source, $destination);
+ if (!is_null($error)) {
+ throw UnableToMoveFile::fromLocationTo($source, $destination);
+ }
+ }
+
+ public function copy(string $source, string $destination, Config $config): void
+ {
+ [, $error] = $this->getBucketMgr()->copy($this->bucket, $source, $this->bucket, $destination);
+ if (!is_null($error)) {
+ throw UnableToCopyFile::fromLocationTo($source, $destination);
+ }
+ }
+}
\ No newline at end of file
diff --git a/extend/filesystem/driver/Qiniu.php b/extend/filesystem/driver/Qiniu.php
new file mode 100644
index 00000000..4ee44770
--- /dev/null
+++ b/extend/filesystem/driver/Qiniu.php
@@ -0,0 +1,56 @@
+config['access_key'],
+ $this->config['secret_key'],
+ $this->config['bucket'],
+ $this->config['base_url'],
+ $this->config['path_prefix']
+ );
+ }
+
+ /**
+ * 保存文件
+ * @param string $path 路径
+ * @param \think\File $file 文件
+ * @param null|string|\Closure $rule 文件名规则
+ * @param array $options 参数
+ * @return bool|string
+ */
+ public function putFile(string $path, \think\File $file, $rule = null, array $options = [])
+ {
+ if (!empty($this->config['filename_generator']) && $this->config['filename_generator'] instanceof Closure) {
+ $rule = $this->config['filename_generator']($file, $rule);
+ }
+
+ return $this->putFileAs($path, $file, $file->hashName($rule), $options);
+ }
+
+ public function url(string $path): string
+ {
+ if (str_starts_with($path, 'http://') || str_starts_with($path, 'https://')) {
+ return $path;
+ }
+ if (!str_starts_with($path, $this->config['path_prefix'])) {
+ $path = $this->config['path_prefix'] . '/' . $path;
+ }
+ return $this->concatPathToUrl($this->config['base_url'], $path);
+ }
+
+ public function path(string $path): string
+ {
+ if (!str_starts_with($path, $this->config['path_prefix'])) {
+ $path = $this->config['path_prefix'] . '/' . $path;
+ }
+ return $path;
+ }
+}
diff --git a/extend/uploader/Qiniu.php b/extend/uploader/Qiniu.php
deleted file mode 100644
index 54551cb3..00000000
--- a/extend/uploader/Qiniu.php
+++ /dev/null
@@ -1,157 +0,0 @@
- 1024 * 1024 * 5, // 默认最大上传5M
- 'fileExt' => 'jpeg,jpg,png', // 默认上传文件后缀
- 'fileMime' => 'image/jpeg,image/png,image/gif' // 默认上传文件mime
- ];
-
- private $dir = true;
- private $originalName = false;
- private $pathPrefix = '';
- private $fileNamePrefix = 'orico';
-
- static public $domain = 'http://opdfile.f2b211.com/';
-
- public function __construct($conf = [])
- {
- if (!empty($conf['bucket'])) {
- $this->bucket = $conf['bucket'];
- }
- if (!empty($conf['accessKey'])) {
- $this->accessKey = $conf['accessKey'];
- }
- if (!empty($conf['secretKey'])) {
- $this->secretKey = $conf['secretKey'];
- }
- if (!empty($conf['pathPrefix'])) {
- $this->pathPrefix = trim($conf['pathPrefix'], '/');
- }
- }
-
- /**
- * 生成随机字符串
- */
- private function random($length, $type = "string", $convert = "0")
- {
- $conf = [
- 'number' => '0123456789',
- 'string' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
- 'all' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789='
- ];
- $string = $conf[$type];
- if (!$string) {
- $string = $conf['string'];
- }
- $strlen = strlen($string) - 1;
- $char = '';
- for ($i = 0; $i < $length; $i++) {
- $char .= $string[mt_rand(0, $strlen)];
- }
- if ($convert > 0) {
- $res = strtoupper($char);
- } elseif ($convert == 0) {
- $res = $char;
- } elseif ($convert < 0) {
- $res = strtolower($char);
- }
- return $res;
- }
-
- /**
- * 组装文件名
- */
- private function buildFileName()
- {
- return $this->fileNamePrefix . time() . substr(time(), -5) . substr(microtime(), 2, 3) . $this->random(8);
- }
-
- /**
- * 上传验证规则
- */
- public function validate($rule)
- {
- $this->rule = $rule;
- }
-
- /**
- * 上传文件到七牛云
- */
- public function uploadFile($name)
- {
- // 构建鉴权对象
- $auth = new Auth($this->accessKey, $this->secretKey);
-
- // 生成上传 Token
- $token = $auth->uploadToken($this->bucket);
-
- // 初始化 UploadManager 对象并进行文件的上传。
- $uploadMgr = new UploadManager();
-
- $file = request()->file($name);
-
- $aspectRatio = [];
- if (!empty($this->rule['aspectRatio'])) {
- $aspectRatio = $this->rule['aspectRatio'];
- unset($this->rule['aspectRatio']);
- }
- $validate = validate([$name => $this->rule]);
- if (!$validate->check([$name => $file])) {
- throw new \Exception($validate->getError());
- }
-
- $fileName = $file->getOriginalName(); // 文件原名
- if (!$this->originalName) {
- $fileName = $this->buildFileName() . '.' . $file->extension();
- if (!$this->dir && !empty($this->pathPrefix)) {
- $fileName = $this->pathPrefix . '/' . $fileName;
- }
- }
- if ($this->dir) {
- $fileName = date('Y') . '/' . date('m') . '/' . date('d') . '/' . $fileName;
- if (!empty($this->pathPrefix)) {
- $fileName = $this->pathPrefix . '/' . $fileName;
- }
- }
- $filePath = $file->getPathname(); // 临时路径
- if (!empty($aspectRatio)) { // 验证图片宽高
- list($width, $height, $type, $attr) = getimagesize($file);
- if ($width != $aspectRatio['width'] || $height != $aspectRatio['height']) {
- throw new \Exception('图片宽高不符合');
- }
- }
- $fileType = $file->getOriginalMime();
- list($ret, $err) = $uploadMgr->putFile($token, $fileName, $filePath, null, $fileType, false);
-
- if ($err !== null) {
- throw new \Exception($err);
- } else {
- return ['hash' => $ret['hash'], 'filename' => $ret['key'], 'remote_url' => self::$domain . $ret['key']];
- }
- }
-
-
- /**
- * 上传文件到七牛云
- */
- public function deleteFile($name)
- {
- // 构建鉴权对象
- $auth = new Auth($this->accessKey, $this->secretKey);
- // 初始化 BucketManager 对象并进行文件的删除。
- $bucketManager = new BucketManager($auth);
- $ret = $bucketManager->delete($this->bucket, $name);
- return $ret;
- }
-}
From 77d61919df2026a83e4f79084b8b9a5ce0bdec79 Mon Sep 17 00:00:00 2001
From: jsasg <735273025@qq.com>
Date: Fri, 25 Jul 2025 18:00:14 +0800
Subject: [PATCH 3/9] refactor: .gitignore
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore
index 8a6bec25..9c1c0de2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,8 @@ Thumbs.db
.env.local
.env.prod
+public/dist
+public/opendoc
/.idea
/.vscode
/vendor
From 546b4f3f990eddeb581c459175b7a737b5e1600f Mon Sep 17 00:00:00 2001
From: jsasg <735273025@qq.com>
Date: Mon, 28 Jul 2025 10:16:03 +0800
Subject: [PATCH 4/9] =?UTF-8?q?perf:=20=E4=B8=83=E7=89=9B=E4=BA=91?=
=?UTF-8?q?=E5=AD=98=E5=82=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.example.env | 7 +++++++
app/common.php | 4 ++--
config/filesystem.php | 16 ++++++++--------
3 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/.example.env b/.example.env
index aba84550..20e71346 100644
--- a/.example.env
+++ b/.example.env
@@ -26,6 +26,13 @@ TTL=3600
REFRESH_TTL=20160
SECRET=b43e6276644ed60e65c50d1b324ba10b
+# 七牛云存储配置
+[QINIU_CLOUD]
+BUCKET = orico-official-website
+BASE_URL = //ow.static.f2b211.com
+ACCESS_KEY = dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms
+SECRET_KEY = KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q
+
# 后台不需要登录的接口
[ADMIN_AUTH]
WHITE_LIST[] = v1/user/login
diff --git a/app/common.php b/app/common.php
index 8418474f..8ba851ef 100644
--- a/app/common.php
+++ b/app/common.php
@@ -179,8 +179,8 @@ if (!function_exists('url_filesystem_detect')) {
}
$disks = [
- 'public_qiniu' => '_' . base64_encode('public_qiniu'),
- 'video_qiniu' => '_' . base64_encode('video_qiniu')
+ 'public_qiniu' => '_' . base64_encode('public_qiniu'),
+ 'video_qiniu' => '_' . base64_encode('video_qiniu')
];
foreach ($disks as $disk => $marker) {
if (str_ends_with(mb_substr($url, 0, $idx), $marker)) {
diff --git a/config/filesystem.php b/config/filesystem.php
index 8f2708c3..98eb901c 100644
--- a/config/filesystem.php
+++ b/config/filesystem.php
@@ -43,13 +43,13 @@ return [
// 磁盘类型
'type' => \filesystem\driver\Qiniu::class,
// bucker 名称
- 'bucket' => 'orico-official-website',
+ 'bucket' => env('QINIU_CLOUD.BUCKET', 'orico-official-website'),
// 访问密钥
- 'access_key' => 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms',
+ 'access_key' => env('QINIU_CLOUD.ACCESS_KEY', 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms'),
// 密钥
- 'secret_key' => 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q',
+ 'secret_key' => env('QINIU_CLOUD.SECRET_KEY', 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q'),
// 外部URL
- 'base_url' => '//szw73dlk3.hn-bkt.clouddn.com',
+ 'base_url' => env('QINIU_CLOUD.BASE_URL', '//szw73dlk3.hn-bkt.clouddn.com'),
// 路径
'path_prefix' => '/storage',
// 文件名称回调,可为文件名添加特定标志,以便可以在后续识别
@@ -70,13 +70,13 @@ return [
// 磁盘类型
'type' => \filesystem\driver\Qiniu::class,
// bucker 名称
- 'bucket' => 'orico-official-website',
+ 'bucket' => env('QINIU_CLOUD.BUCKET', 'orico-official-website'),
// 访问密钥
- 'access_key' => 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms',
+ 'access_key' => env('QINIU_CLOUD.ACCESS_KEY', 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms'),
// 密钥
- 'secret_key' => 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q',
+ 'secret_key' => env('QINIU_CLOUD.SECRET_KEY', 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q'),
// 外部URL
- 'base_url' => '//szw73dlk3.hn-bkt.clouddn.com',
+ 'base_url' => env('QINIU_CLOUD.BASE_URL', '//szw73dlk3.hn-bkt.clouddn.com'),
// 路径
'path_prefix' => '/storage/videos',
// 文件名称回调,可为文件名添加特定标志,以便可以在后续识别
From b2dbffc9d137d4ab8def6dcf46ad9d02e255a219 Mon Sep 17 00:00:00 2001
From: jsasg <735273025@qq.com>
Date: Mon, 28 Jul 2025 10:33:44 +0800
Subject: [PATCH 5/9] perf: migrations/seeds
---
database/seeds/SysConfigInit.php | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/database/seeds/SysConfigInit.php b/database/seeds/SysConfigInit.php
index cccdb2ec..90f9f79c 100644
--- a/database/seeds/SysConfigInit.php
+++ b/database/seeds/SysConfigInit.php
@@ -119,6 +119,10 @@ class SysConfigInit extends Seeder
["id" => 102, "group_id" => 13, "title" => "视频 - 唯一性保持", "name" => "upload_video.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 5, "remark" => "如果保持视频文件唯一,重复视频上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:24:24", "updated_at" => "2025-06-12 11:25:18", "deleted_at" => NULL],
["id" => 103, "group_id" => 13, "title" => "附件 - 保留原文件名", "name" => "upload_attachment.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 6, "remark" => "默认为否", "created_at" => "2025-06-12 11:27:08", "updated_at" => "2025-06-12 11:27:08", "deleted_at" => NULL],
["id" => 104, "group_id" => 13, "title" => "附件 - 唯一性保持", "name" => "upload_attachment.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 7, "remark" => "如果保持附件文件唯一,重复附件上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:28:22", "updated_at" => "2025-06-12 11:28:22", "deleted_at" => NULL],
+ ['id' => 105, 'group_id' => 13, 'title' => '视频 - 保存到', 'name' => 'upload_video.save_to', 'value' => 'qiniu_cloud', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 6, 'remark' => '视频保存位置,默认为“本地” - [本地为本站点服务器;七牛去为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:46:24', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
+ ['id' => 106, 'group_id' => 13, 'title' => '附件 - 保存到', 'name' => 'upload_attachment.save_to', 'value' => 'local', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 9, 'remark' => '附件保存位置,默认为“本地” - [本地为本站点服务器;七牛去为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:51:34', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
+ ['id' => 107, 'group_id' => 14, 'title' => '视频 - 保存到', 'name' => 'upload_video.save_to', 'value' => 'qiniu_cloud', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 6, 'remark' => '视频保存位置,默认为“本地” - [本地为本站点服务器;七牛去为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:46:24', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
+ ['id' => 108, 'group_id' => 14, 'title' => '附件 - 保存到', 'name' => 'upload_attachment.save_to', 'value' => 'local', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 9, 'remark' => '附件保存位置,默认为“本地” - [本地为本站点服务器;七牛去为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:51:34', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
];
$table = $this->table('sys_config');
From 9b55bce1bb2bdf49d0880895b36049fc815eb4d8 Mon Sep 17 00:00:00 2001
From: jsasg <735273025@qq.com>
Date: Mon, 28 Jul 2025 11:13:56 +0800
Subject: [PATCH 6/9] chore: composer.json
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 2fc3329d..30b0b868 100644
--- a/composer.json
+++ b/composer.json
@@ -21,7 +21,7 @@
],
"require": {
"php": ">=8.0.0",
- "topthink/framework": "^8.0",
+ "topthink/framework": "8.1.2",
"topthink/think-orm": "v3.0.34",
"topthink/think-filesystem": "^3.0",
"topthink/think-multi-app": "^1.1",
From db9d8568dad81c89ccdb51d9b7a3ced5e790f182 Mon Sep 17 00:00:00 2001
From: liangjiami <2249412933@qq.com>
Date: Mon, 28 Jul 2025 14:25:01 +0800
Subject: [PATCH 7/9] =?UTF-8?q?style=EF=BC=9A=E5=AE=BD=E5=BA=A6=E8=B0=83?=
=?UTF-8?q?=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/static/index/pc/css/topic_nas_help-detail.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/static/index/pc/css/topic_nas_help-detail.css b/public/static/index/pc/css/topic_nas_help-detail.css
index fda9f261..08a2477e 100755
--- a/public/static/index/pc/css/topic_nas_help-detail.css
+++ b/public/static/index/pc/css/topic_nas_help-detail.css
@@ -4,7 +4,7 @@
background: #f9f9f9;
}
.narshelpdetailPc .ql-container{
- width: 95%;
+ width: 81%;
}
.narshelpdetailPc .narsssmain {
width: 100%;
From cca73dd4db5b20bffc6ed6200bdf058aae392c44 Mon Sep 17 00:00:00 2001
From: jsasg <735273025@qq.com>
Date: Tue, 29 Jul 2025 12:00:14 +0800
Subject: [PATCH 8/9] =?UTF-8?q?fix:=20=E4=BA=A7=E5=93=81=E8=AF=A6=E6=83=85?=
=?UTF-8?q?-=E5=88=86=E7=B1=BB=E8=B7=AF=E5=BE=84bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/index/view/mobile/product/detail.html | 4 ++++
app/index/view/pc/product/detail.html | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/app/index/view/mobile/product/detail.html b/app/index/view/mobile/product/detail.html
index 3ea3fc49..d2789f99 100644
--- a/app/index/view/mobile/product/detail.html
+++ b/app/index/view/mobile/product/detail.html
@@ -22,7 +22,11 @@
{:lang_i18n('首页')}
{volist name="product_categorys" id="ca"}
+ {eq name="ca.pid" value="0"}
{$ca.name}
+ {else /}
+ {$ca.name}
+ {/eq}
{/volist}
diff --git a/app/index/view/pc/product/detail.html b/app/index/view/pc/product/detail.html
index 7e481523..7b061f50 100644
--- a/app/index/view/pc/product/detail.html
+++ b/app/index/view/pc/product/detail.html
@@ -22,7 +22,11 @@
{:lang_i18n('首页')}
{volist name="product_categorys" id="ca"}
+ {eq name="ca.pid" value="0"}
{$ca.name}
+ {else /}
+ {$ca.name}
+ {/eq}
{/volist}
From 5f9d1c0d53583b1b2f343b9ad6c83189c6e509c7 Mon Sep 17 00:00:00 2001
From: jsasg <735273025@qq.com>
Date: Tue, 29 Jul 2025 14:08:30 +0800
Subject: [PATCH 9/9] fix: migrations/seeds
---
database/seeds/SysConfigInit.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/database/seeds/SysConfigInit.php b/database/seeds/SysConfigInit.php
index 90f9f79c..d1e00b70 100644
--- a/database/seeds/SysConfigInit.php
+++ b/database/seeds/SysConfigInit.php
@@ -119,10 +119,10 @@ class SysConfigInit extends Seeder
["id" => 102, "group_id" => 13, "title" => "视频 - 唯一性保持", "name" => "upload_video.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 5, "remark" => "如果保持视频文件唯一,重复视频上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:24:24", "updated_at" => "2025-06-12 11:25:18", "deleted_at" => NULL],
["id" => 103, "group_id" => 13, "title" => "附件 - 保留原文件名", "name" => "upload_attachment.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 6, "remark" => "默认为否", "created_at" => "2025-06-12 11:27:08", "updated_at" => "2025-06-12 11:27:08", "deleted_at" => NULL],
["id" => 104, "group_id" => 13, "title" => "附件 - 唯一性保持", "name" => "upload_attachment.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 7, "remark" => "如果保持附件文件唯一,重复附件上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:28:22", "updated_at" => "2025-06-12 11:28:22", "deleted_at" => NULL],
- ['id' => 105, 'group_id' => 13, 'title' => '视频 - 保存到', 'name' => 'upload_video.save_to', 'value' => 'qiniu_cloud', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 6, 'remark' => '视频保存位置,默认为“本地” - [本地为本站点服务器;七牛去为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:46:24', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
- ['id' => 106, 'group_id' => 13, 'title' => '附件 - 保存到', 'name' => 'upload_attachment.save_to', 'value' => 'local', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 9, 'remark' => '附件保存位置,默认为“本地” - [本地为本站点服务器;七牛去为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:51:34', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
- ['id' => 107, 'group_id' => 14, 'title' => '视频 - 保存到', 'name' => 'upload_video.save_to', 'value' => 'qiniu_cloud', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 6, 'remark' => '视频保存位置,默认为“本地” - [本地为本站点服务器;七牛去为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:46:24', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
- ['id' => 108, 'group_id' => 14, 'title' => '附件 - 保存到', 'name' => 'upload_attachment.save_to', 'value' => 'local', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 9, 'remark' => '附件保存位置,默认为“本地” - [本地为本站点服务器;七牛去为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:51:34', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
+ ['id' => 105, 'group_id' => 13, 'title' => '视频 - 保存到', 'name' => 'upload_video.save_to', 'value' => 'qiniu_cloud', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 6, 'remark' => '视频保存位置,默认为“本地” - [本地为本站点服务器;七牛云为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:46:24', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
+ ['id' => 106, 'group_id' => 13, 'title' => '附件 - 保存到', 'name' => 'upload_attachment.save_to', 'value' => 'local', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 9, 'remark' => '附件保存位置,默认为“本地” - [本地为本站点服务器;七牛云为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:51:34', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
+ ['id' => 107, 'group_id' => 14, 'title' => '视频 - 保存到', 'name' => 'upload_video.save_to', 'value' => 'qiniu_cloud', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 6, 'remark' => '视频保存位置,默认为“本地” - [本地为本站点服务器;七牛云为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:46:24', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
+ ['id' => 108, 'group_id' => 14, 'title' => '附件 - 保存到', 'name' => 'upload_attachment.save_to', 'value' => 'local', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 9, 'remark' => '附件保存位置,默认为“本地” - [本地为本站点服务器;七牛云为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:51:34', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
];
$table = $this->table('sys_config');