Compare commits
224 Commits
dc8a3dc5da
...
cssupdate
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fde7159e0 | |||
| 6068efa03f | |||
| 738b293ea2 | |||
| a1be105c31 | |||
| 03374856e4 | |||
| f07741ff19 | |||
| c64450d74c | |||
| e462b38ff9 | |||
| b96021d21d | |||
| 12d6fdc3a6 | |||
| cd3f651a2a | |||
| 1e4b416cac | |||
| e38446f3fd | |||
| 06b9d42ae4 | |||
| 99d78069d5 | |||
| 342a3754aa | |||
| 51e9c8ced1 | |||
| b13d481e1e | |||
| da8f204167 | |||
| c1979da1af | |||
| 1802f57906 | |||
| 3fa3b8fb63 | |||
| fb2b1455bc | |||
| cc497b2ebc | |||
| 2b450a2e9c | |||
| e266e89a97 | |||
| 2a94a7ecec | |||
| 9137335ce3 | |||
| b8946f223a | |||
| 3a8440c2b9 | |||
| c2bba7fb56 | |||
| 052570fefa | |||
| 09b1f9f14c | |||
| 37825f88ba | |||
| 1c7434b591 | |||
| 585da730ea | |||
| 2ecc51d8a9 | |||
| ad7148ccfc | |||
| 1e00db6c97 | |||
| 5ed692a672 | |||
| 5f7156470e | |||
| 3aafcd3f3b | |||
| 9b339d6364 | |||
| 09f9bfd301 | |||
| 910a07ea47 | |||
| c27d529b82 | |||
| b6724c0361 | |||
| d4fa15f671 | |||
| 60229ae058 | |||
| 6cf27d8b9c | |||
| 6ba7181e3f | |||
| 4334c2db66 | |||
| d7e93567d9 | |||
| e19ba6a315 | |||
| a8e7ad2430 | |||
| 55c8762255 | |||
| 43a4f5f706 | |||
| c6cff2e97d | |||
| 5d53c26c5c | |||
| 857bb4ad21 | |||
| b3dfb8655b | |||
| 10c1f86708 | |||
| 62a67bf7a0 | |||
| 4dc4932ac7 | |||
| b99c07ef4a | |||
| f8dc645048 | |||
| 051b4ed7e7 | |||
| 142e29f131 | |||
| 7f58f1ff83 | |||
| 5650ccfb87 | |||
| 439c9073b8 | |||
| f78f164326 | |||
| 5fb2abe818 | |||
| 1f3b646495 | |||
| a1ea5c6752 | |||
| beb86140a6 | |||
| 0d442fb63a | |||
| af139f6bf4 | |||
| 1d79ea5186 | |||
| de02e59b0e | |||
| f4fa5afcfa | |||
| 2c40c95794 | |||
| 70534f2a97 | |||
| 4515939fcf | |||
| b16971e6f1 | |||
| 3840206e7c | |||
| ef1f786417 | |||
| 745671bd33 | |||
| a13ea053e3 | |||
| 0725cd779f | |||
| 47caddad60 | |||
| 5db4263f67 | |||
| 9887bd1045 | |||
| 768e1ed786 | |||
| f211f58068 | |||
| e7e7386054 | |||
| 9c7f2d394b | |||
| a1f1716f5c | |||
| 250f78593a | |||
| 2c0b8161a5 | |||
| 83fa83e00d | |||
| 176b25b631 | |||
| 4b2566b762 | |||
| a25f87de9f | |||
| ec6fa7fe77 | |||
| 0ba299ee05 | |||
| d06002d95c | |||
| 1758fb8995 | |||
| 52259d573c | |||
| a680391d86 | |||
| 0e0ed64b38 | |||
| 5221b43c01 | |||
| a373ee7163 | |||
| 07692a2a29 | |||
| 3c7bdd8ac9 | |||
| db3b704d89 | |||
| 6e3e0d59db | |||
| f8884aa736 | |||
| 8e62d95864 | |||
| 7bf88fd578 | |||
| a4330c1216 | |||
| 6c80dbabeb | |||
| e0009fb8fa | |||
| 66da36a907 | |||
| 702e874e08 | |||
| 7e486e463c | |||
| df482bbcdd | |||
| 7651b056b6 | |||
| 877c8835d9 | |||
| 67865d64cd | |||
| 699e55ffa1 | |||
| 4ca9a84d14 | |||
| ac5d0143ac | |||
| 6434d031ca | |||
| 8f2dbf8798 | |||
| 7a0c3af1e9 | |||
| 7879f7914b | |||
| 99a69bad5f | |||
| 38783d80a0 | |||
| b37ed217cd | |||
| dd687120cc | |||
| 004a007148 | |||
| 5018a59045 | |||
| 8fa1399902 | |||
| e781887d16 | |||
| 55d72124a0 | |||
| 3eda90f2d1 | |||
| 6b815ea414 | |||
| df8001d43e | |||
| 7f8ad55c97 | |||
| 14f0f1609e | |||
| 6c176a1039 | |||
| bffe804a7b | |||
| a9beb0dda6 | |||
| 3c72fa125f | |||
| 81df05e0f9 | |||
| e0fd77837d | |||
| 7344691613 | |||
| fe697df167 | |||
| b743688d99 | |||
| 51b6841a3a | |||
| 768ed5b0fb | |||
| 0c2f96fd49 | |||
| 40c8385776 | |||
| 80c6647a0c | |||
| 187a0affcc | |||
| a35288dd0b | |||
| b36627ec25 | |||
| eb2a98e7fe | |||
| 5c79e33ce1 | |||
| 341e1f54fb | |||
| 78925fbbab | |||
| d9e056972c | |||
| b09f7d1e6f | |||
| ad0f7f4b87 | |||
| 61e4ac1fb3 | |||
| 728730433b | |||
| 3a50a23cfa | |||
| 1dc03040f1 | |||
| 900d73d389 | |||
| 5b69987d6e | |||
| 512c07b5a8 | |||
| 885b86ded9 | |||
| c04b7cae38 | |||
| 3ff0137e4b | |||
| 15c18d5fc1 | |||
| 91b083f0e5 | |||
| a3dccb8b19 | |||
| 974f561c5a | |||
| 8fd52854cc | |||
| b9b865ece0 | |||
| acc39f4580 | |||
| e82c201a2b | |||
| 6927bdbc42 | |||
| 3db7e42e71 | |||
| 12bd511d0b | |||
| 4a52be183c | |||
| 58324ebb33 | |||
| 8ccca36e44 | |||
| d6c7a0f11e | |||
| 858468b72b | |||
| 3eadc5c3eb | |||
| fe324bc62f | |||
| 2329b1bbe6 | |||
| 134c75cc4b | |||
| 3b737b0bd0 | |||
| 2da153e935 | |||
| 271f22ea18 | |||
| 4a56e7e980 | |||
| b3475a7d06 | |||
| 988bdde6f1 | |||
| 456209121e | |||
| 8186a424de | |||
| ebc8c6431a | |||
| 7cbb6adb5d | |||
| 4b8963161f | |||
| eeb79e8c56 | |||
| 2a503cbf68 | |||
| aed2ce4655 | |||
| 70b524ce04 | |||
| db82564148 | |||
| 386cd613ee | |||
| 796231a50e | |||
| 6b082f2de9 |
5
.env
5
.env
@@ -1,5 +0,0 @@
|
|||||||
|
|
||||||
[JWT]
|
|
||||||
TTL=3600
|
|
||||||
REFRESH_TTL=20160
|
|
||||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
|
||||||
42
.example.env
42
.example.env
@@ -26,6 +26,13 @@ TTL=3600
|
|||||||
REFRESH_TTL=20160
|
REFRESH_TTL=20160
|
||||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
||||||
|
|
||||||
|
# 七牛云存储配置
|
||||||
|
[QINIU_CLOUD]
|
||||||
|
BUCKET = orico-official-website
|
||||||
|
BASE_URL = //ow.static.f2b211.com
|
||||||
|
ACCESS_KEY = dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms
|
||||||
|
SECRET_KEY = KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q
|
||||||
|
|
||||||
# 后台不需要登录的接口
|
# 后台不需要登录的接口
|
||||||
[ADMIN_AUTH]
|
[ADMIN_AUTH]
|
||||||
WHITE_LIST[] = v1/user/login
|
WHITE_LIST[] = v1/user/login
|
||||||
@@ -36,17 +43,26 @@ WHITE_LIST[] = receive_sync/product
|
|||||||
# 不需记录日志的接口
|
# 不需记录日志的接口
|
||||||
[ADMIN_API]
|
[ADMIN_API]
|
||||||
IGNORE_LOGGING_LIST[] = v1/OperateLog/index
|
IGNORE_LOGGING_LIST[] = v1/OperateLog/index
|
||||||
MAX_IMAGE_SIZE = 5mb # 图片上传最大限制
|
MAX_IMAGE_SIZE = 5mb; # 图片上传最大限制
|
||||||
MAX_VIDEO_SIZE = 150mb # 视频上传最大限制
|
MAX_VIDEO_SIZE = 150mb; # 视频上传最大限制
|
||||||
MAX_ATTACHMENT_SIZE = 100mb # 附件上传最大限制
|
MAX_ATTACHMENT_SIZE = 100mb; # 附件上传最大限制
|
||||||
|
|
||||||
# 开放API
|
# 开放API
|
||||||
[OPENAPI]
|
[OPENAPI]
|
||||||
|
ACCESS_TOKEN_LIFETIME = 3600; # 访问令牌有效期
|
||||||
|
REFRESH_TOKEN_LIFETIME = 1209600; # 刷新令牌有效期
|
||||||
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
|
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
|
||||||
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
|
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
|
||||||
|
|
||||||
# 视图模板规则配置
|
# 七牛云存储配置
|
||||||
[VIEW_TPL]
|
[QINUI]
|
||||||
|
BUCKET = orico
|
||||||
|
BASE_URL = http://local.orico.com
|
||||||
|
ACCESS_KEY = 1234567890
|
||||||
|
SECRET_KEY = 1234567890
|
||||||
|
|
||||||
|
# 前台视图模板规则配置
|
||||||
|
[INDEX_VIEW_TPL]
|
||||||
# 视图目录
|
# 视图目录
|
||||||
# query 规则:URL参数 mtpl=1 表示移动端访问
|
# query 规则:URL参数 mtpl=1 表示移动端访问
|
||||||
# 例如:http://xxxx.com?mtpl=1
|
# 例如:http://xxxx.com?mtpl=1
|
||||||
@@ -62,3 +78,19 @@ RULE_DOMAIN_SCHEME[] = http
|
|||||||
RULE_DOMAIN_SCHEME[] = https
|
RULE_DOMAIN_SCHEME[] = https
|
||||||
# domain 规则域名
|
# domain 规则域名
|
||||||
RULE_DOMAIN_HOST = mobile.orico.cn
|
RULE_DOMAIN_HOST = mobile.orico.cn
|
||||||
|
|
||||||
|
# 前台语言检测配置
|
||||||
|
[INDEX_LANG_DETECT]
|
||||||
|
# 是否启用域名检测方式来检测语言
|
||||||
|
DOMAIN_DETECT = true
|
||||||
|
# 域名规则
|
||||||
|
# 格式:域名=语言
|
||||||
|
# 例如:mobile.orico.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = orico.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = orico.com.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = www.orico.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = www.orico.com.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = ow.f2b211.com=zh-cn
|
||||||
|
DOMAIN_RULE[] = orico.cc=en-us
|
||||||
|
DOMAIN_RULE[] = www.orico.cc=en-us
|
||||||
|
DOMAIN_RULE[] = ow.us.f2b211.com=en-us
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,9 +3,13 @@ composer.phar
|
|||||||
composer.lock
|
composer.lock
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
.env
|
||||||
.env.dev
|
.env.dev
|
||||||
.env.local
|
.env.local
|
||||||
|
.env.prod
|
||||||
|
|
||||||
|
public/dist
|
||||||
|
public/opendoc
|
||||||
/.idea
|
/.idea
|
||||||
/.vscode
|
/.vscode
|
||||||
/vendor
|
/vendor
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ class ReceiveProductSync
|
|||||||
}
|
}
|
||||||
|
|
||||||
$category = ProductCategoryModel::language($lang_id)->tcoId($tco_category['id'])->find();
|
$category = ProductCategoryModel::language($lang_id)->tcoId($tco_category['id'])->find();
|
||||||
|
if (!empty($category)) {
|
||||||
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
|
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
|
||||||
if (!empty($tco_parent)) {
|
if (!empty($tco_parent)) {
|
||||||
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
|
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
|
||||||
@@ -109,10 +110,11 @@ class ReceiveProductSync
|
|||||||
$category['path'] = $parent['path'] . $parent['pid'];
|
$category['path'] = $parent['path'] . $parent['pid'];
|
||||||
$category['level'] = $parent['level'] + 1;
|
$category['level'] = $parent['level'] + 1;
|
||||||
}
|
}
|
||||||
if (!$category->save($category)) {
|
if (!$category->save()) {
|
||||||
throw new \Exception('产品分类更新失败');
|
throw new \Exception('产品分类更新失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Db::commit();
|
Db::commit();
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
@@ -183,7 +185,7 @@ class ReceiveProductSync
|
|||||||
'desc' => '',
|
'desc' => '',
|
||||||
'video_img' => '',
|
'video_img' => '',
|
||||||
'video_url' => '',
|
'video_url' => '',
|
||||||
'is_sale' => 0,
|
'is_sale' => 1,
|
||||||
'is_new' => 0,
|
'is_new' => 0,
|
||||||
'is_hot' => 0,
|
'is_hot' => 0,
|
||||||
'is_show' => 0,
|
'is_show' => 0,
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ class Article
|
|||||||
private function getExportArticleData()
|
private function getExportArticleData()
|
||||||
{
|
{
|
||||||
$server = request()->server();
|
$server = request()->server();
|
||||||
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . config('filesystem.disks.public.url') . '/';
|
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . '/';
|
||||||
$param = request()->param(['title', 'category_id', 'release_time']);
|
$param = request()->param(['title', 'category_id', 'release_time']);
|
||||||
$data = ArticleModel::field([
|
$data = ArticleModel::field([
|
||||||
'*',
|
'*',
|
||||||
@@ -253,7 +253,7 @@ class Article
|
|||||||
])
|
])
|
||||||
->bindAttr('category', ['category_name' => 'name'])
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
->each(function ($item) use($image_host) {
|
->each(function ($item) use($image_host) {
|
||||||
$item->image = !empty($item->image) ? $image_host . $item->image : '';
|
$item->image = !empty($item->image) ? url_join($image_host, $item->image) : '';
|
||||||
return $item;
|
return $item;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -262,11 +262,9 @@ class BannerItem
|
|||||||
// 获取导出数据
|
// 获取导出数据
|
||||||
private function getBannerExportData()
|
private function getBannerExportData()
|
||||||
{
|
{
|
||||||
$param = request()->param([
|
$server = request()->server();
|
||||||
'title',
|
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . '/';
|
||||||
'banner_id',
|
$param = request()->param(['title', 'banner_id', 'created_at']);
|
||||||
'created_at'
|
|
||||||
]);
|
|
||||||
return SysBannerItemModel::alias('item')
|
return SysBannerItemModel::alias('item')
|
||||||
->field([
|
->field([
|
||||||
'item.id',
|
'item.id',
|
||||||
@@ -311,7 +309,13 @@ class BannerItem
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
->order(['item.sort' => 'asc', 'item.id' => 'desc'])
|
->order(['item.sort' => 'asc', 'item.id' => 'desc'])
|
||||||
->select();
|
->select()
|
||||||
|
->each(function($item) use($image_host) {
|
||||||
|
$item->image = !empty($item->image) ? url_join($image_host, $item->image) : '';
|
||||||
|
$item->extra_image = !empty($item->extra_image) ? url_join($image_host, $item->extra_image) : '';
|
||||||
|
$item->video = !empty($item->video) ? url_join($image_host, $item->video) : '';
|
||||||
|
return $item;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class Product
|
|||||||
])
|
])
|
||||||
->categoryNullable($param['category_id']??null)
|
->categoryNullable($param['category_id']??null)
|
||||||
->isShowNullable(isset($param['is_show']) ? (bool)$param['is_show'] : null)
|
->isShowNullable(isset($param['is_show']) ? (bool)$param['is_show'] : null)
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'created_at' => 'desc', 'id' => 'desc'])
|
||||||
->paginate([
|
->paginate([
|
||||||
'list_rows' => $param['size'],
|
'list_rows' => $param['size'],
|
||||||
'page' => $param['page'],
|
'page' => $param['page'],
|
||||||
@@ -171,7 +171,7 @@ class Product
|
|||||||
// 更新产品参数
|
// 更新产品参数
|
||||||
if ($put['params'] != "") {
|
if ($put['params'] != "") {
|
||||||
ProductParamsModel::productId($id)->delete();
|
ProductParamsModel::productId($id)->delete();
|
||||||
if (preg_match_all('/(\S+):(.[^\s]+)/', $put['params'], $match_result)) {
|
if (preg_match_all('/(.+):(.+)/', $put['params'], $match_result)) {
|
||||||
$params = [];
|
$params = [];
|
||||||
for ($i = 0; $i < count($match_result[0]); $i++) {
|
for ($i = 0; $i < count($match_result[0]); $i++) {
|
||||||
$params[] = [
|
$params[] = [
|
||||||
@@ -346,7 +346,7 @@ class Product
|
|||||||
private function getExportProductData()
|
private function getExportProductData()
|
||||||
{
|
{
|
||||||
$server = request()->server();
|
$server = request()->server();
|
||||||
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . config('filesystem.disks.public.url') . '/';
|
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . '/';
|
||||||
$param = request()->param([
|
$param = request()->param([
|
||||||
'name',
|
'name',
|
||||||
'spu',
|
'spu',
|
||||||
@@ -360,10 +360,10 @@ class Product
|
|||||||
'spu',
|
'spu',
|
||||||
'name',
|
'name',
|
||||||
'short_name',
|
'short_name',
|
||||||
'CONCAT("' . $image_host . '", `cover_image`)' => 'cover_image',
|
'cover_image',
|
||||||
'desc',
|
'desc',
|
||||||
'CONCAT("' . $image_host . '", `video_img`)' => 'video_img',
|
'video_img',
|
||||||
'CONCAT("' . $image_host . '", `video_url`)' => 'video_url',
|
'video_url',
|
||||||
'CASE WHEN is_new = 1 THEN "是" ELSE "否" END' => 'is_new',
|
'CASE WHEN is_new = 1 THEN "是" ELSE "否" END' => 'is_new',
|
||||||
'CASE WHEN is_hot = 1 THEN "是" ELSE "否" END' => 'is_hot',
|
'CASE WHEN is_hot = 1 THEN "是" ELSE "否" END' => 'is_hot',
|
||||||
'CASE WHEN is_sale = 1 THEN "是" ELSE "否" END' => 'is_sale',
|
'CASE WHEN is_sale = 1 THEN "是" ELSE "否" END' => 'is_sale',
|
||||||
@@ -390,7 +390,18 @@ class Product
|
|||||||
->order(['id' => 'asc'])
|
->order(['id' => 'asc'])
|
||||||
->select()
|
->select()
|
||||||
->bindAttr('category', ['category_name' => 'name'])
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
->hidden(['category_id', 'category']);
|
->hidden(['category_id', 'category'])
|
||||||
|
->each(function($item) use($image_host) {
|
||||||
|
if (!empty($item["cover_image"])) {
|
||||||
|
$item["cover_image"] = url_join($image_host, $item["cover_image"]);
|
||||||
|
}
|
||||||
|
if (!empty($item["video_img"])) {
|
||||||
|
$item["video_img"] = url_join($image_host, $item["video_img"]);
|
||||||
|
}
|
||||||
|
if (!empty($item["video_url"])) {
|
||||||
|
$item["video_url"] = url_join($image_host, $item["video_url"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!$products->isEmpty()) {
|
if (!$products->isEmpty()) {
|
||||||
// 产品参数
|
// 产品参数
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ class ProductTcoCategory
|
|||||||
$param = request()->param(['name']);
|
$param = request()->param(['name']);
|
||||||
|
|
||||||
$categorys = ProductTcoCategoryModel::field([
|
$categorys = ProductTcoCategoryModel::field([
|
||||||
'tco_id' => 'id',
|
'id',
|
||||||
'tco_pid' => 'pid',
|
'tco_id',
|
||||||
|
'tco_pid',
|
||||||
'name',
|
'name',
|
||||||
])
|
])
|
||||||
->withSearch(['name'], [
|
->withSearch(['name'], [
|
||||||
@@ -25,10 +26,10 @@ class ProductTcoCategory
|
|||||||
])
|
])
|
||||||
->language(request()->lang_id)
|
->language(request()->lang_id)
|
||||||
->enabled()
|
->enabled()
|
||||||
->order(['id' => 'asc'])
|
->order(['tco_id' => 'asc'])
|
||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
return success('获取成功', array_to_tree($categorys, 0, 'pid', false));
|
return success('获取成功', array_to_tree($categorys, 0, 'tco_pid', false, true, 'tco_id'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use app\admin\model\v1\SysAttachmentUploadRecordModel;
|
|||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
use Intervention\Image\Typography\FontFactory;
|
use Intervention\Image\Typography\FontFactory;
|
||||||
use think\facade\Filesystem;
|
use think\facade\Filesystem;
|
||||||
|
use filesystem\Qiniu;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件上传控制器
|
* 文件上传控制器
|
||||||
@@ -71,7 +72,7 @@ class Upload
|
|||||||
// 转换为webp格式
|
// 转换为webp格式
|
||||||
$webp = $image->toWebp(75);
|
$webp = $image->toWebp(75);
|
||||||
$root = config('filesystem.disks.image.root');
|
$root = config('filesystem.disks.image.root');
|
||||||
$filename = $param['module'] . '/' . ($name_rule() ?? date('Ymd') . '/' . md5((string)time()) . '.webp');
|
$filename = $param['module'] . '/' . ($name_rule() ? $name_rule()() : date('Ymd') . '/' . md5((string)time() . random_str(8))) . '.webp';
|
||||||
$webp->save($this->checkPath($root . '/' . $filename));
|
$webp->save($this->checkPath($root . '/' . $filename));
|
||||||
// 获取webp文件大小
|
// 获取webp文件大小
|
||||||
$file_size = $webp->size();
|
$file_size = $webp->size();
|
||||||
@@ -153,8 +154,8 @@ class Upload
|
|||||||
$image_model = new SysImageUploadRecordModel();
|
$image_model = new SysImageUploadRecordModel();
|
||||||
$image_model->language_id = request()->lang_id;
|
$image_model->language_id = request()->lang_id;
|
||||||
$image_model->module = $param['module'];
|
$image_model->module = $param['module'];
|
||||||
$image_model->image_path = $filename;
|
$image_model->image_path = $storage . '/' . $filename;
|
||||||
$image_model->image_thumb = $thumb_filename;
|
$image_model->image_thumb = $storage . '/' . $thumb_filename;
|
||||||
$image_model->file_size = $file_size;
|
$image_model->file_size = $file_size;
|
||||||
$image_model->file_type = $mime_type;
|
$image_model->file_type = $mime_type;
|
||||||
$image_model->file_md5 = $filemd5;
|
$image_model->file_md5 = $filemd5;
|
||||||
@@ -165,8 +166,8 @@ class Upload
|
|||||||
}
|
}
|
||||||
|
|
||||||
return success('操作成功', [
|
return success('操作成功', [
|
||||||
'path' => $storage . '/' . $image_model->image_path,
|
'path' => $image_model->image_path,
|
||||||
'thumb_path' => $storage . '/' . $image_model->image_thumb,
|
'thumb_path' => $image_model->image_thumb,
|
||||||
'filemd5' => $image_model->file_md5,
|
'filemd5' => $image_model->file_md5,
|
||||||
'filesha1' => $image_model->file_sha1
|
'filesha1' => $image_model->file_sha1
|
||||||
]);
|
]);
|
||||||
@@ -226,6 +227,7 @@ class Upload
|
|||||||
'filename_keep' => (int)data_get($options, 'filename_keep.value', 0) == 1,
|
'filename_keep' => (int)data_get($options, 'filename_keep.value', 0) == 1,
|
||||||
'filemd5_unique' => (int)data_get($options, 'filemd5_unique.value', 0) == 1,
|
'filemd5_unique' => (int)data_get($options, 'filemd5_unique.value', 0) == 1,
|
||||||
'filetype_to' => data_get($options, 'filetype_to.value', 'original'),
|
'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(
|
list(
|
||||||
'filename_keep' => $filename_keep,
|
'filename_keep' => $filename_keep,
|
||||||
'filemd5_unique' => $filemd5_unique
|
'filemd5_unique' => $filemd5_unique,
|
||||||
|
'save_to' => $save_to,
|
||||||
) = $this->getUploadOptions('upload_video');
|
) = $this->getUploadOptions('upload_video');
|
||||||
// 是否需要根据文件MD5值检查文件是否已存在
|
// 是否需要根据文件MD5值检查文件是否已存在
|
||||||
$video = $filemd5_unique ? SysVideoUploadRecordModel::md5($filemd5)->find() : null;
|
$video = $filemd5_unique ? SysVideoUploadRecordModel::md5($filemd5)->find() : null;
|
||||||
if (is_null($video)) {
|
if (is_null($video)) {
|
||||||
|
// 保存位置配置 key
|
||||||
|
$disk = 'video';
|
||||||
// 检查是否需要保留原文件名
|
// 检查是否需要保留原文件名
|
||||||
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
$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 = new SysVideoUploadRecordModel();
|
||||||
$video->language_id = request()->lang_id;
|
$video->language_id = request()->lang_id;
|
||||||
$video->module = $param['module'];
|
$video->module = $param['module'];
|
||||||
$video->video_path = $filename;
|
$video->video_path = $video_path;
|
||||||
$video->file_size = $file->getSize();
|
$video->file_size = $file->getSize();
|
||||||
$video->file_type = $file->getOriginalMime();
|
$video->file_type = $file->getOriginalMime();
|
||||||
$video->file_md5 = $filemd5;
|
$video->file_md5 = $filemd5;
|
||||||
@@ -369,7 +386,7 @@ class Upload
|
|||||||
}
|
}
|
||||||
|
|
||||||
return success('上传成功', [
|
return success('上传成功', [
|
||||||
'path' => $storage . '/' . $video->video_path,
|
'path' => $video->video_path,
|
||||||
'file_md5' => $video->file_md5,
|
'file_md5' => $video->file_md5,
|
||||||
'file_sha1' => $video->file_sha1
|
'file_sha1' => $video->file_sha1
|
||||||
]);
|
]);
|
||||||
@@ -399,25 +416,42 @@ class Upload
|
|||||||
return error($validate->getError());
|
return error($validate->getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$storage = config('filesystem.disks.public.url');
|
||||||
|
|
||||||
$filemd5 = $file->md5();
|
$filemd5 = $file->md5();
|
||||||
$filesha1 = $file->sha1();
|
$filesha1 = $file->sha1();
|
||||||
|
|
||||||
// 获取附件上传配置
|
// 获取附件上传配置
|
||||||
list(
|
list(
|
||||||
'filename_keep' => $filename_keep,
|
'filename_keep' => $filename_keep,
|
||||||
'filemd5_unique' => $filemd5_unique
|
'filemd5_unique' => $filemd5_unique,
|
||||||
|
'save_to' => $save_to
|
||||||
) = $this->getUploadOptions('upload_attachment');
|
) = $this->getUploadOptions('upload_attachment');
|
||||||
// 是否需要根据文件MD5值检查文件是否已存在
|
// 是否需要根据文件MD5值检查文件是否已存在
|
||||||
$attachment = $filemd5_unique ? SysAttachmentUploadRecordModel::md5($filemd5)->find() : null;
|
$attachment = $filemd5_unique ? SysAttachmentUploadRecordModel::md5($filemd5)->find() : null;
|
||||||
if (is_null($attachment)) {
|
if (is_null($attachment)) {
|
||||||
|
// 保存位置配置 key
|
||||||
|
$disk = 'public';
|
||||||
// 检查是否需要保留原文件名
|
// 检查是否需要保留原文件名
|
||||||
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
$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 = new SysAttachmentUploadRecordModel();
|
||||||
$attachment->language_id = request()->lang_id;
|
$attachment->language_id = request()->lang_id;
|
||||||
$attachment->attachment_path = $filename;
|
$attachment->attachment_path = $attachment_path;
|
||||||
$attachment->file_size = $file->getSize();
|
$attachment->file_size = $file->getSize();
|
||||||
$attachment->file_type = $file->getOriginalMime();
|
$attachment->file_type = $file->getOriginalMime();
|
||||||
$attachment->file_md5 = $filemd5;
|
$attachment->file_md5 = $filemd5;
|
||||||
@@ -427,9 +461,8 @@ class Upload
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$storage = config('filesystem.disks.public.url');
|
|
||||||
return success('上传成功', [
|
return success('上传成功', [
|
||||||
'path' => $storage . '/' . $attachment->attachment_path,
|
'path' => $attachment->attachment_path,
|
||||||
'file_md5' => $attachment->file_md5,
|
'file_md5' => $attachment->file_md5,
|
||||||
'file_sha1' => $attachment->file_sha1
|
'file_sha1' => $attachment->file_sha1
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -209,9 +209,6 @@ class Video
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$domain = request()->domain();
|
$domain = request()->domain();
|
||||||
$image_path = Config::get('filesystem.disks.image.url');
|
|
||||||
$video_path = Config::get('filesystem.disks.video.url');
|
|
||||||
|
|
||||||
return VideoModel::withoutField([
|
return VideoModel::withoutField([
|
||||||
'language_id',
|
'language_id',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
@@ -230,13 +227,9 @@ class Video
|
|||||||
->select()
|
->select()
|
||||||
->bindAttr('category', ['category_name' => 'name'])
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
->hidden(['category_id', 'category'])
|
->hidden(['category_id', 'category'])
|
||||||
->each(function ($item) use($domain, $image_path, $video_path) {
|
->each(function ($item) use($domain) {
|
||||||
if (!empty($item->image)) {
|
$item->image = !empty($item->image) ? url_join($domain, $item->image) : '';
|
||||||
$item->image = $domain . $image_path . '/' . $item->image;
|
$item->video = !empty($item->video) ? url_join($domain, $item->video) : '';
|
||||||
}
|
|
||||||
if (!empty($item->video)) {
|
|
||||||
$item->video = $domain . $video_path . '/' . $item->video;
|
|
||||||
}
|
|
||||||
$item->recommend = $item->recommend == 1 ? '是' : '否';
|
$item->recommend = $item->recommend == 1 ? '是' : '否';
|
||||||
$item->status = $item->status == 1 ? '启用' : '禁用';
|
$item->status = $item->status == 1 ? '启用' : '禁用';
|
||||||
return $item;
|
return $item;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class SysBannerItemValidate extends Validate
|
|||||||
*/
|
*/
|
||||||
protected $rule = [
|
protected $rule = [
|
||||||
'id' => 'require|integer',
|
'id' => 'require|integer',
|
||||||
'banner_id' => 'require|integer',
|
'banner_id' => 'require|integer|gt:0',
|
||||||
'title' => 'require|max:256',
|
'title' => 'require|max:256',
|
||||||
'title_txt_color' => 'max:7',
|
'title_txt_color' => 'max:7',
|
||||||
'desc' => 'max:1024',
|
'desc' => 'max:1024',
|
||||||
@@ -25,7 +25,7 @@ class SysBannerItemValidate extends Validate
|
|||||||
'extra_image' => 'max:255',
|
'extra_image' => 'max:255',
|
||||||
'video' => 'max:255',
|
'video' => 'max:255',
|
||||||
'link_to' => 'requireIf:type,image|max:64|in:article,article_category,product,product_category,system_page,custom',
|
'link_to' => 'requireIf:type,image|max:64|in:article,article_category,product,product_category,system_page,custom',
|
||||||
'link' => 'max:255',
|
'link' => 'max:510',
|
||||||
'sort' => 'integer',
|
'sort' => 'integer',
|
||||||
'status' => 'in:-1,1'
|
'status' => 'in:-1,1'
|
||||||
];
|
];
|
||||||
@@ -41,6 +41,7 @@ class SysBannerItemValidate extends Validate
|
|||||||
'id.integer' => 'ID必须是整数',
|
'id.integer' => 'ID必须是整数',
|
||||||
'banner_id.require' => '横幅项分类不能为空',
|
'banner_id.require' => '横幅项分类不能为空',
|
||||||
'banner_id.integer' => '横幅项分类必须是整数',
|
'banner_id.integer' => '横幅项分类必须是整数',
|
||||||
|
'banner_id.gt' => '该横幅分类不可选',
|
||||||
'title.require' => '名称不能为空',
|
'title.require' => '名称不能为空',
|
||||||
'title.max' => '名称最多不能超过256个字符',
|
'title.max' => '名称最多不能超过256个字符',
|
||||||
'title_txt_color.max' => '名称字体颜色最多不能超过7个字符',
|
'title_txt_color.max' => '名称字体颜色最多不能超过7个字符',
|
||||||
@@ -53,7 +54,7 @@ class SysBannerItemValidate extends Validate
|
|||||||
'link_to.requireIf' => '链接类型不能为空',
|
'link_to.requireIf' => '链接类型不能为空',
|
||||||
'link_to.max' => '链接类型最多不能超过64个字符',
|
'link_to.max' => '链接类型最多不能超过64个字符',
|
||||||
'link_to.in' => '链接类型必须是article,article_category,product,product_category,system_page,custom中之一',
|
'link_to.in' => '链接类型必须是article,article_category,product,product_category,system_page,custom中之一',
|
||||||
'link.max' => '链接最多不能超过255个字符',
|
'link.max' => '链接最多不能超过512个字符',
|
||||||
'sort.integer' => '排序值必须是整数',
|
'sort.integer' => '排序值必须是整数',
|
||||||
'status.in' => '状态必须是-1或1'
|
'status.in' => '状态必须是-1或1'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ class VideoValidate extends Validate
|
|||||||
'id' => 'require|integer',
|
'id' => 'require|integer',
|
||||||
'language_id' => 'require|integer',
|
'language_id' => 'require|integer',
|
||||||
'category_id' => 'require|integer',
|
'category_id' => 'require|integer',
|
||||||
'name' => 'require|max:64',
|
'name' => 'require|max:128',
|
||||||
'desc' => 'max:255',
|
'desc' => 'max:512',
|
||||||
'image' => 'max:125',
|
'image' => 'max:125',
|
||||||
'video' => 'max:125',
|
'video' => 'max:125',
|
||||||
'link' => 'url|max:125',
|
'link' => 'url|max:125',
|
||||||
@@ -43,8 +43,8 @@ class VideoValidate extends Validate
|
|||||||
'category_id.require' => '分类不能为空',
|
'category_id.require' => '分类不能为空',
|
||||||
'category_id.integer' => '分类参数类型错误',
|
'category_id.integer' => '分类参数类型错误',
|
||||||
'name.require' => '名称不能为空',
|
'name.require' => '名称不能为空',
|
||||||
'name.max' => '名称不能超过64个字符',
|
'name.max' => '名称不能超过128个字符',
|
||||||
'desc.max' => '描述不能超过255个字符',
|
'desc.max' => '描述不能超过512个字符',
|
||||||
'image.max' => '图片不能超过125个字符',
|
'image.max' => '图片不能超过125个字符',
|
||||||
'video.max' => '视频不能超过125个字符',
|
'video.max' => '视频不能超过125个字符',
|
||||||
'link.url' => '链接格式错误',
|
'link.url' => '链接格式错误',
|
||||||
|
|||||||
@@ -60,10 +60,10 @@ class DataMigration extends Command
|
|||||||
// $this->migrateProductPurchaseLinks();
|
// $this->migrateProductPurchaseLinks();
|
||||||
|
|
||||||
// 迁移文章
|
// 迁移文章
|
||||||
$this->migrateArticle([
|
// $this->migrateArticle([
|
||||||
16 => 7,
|
// 16 => 7,
|
||||||
31 => 9,
|
// 31 => 9,
|
||||||
32 => 8,
|
// 32 => 8,
|
||||||
// 68 => 10,
|
// 68 => 10,
|
||||||
// 69 => 11,
|
// 69 => 11,
|
||||||
// 70 => 12,
|
// 70 => 12,
|
||||||
@@ -80,7 +80,7 @@ class DataMigration extends Command
|
|||||||
// 83 => 24,
|
// 83 => 24,
|
||||||
// 84 => 25,
|
// 84 => 25,
|
||||||
// 85 => 26
|
// 85 => 26
|
||||||
]);
|
// ]);
|
||||||
|
|
||||||
// 迁移faq
|
// 迁移faq
|
||||||
// $this->migrateFaq();
|
// $this->migrateFaq();
|
||||||
@@ -930,7 +930,8 @@ class DataMigration extends Command
|
|||||||
{
|
{
|
||||||
$videos = Db::connect('old')
|
$videos = Db::connect('old')
|
||||||
->name('video')
|
->name('video')
|
||||||
->where('id', '>', 844)
|
// ->where('id', '>', 844)
|
||||||
|
->where('cid', 'in', array_keys($category_map))
|
||||||
->where('country_code', 'in', ['ZH', 'US'])
|
->where('country_code', 'in', ['ZH', 'US'])
|
||||||
->order(['id' => 'asc'])
|
->order(['id' => 'asc'])
|
||||||
->cursor();
|
->cursor();
|
||||||
@@ -970,7 +971,16 @@ class DataMigration extends Command
|
|||||||
'seo_desc' => $val['seo_description'],
|
'seo_desc' => $val['seo_description'],
|
||||||
'deleted_at' => $val['stat'] == -1 ? date('Y-m-d H:i:s') : null
|
'deleted_at' => $val['stat'] == -1 ? date('Y-m-d H:i:s') : null
|
||||||
];
|
];
|
||||||
|
$ret = Db::name('video')
|
||||||
|
->where('language_id', '=', $item['language_id'])
|
||||||
|
->where('name', '=', $item['name'])
|
||||||
|
->find();
|
||||||
|
if (empty($ret)) {
|
||||||
Db::name('video')->insert($item);
|
Db::name('video')->insert($item);
|
||||||
|
} else {
|
||||||
|
Db::name('video')->where('id', '=', $ret['id'])->update($item);
|
||||||
|
}
|
||||||
|
|
||||||
$this->println('迁移视频ID:' . $val['id']);
|
$this->println('迁移视频ID:' . $val['id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ if (!function_exists('array_to_tree')) {
|
|||||||
* @param bool $keep_pid 是否保留pid
|
* @param bool $keep_pid 是否保留pid
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
function array_to_tree(array $data, int $pid, string $with = 'pid', int|bool $level = 1, bool $keep_pid = true)
|
function array_to_tree(array $data, int $pid, string $with = 'pid', int|bool $level = 1, bool $keep_pid = true, $with_ref = 'id')
|
||||||
{
|
{
|
||||||
$ret = [];
|
$ret = [];
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
@@ -93,7 +93,7 @@ if (!function_exists('array_to_tree')) {
|
|||||||
if ($keep_pid === false) {
|
if ($keep_pid === false) {
|
||||||
unset($item[$with]);
|
unset($item[$with]);
|
||||||
}
|
}
|
||||||
$children = array_to_tree($data, $item['id'], $with, $lv, $keep_pid);
|
$children = array_to_tree($data, $item[$with_ref], $with, $lv, $keep_pid, $with_ref);
|
||||||
if ($children) {
|
if ($children) {
|
||||||
$item['children'] = $children;
|
$item['children'] = $children;
|
||||||
}
|
}
|
||||||
@@ -145,3 +145,90 @@ if (!function_exists('thumb')) {
|
|||||||
return mb_substr($url, 0, $idx, 'utf-8') . '_thumb' . mb_substr($url, $idx, $len - $idx, 'utf-8');
|
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|null $url, string $disk): string
|
||||||
|
{
|
||||||
|
if (is_null($url)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
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|null $url): string
|
||||||
|
{
|
||||||
|
if (is_null($url)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('url_join')) {
|
||||||
|
/**
|
||||||
|
* 合并URL
|
||||||
|
* @param string $url 基础URL
|
||||||
|
* @param string $path 路径
|
||||||
|
* @param bool $remove_slash 是否移除首尾的斜杠
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function url_join(string $url, string $path, bool $remove_slash = true): string
|
||||||
|
{
|
||||||
|
if (empty($url)) {
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
if (empty($path)) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
if (\think\helper\Str::startsWith($path, ['http://', 'https://', '//'])) {
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($remove_slash) {
|
||||||
|
if (str_ends_with($url, '/') && str_starts_with($path, '/')) {
|
||||||
|
return $url . substr($path, 1);
|
||||||
|
}
|
||||||
|
if (!str_ends_with($url, '/') && !str_starts_with($path, '/')) {
|
||||||
|
return $url . '/' . $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url . $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,6 @@ class SysRoleAuthorityBaseModel extends Model
|
|||||||
protected $schema = [
|
protected $schema = [
|
||||||
'role_id' => 'int',
|
'role_id' => 'int',
|
||||||
'menu_id' => 'int',
|
'menu_id' => 'int',
|
||||||
'permission' => 'int',
|
'permission' => 'string',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,14 +194,14 @@ if (!function_exists('get_platform')) {
|
|||||||
} else {
|
} else {
|
||||||
// 在非移动端环境,根据配置规则判断是否要显示移动端
|
// 在非移动端环境,根据配置规则判断是否要显示移动端
|
||||||
$view_cfg = $view_cfg = [
|
$view_cfg = $view_cfg = [
|
||||||
'rule' => env('VIEW_TPL.RULE', 'query'),
|
'rule' => env('INDEX_VIEW_TPL.RULE', 'query'),
|
||||||
'query' => [
|
'query' => [
|
||||||
'name' => env('VIEW_TPL.RULE_QUERY_NAME', 'mtpl'),
|
'name' => env('INDEX_VIEW_TPL.RULE_QUERY_NAME', 'mtpl'),
|
||||||
'value' => env('VIEW_TPL.RULE_QUERY_VALUE', '1'),
|
'value' => env('INDEX_VIEW_TPL.RULE_QUERY_VALUE', '1'),
|
||||||
],
|
],
|
||||||
'domain' => [
|
'domain' => [
|
||||||
'scheme' => env('VIEW_TPL.RULE_DOMAIN_SCHEME', ['http']),
|
'scheme' => env('INDEX_VIEW_TPL.RULE_DOMAIN_SCHEME', ['http']),
|
||||||
'host' => env('VIEW_TPL.RULE_DOMAIN_HOST'),
|
'host' => env('INDEX_VIEW_TPL.RULE_DOMAIN_HOST'),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
if ($view_cfg['rule'] == 'query') {
|
if ($view_cfg['rule'] == 'query') {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class Attachment extends Common
|
|||||||
{
|
{
|
||||||
$param = request()->param([
|
$param = request()->param([
|
||||||
'id',
|
'id',
|
||||||
'keyword',
|
'keyword' => '',
|
||||||
'page/d' => 1,
|
'page/d' => 1,
|
||||||
'size/d' => 12,
|
'size/d' => 12,
|
||||||
]);
|
]);
|
||||||
@@ -48,9 +48,9 @@ class Attachment extends Common
|
|||||||
'support_platform',
|
'support_platform',
|
||||||
'attach',
|
'attach',
|
||||||
])
|
])
|
||||||
->withSearch(['name'], ['name' => $param['keyword']??null])
|
->withSearch(['name'], ['name' => !empty($param['keyword']) ? trim($param['keyword']) : null])
|
||||||
->language($this->lang_id)
|
->language($this->lang_id)
|
||||||
->category($param['id']??null)
|
->category(!empty($param['id']) ? $param['id'] : $categorys[0]['id']??null)
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
->paginate([
|
->paginate([
|
||||||
'list_rows' => $param['size'],
|
'list_rows' => $param['size'],
|
||||||
@@ -59,6 +59,16 @@ class Attachment extends Common
|
|||||||
'id' => $param['id']??null
|
'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('attachements', $attachements);
|
||||||
View::assign('page', $attachements->render());
|
View::assign('page', $attachements->render());
|
||||||
|
|
||||||
@@ -109,9 +119,9 @@ class Attachment extends Common
|
|||||||
'video',
|
'video',
|
||||||
'link'
|
'link'
|
||||||
])
|
])
|
||||||
->withSearch(['name'], ['name' => $param['keyword']??null])
|
->withSearch(['name'], ['name' => !empty($param['keyword']) ? trim($param['keyword']) : null])
|
||||||
->language($this->lang_id)
|
->language($this->lang_id)
|
||||||
->category($param['id']??$video_categorys[0]['id']??null)
|
->category(!empty($param['id']) ? $param['id'] : $video_categorys[0]['id']??null)
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
->paginate([
|
->paginate([
|
||||||
'list_rows' => $param['size'],
|
'list_rows' => $param['size'],
|
||||||
@@ -122,6 +132,9 @@ class Attachment extends Common
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (!$videos->isEmpty()) {
|
if (!$videos->isEmpty()) {
|
||||||
|
$videos->each(function($item) {
|
||||||
|
$item->video = url_filesystem_detect($item->video);
|
||||||
|
});
|
||||||
$videos->setCollection($videos->getCollection()->chunk(2));
|
$videos->setCollection($videos->getCollection()->chunk(2));
|
||||||
}
|
}
|
||||||
View::assign('videos', $videos);
|
View::assign('videos', $videos);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class Product extends Common
|
|||||||
->onSale(true)
|
->onSale(true)
|
||||||
->onShelves(true)
|
->onShelves(true)
|
||||||
->append(['p' => $list[0]['id']])
|
->append(['p' => $list[0]['id']])
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'created_at' => 'desc', 'id' => 'desc'])
|
||||||
->limit(5)
|
->limit(5)
|
||||||
->buildSql();
|
->buildSql();
|
||||||
$query = \think\facade\Db::table("($sql) as a");
|
$query = \think\facade\Db::table("($sql) as a");
|
||||||
@@ -126,7 +126,7 @@ class Product extends Common
|
|||||||
->enabled(true)
|
->enabled(true)
|
||||||
->onSale(true)
|
->onSale(true)
|
||||||
->onShelves(true)
|
->onShelves(true)
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'created_at' => 'desc', 'id' => 'desc'])
|
||||||
->limit(5);
|
->limit(5);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ class Product extends Common
|
|||||||
->enabled(true)
|
->enabled(true)
|
||||||
->onSale(true)
|
->onSale(true)
|
||||||
->onShelves(true)
|
->onShelves(true)
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'created_at' => 'desc', 'id' => 'desc'])
|
||||||
->select();
|
->select();
|
||||||
if (!$products->isEmpty()) {
|
if (!$products->isEmpty()) {
|
||||||
// 获取sku信息
|
// 获取sku信息
|
||||||
@@ -277,7 +277,7 @@ class Product extends Common
|
|||||||
'page/d' => 1,
|
'page/d' => 1,
|
||||||
'size/d' => 10
|
'size/d' => 10
|
||||||
]);
|
]);
|
||||||
$keywords = $param['keywords'] ?? '';
|
$keywords = !empty($param['keywords']) ? trim($param['keywords']) : '';
|
||||||
|
|
||||||
// 关键词搜索
|
// 关键词搜索
|
||||||
$products = ProductModel::field([
|
$products = ProductModel::field([
|
||||||
@@ -396,8 +396,11 @@ class Product extends Common
|
|||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
->select()
|
->select()
|
||||||
->hidden(['platform'])
|
->hidden(['platform'])
|
||||||
->bindAttr('platform', ['platform_name' => 'platform'])
|
->bindAttr('platform', ['platform_name' => 'platform', 'platform_sort' => 'sort'])
|
||||||
->toArray();
|
->toArray();
|
||||||
|
// 根据购买链接平台排序
|
||||||
|
$sort_by_arr = array_column($product_purchase_links, 'platform_sort');
|
||||||
|
array_multisort($sort_by_arr, SORT_ASC, $product_purchase_links);
|
||||||
|
|
||||||
// 获取相关产品信息
|
// 获取相关产品信息
|
||||||
$related = ProductRelatedModel::with(['product' => function($query) {
|
$related = ProductRelatedModel::with(['product' => function($query) {
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ class TopicNas extends Common
|
|||||||
->language($this->lang_id)
|
->language($this->lang_id)
|
||||||
->parent($parent)
|
->parent($parent)
|
||||||
->isShow(true)
|
->isShow(true)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
->select();
|
->select();
|
||||||
View::assign('article_categorys', $article_categorys);
|
View::assign('article_categorys', $article_categorys);
|
||||||
|
|
||||||
@@ -256,6 +257,7 @@ class TopicNas extends Common
|
|||||||
->language($this->lang_id)
|
->language($this->lang_id)
|
||||||
->parent($parent)
|
->parent($parent)
|
||||||
->isShow(true)
|
->isShow(true)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
->select();
|
->select();
|
||||||
View::assign('article_categorys', $article_categorys);
|
View::assign('article_categorys', $article_categorys);
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ return [
|
|||||||
'product/search' => [
|
'product/search' => [
|
||||||
'搜索' => 'Search',
|
'搜索' => 'Search',
|
||||||
'请搜索' => 'Please search...',
|
'请搜索' => 'Please search...',
|
||||||
|
'暂无数据' => 'No data',
|
||||||
],
|
],
|
||||||
// 产品详情
|
// 产品详情
|
||||||
'product/detail' => [
|
'product/detail' => [
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ return [
|
|||||||
// 产品 - 产品详情页
|
// 产品 - 产品详情页
|
||||||
'product/detail' => [
|
'product/detail' => [
|
||||||
'首页' => 'Home',
|
'首页' => 'Home',
|
||||||
|
'型号' => 'Product Model',
|
||||||
'产品详情' => 'Product Description',
|
'产品详情' => 'Product Description',
|
||||||
'相关产品' => 'Related Products',
|
'相关产品' => 'Related Products',
|
||||||
'发送查询' => 'Send Inquiry',
|
'发送查询' => 'Send Inquiry',
|
||||||
@@ -177,6 +178,11 @@ return [
|
|||||||
'提交' => 'SUBMIT',
|
'提交' => 'SUBMIT',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// 产品 - 搜索
|
||||||
|
'product/search' => [
|
||||||
|
'暂无数据' => 'No data',
|
||||||
|
],
|
||||||
|
|
||||||
// 产品 - 分类
|
// 产品 - 分类
|
||||||
'product/category' => [
|
'product/category' => [
|
||||||
'查看全部' => 'View All',
|
'查看全部' => 'View All',
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
// 这是系统自动生成的middleware定义文件
|
// 这是系统自动生成的middleware定义文件
|
||||||
return [
|
return [
|
||||||
// 启用多语言支持
|
// 启用多语言支持
|
||||||
think\middleware\LoadLangPack::class,
|
// think\middleware\LoadLangPack::class,
|
||||||
|
app\index\middleware\LoadLangPack::class,
|
||||||
// 确认请求来源
|
// 确认请求来源
|
||||||
app\index\middleware\ConfirmRequestFrom::class,
|
app\index\middleware\ConfirmRequestFrom::class,
|
||||||
];
|
];
|
||||||
|
|||||||
39
app/index/middleware/LoadLangPack.php
Normal file
39
app/index/middleware/LoadLangPack.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\index\middleware;
|
||||||
|
|
||||||
|
use think\Request;
|
||||||
|
|
||||||
|
class LoadLangPack extends \think\middleware\LoadLangPack
|
||||||
|
{
|
||||||
|
// 重写检测语言方法
|
||||||
|
protected function detect(Request $request): string
|
||||||
|
{
|
||||||
|
$domain_detect = env('INDEX_LANG_DETECT.DOMAIN_DETECT', false);
|
||||||
|
if ($domain_detect) {
|
||||||
|
$lang = $this->getLangSet($request, env('INDEX_LANG_DETECT.DOMAIN_RULE', []));
|
||||||
|
if ($lang != '') {
|
||||||
|
return $lang;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::detect($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据请求及规则获取语言
|
||||||
|
private function getLangSet(Request $request, array $rules): string
|
||||||
|
{
|
||||||
|
$map = [];
|
||||||
|
foreach ($rules as $v) {
|
||||||
|
$val = str_replace(',', ',', $v);
|
||||||
|
$item = explode(',', $v);
|
||||||
|
foreach ($item as $val) {
|
||||||
|
$it = explode('=', $val);
|
||||||
|
$map[$it[0]] = $it[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map[$request->host()] ?? '';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
{notempty name="video_categorys"}
|
{notempty name="video_categorys"}
|
||||||
{volist name="video_categorys" id="va"}
|
{volist name="video_categorys" id="va"}
|
||||||
<a href="{:url('attachment/index', ['id' => $va.id])}"><div class="tabit active">{$va.name}</div></a>
|
<a href="{:url('attachment/video', ['id' => $va.id])}"><div class="tabit active">{$va.name}</div></a>
|
||||||
{/volist}
|
{/volist}
|
||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -101,7 +101,7 @@
|
|||||||
<a href="{$sc.link}"><img src="{$sc.image}" /></a>
|
<a href="{$sc.link}"><img src="{$sc.image}" /></a>
|
||||||
<div class="position_a text_center wow animated bounceInLeft">
|
<div class="position_a text_center wow animated bounceInLeft">
|
||||||
<p class="f_weight_500 timetitle" {:style(['color'=>$sc['title_txt_color']])}>{$sc.title}</p>
|
<p class="f_weight_500 timetitle" {:style(['color'=>$sc['title_txt_color']])}>{$sc.title}</p>
|
||||||
<p class=" margin-top-14 f_weight_400 timedesin" {:style(['color'=>$sc['desc_txt_color']])}>{$sc.desc}</p>
|
<p class=" margin-top-14 f_weight_400 timedesin" {:style(['color'=>$sc['desc_txt_color']])}>{$sc.desc|raw}</p>
|
||||||
<p class=" margin-top-20 f_weight_400">
|
<p class=" margin-top-20 f_weight_400">
|
||||||
<a href="{$sc.link}" class="timeblue"> {:lang_i18n('了解更多')} <img src="__IMAGES__/more-r.png"></a>
|
<a href="{$sc.link}" class="timeblue"> {:lang_i18n('了解更多')} <img src="__IMAGES__/more-r.png"></a>
|
||||||
</p>
|
</p>
|
||||||
@@ -141,7 +141,7 @@
|
|||||||
<img src="{$bs.image}">
|
<img src="{$bs.image}">
|
||||||
<div class="position_a text_center">
|
<div class="position_a text_center">
|
||||||
<p class=" timetitle" {:style(['color'=>$bs['title_txt_color']])}>{$bs.title} </p>
|
<p class=" timetitle" {:style(['color'=>$bs['title_txt_color']])}>{$bs.title} </p>
|
||||||
<p class=" margin-top-14 f_weight_400 timedesin" {:style(['color'=>$bs['desc_txt_color']])}>{$bs.desc}</p>
|
<p class=" margin-top-14 f_weight_400 timedesin" {:style(['color'=>$bs['desc_txt_color']])}>{$bs.desc|raw}</p>
|
||||||
<p class=" margin-top-20 f_weight_400">
|
<p class=" margin-top-20 f_weight_400">
|
||||||
<span class=" timeblue">
|
<span class=" timeblue">
|
||||||
<a href="{$bs.link}">{:lang_i18n('了解更多')}<img src="__IMAGES__/more-r.png"></a>
|
<a href="{$bs.link}">{:lang_i18n('了解更多')}<img src="__IMAGES__/more-r.png"></a>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
{volist name="vo.products" id="pro" length="4"}
|
{volist name="vo.products" id="pro" length="4"}
|
||||||
<li class="img-responsive">
|
<li class="img-responsive">
|
||||||
<a href="{:url('product/detail', ['id' => $pro.id])}">
|
<a href="{:url('product/detail', ['id' => $pro.id])}">
|
||||||
<img src="{$pro.cover_image}">
|
<img src="{:thumb($pro.cover_image)}">
|
||||||
<span class="title">{$pro.name}</span>
|
<span class="title">{$pro.name}</span>
|
||||||
<span class="subtitle">{$pro.spu}</span>
|
<span class="subtitle">{$pro.spu}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -22,7 +22,11 @@
|
|||||||
<a class="href_01">{:lang_i18n('首页')}</a>
|
<a class="href_01">{:lang_i18n('首页')}</a>
|
||||||
{volist name="product_categorys" id="ca"}
|
{volist name="product_categorys" id="ca"}
|
||||||
<span class="icon-arrow arrow_address"></span>
|
<span class="icon-arrow arrow_address"></span>
|
||||||
|
{eq name="ca.pid" value="0"}
|
||||||
<a class="href_02" href="{:url('product/category', ['id' => $ca.id])}">{$ca.name}</a>
|
<a class="href_02" href="{:url('product/category', ['id' => $ca.id])}">{$ca.name}</a>
|
||||||
|
{else /}
|
||||||
|
<a class="href_02" href="{:url('product/subcategory', ['id' => $ca.id])}">{$ca.name}</a>
|
||||||
|
{/eq}
|
||||||
{/volist}
|
{/volist}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<div class="prlist">
|
<div class="prlist">
|
||||||
{volist name="products" id="pro"}
|
{volist name="products" id="pro"}
|
||||||
<a class="pritem" href="{:url('product/detail',['id'=>$pro.id])}">
|
<a class="pritem" href="{:url('product/detail',['id'=>$pro.id])}">
|
||||||
<img src="{$pro.cover_image}" class="primg"/>
|
<img src="{:thumb($pro.cover_image)}" class="primg"/>
|
||||||
<div class="prinfo">
|
<div class="prinfo">
|
||||||
<span class="t1">{$pro.name|raw}</span>
|
<span class="t1">{$pro.name|raw}</span>
|
||||||
<span class="t2">{$pro.spu|raw}</span>
|
<span class="t2">{$pro.spu|raw}</span>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<div>{$page|raw}</div>
|
<div>{$page|raw}</div>
|
||||||
{else/}
|
{else/}
|
||||||
<div style="text-align: center; padding: 10%;">暂无数据</div>
|
<div style="text-align: center; padding: 10%;">{:lang_i18n('暂无数据')}</div>
|
||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
<div class="m_Container">
|
<div class="m_Container">
|
||||||
{notempty name="categorys_data"}
|
{notempty name="categorys_data"}
|
||||||
<div class="product_list">
|
<div class="product_list">
|
||||||
|
{if condition="in_array('products', array_keys($categorys_data[0]))"}
|
||||||
<ul>
|
<ul>
|
||||||
{assign name="products" value=":\think\helper\Arr::flatMap(fn($pro) => $pro['products'], $categorys_data)" /}
|
{assign name="products" value=":\think\helper\Arr::flatMap(fn($pro) => $pro['products'], $categorys_data)" /}
|
||||||
{volist name="products" id="pr"}
|
{volist name="products" id="pr"}
|
||||||
@@ -55,6 +56,7 @@
|
|||||||
</li>
|
</li>
|
||||||
{/volist}
|
{/volist}
|
||||||
</ul>
|
</ul>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="__CSS__/public.css" />
|
<link rel="stylesheet" type="text/css" href="__CSS__/public.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="__CSS__/font.css" />
|
<link rel="stylesheet" type="text/css" href="__CSS__/font.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="__CSS__/style.css" />
|
<link rel="stylesheet" type="text/css" href="__CSS__/style.css" />
|
||||||
<!-- <link rel="stylesheet" type="text/css" href="__CSS__/fonts.css" /> -->
|
|
||||||
<link rel="stylesheet" type="text/css" href="__CSS__/header.css" />
|
<link rel="stylesheet" type="text/css" href="__CSS__/header.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="__CSS__/footer.css" />
|
<link rel="stylesheet" type="text/css" href="__CSS__/footer.css" />
|
||||||
{block name="style"}{/block}
|
{block name="style"}{/block}
|
||||||
|
|||||||
@@ -29,12 +29,13 @@
|
|||||||
{/notempty}
|
{/notempty}
|
||||||
<li>
|
<li>
|
||||||
<h3>{:lang_i18n('联系方式')}</h3>
|
<h3>{:lang_i18n('联系方式')}</h3>
|
||||||
{notempty name="contact_config.website_email"}
|
{if condition="!empty($contact_config)"}
|
||||||
<p>{$contact_config.website_email.title}: {$contact_config.website_email.value}</p>
|
{volist name="contact_config" id="vo"}
|
||||||
{/notempty}
|
{if condition="$vo.type != 'image'"}
|
||||||
{notempty name="contact_config.website_hotline_office_hours"}
|
<p>{$vo.value}</p>
|
||||||
<p>{$contact_config.website_hotline_office_hours.title}: {$contact_config.website_hotline_office_hours.value}</p>
|
{/if}
|
||||||
{/notempty}
|
{/volist}
|
||||||
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +65,7 @@
|
|||||||
<div class="copy-text">
|
<div class="copy-text">
|
||||||
{$basic_config.website_powerby.value}
|
{$basic_config.website_powerby.value}
|
||||||
{notempty name="$basic_config.website_icp"}
|
{notempty name="$basic_config.website_icp"}
|
||||||
<a href="https://beian.miit.gov.cn/" style="color:white;">({$basic_config.website_icp.value})</a>
|
<a href="https://beian.miit.gov.cn/" style="color:white;">{$basic_config.website_icp.value|raw}</a>
|
||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
{/notempty}
|
{/notempty}
|
||||||
|
|||||||
@@ -12,6 +12,27 @@
|
|||||||
<span class="icon-category cursor_p top-menu-toggle"><i class="icon-menu-svg"></i></span>
|
<span class="icon-category cursor_p top-menu-toggle"><i class="icon-menu-svg"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 顶部国家选择-->
|
||||||
|
<div class="top-country">
|
||||||
|
<div class="mask"></div>
|
||||||
|
<div class="action-sheet">
|
||||||
|
<div class="menu-title">
|
||||||
|
<div class="menu-name">{:lang_i18n('请择地区')}</div>
|
||||||
|
<div class="close-icon">
|
||||||
|
<img src="__IMAGES__/close.png">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
{volist name="header_languages" id="la"}
|
||||||
|
<li>
|
||||||
|
<a href="{$la.lang_url}" target="_blank">
|
||||||
|
<img src="{$la.lang_icon}">{$la.country_en_name} - {$la.lang_en_name}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{/volist}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 顶部菜单-->
|
<!-- 顶部菜单-->
|
||||||
<div class="top-menu">
|
<div class="top-menu">
|
||||||
@@ -46,7 +67,13 @@
|
|||||||
$(this).siblings('.it-1-2').slideToggle(800);
|
$(this).siblings('.it-1-2').slideToggle(800);
|
||||||
$(this).find('.icon-arrow').addClass('rotate');
|
$(this).find('.icon-arrow').addClass('rotate');
|
||||||
});
|
});
|
||||||
|
// 顶部国家选择
|
||||||
|
$('.top-country-toggle').click(function(){
|
||||||
|
$(".mask,.action-sheet").show();
|
||||||
|
})
|
||||||
|
$('.top-country .close-icon').click(function(){
|
||||||
|
$(".mask,.action-sheet").hide();
|
||||||
|
})
|
||||||
// 移动端顶部宽度设置和主体内容宽度一致
|
// 移动端顶部宽度设置和主体内容宽度一致
|
||||||
var pageWidth = $('.oricoEGapp').outerWidth();
|
var pageWidth = $('.oricoEGapp').outerWidth();
|
||||||
// 设置.header-PC元素的宽度
|
// 设置.header-PC元素的宽度
|
||||||
|
|||||||
@@ -33,14 +33,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 文章内容 -->
|
<!-- 文章内容 -->
|
||||||
<div id="rendered-content" class="nhlp-app-content">
|
<div class="ql-container">
|
||||||
|
<div id="rendered-content" class="nhlp-app-content ql-editor">
|
||||||
{$article.content|raw|default=''}
|
{$article.content|raw|default=''}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<div class="nhlpapp-search">
|
<div class="nhlpapp-search">
|
||||||
<div class="nhlpappshtop">
|
<div class="nhlpappshtop">
|
||||||
<div class="nhlpapp-shdiv">
|
<div class="nhlpapp-shdiv">
|
||||||
<input class="nhlp-ipt" id="search-input" placeholder="{:lang_i18n('请输入搜索关键字,如安装赛博云空间,影视库')}" autocomplete="off">
|
<input class="nhlp-ipt" id="search-input" placeholder="{:lang_i18n('请输入搜索关键字,如安装赛博云空间,影视库')}"
|
||||||
|
autocomplete="off">
|
||||||
<img src="__IMAGES__/ssapp.png" class="searchimg">
|
<img src="__IMAGES__/ssapp.png" class="searchimg">
|
||||||
</div>
|
</div>
|
||||||
<span class="closetx">{:lang_i18n('取消')}</span>
|
<span class="closetx">{:lang_i18n('取消')}</span>
|
||||||
@@ -58,14 +61,16 @@
|
|||||||
<div class="categoryhelp">
|
<div class="categoryhelp">
|
||||||
<div class="categoryhelp-title">
|
<div class="categoryhelp-title">
|
||||||
<div>
|
<div>
|
||||||
<img src="__IMAGES__/nars-jt.png" class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}">
|
<img src="__IMAGES__/nars-jt.png"
|
||||||
|
class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}">
|
||||||
</div>
|
</div>
|
||||||
<span>{$ac.name}</span>
|
<span>{$ac.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<ul class="sub-list" {if condition='$ac.id == $Request.get.cid' }style="display: block;" {/if}>
|
<ul class="sub-list" {if condition='$ac.id == $Request.get.cid' }style="display: block;" {/if}>
|
||||||
{volist name="ac.article" id="ar"}
|
{volist name="ac.article" id="ar"}
|
||||||
<li>
|
<li>
|
||||||
<a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id , 'id' => $ar.id])}" style="padding-top: 6px;">
|
<a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id , 'id' => $ar.id])}"
|
||||||
|
style="padding-top: 6px;">
|
||||||
{$ar.title}
|
{$ar.title}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -77,6 +82,27 @@
|
|||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 顶部国家选择-->
|
||||||
|
<div class="top-country">
|
||||||
|
<div class="mask"></div>
|
||||||
|
<div class="action-sheet">
|
||||||
|
<div class="menu-title">
|
||||||
|
<div class="menu-name">{:lang_i18n('请择地区')}</div>
|
||||||
|
<div class="close-icon">
|
||||||
|
<img src="__IMAGES__/close.png">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
{volist name="header_languages" id="la"}
|
||||||
|
<li>
|
||||||
|
<a href="{$la.lang_url}" target="_blank">
|
||||||
|
<img src="{$la.lang_icon}">{$la.country_en_name} - {$la.lang_en_name}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{/volist}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
@@ -110,6 +136,13 @@
|
|||||||
$('.closetx').click(function () {
|
$('.closetx').click(function () {
|
||||||
$('.nhlpapp-search').hide();
|
$('.nhlpapp-search').hide();
|
||||||
});
|
});
|
||||||
|
// 顶部国家选择
|
||||||
|
$('.top-country-toggle').click(function () {
|
||||||
|
$(".mask,.action-sheet").show();
|
||||||
|
})
|
||||||
|
$('.top-country .close-icon').click(function () {
|
||||||
|
$(".mask,.action-sheet").hide();
|
||||||
|
})
|
||||||
// 搜索
|
// 搜索
|
||||||
var timeout = null;
|
var timeout = null;
|
||||||
$('#search-input').on('focus input', function () {
|
$('#search-input').on('focus input', function () {
|
||||||
@@ -142,6 +175,27 @@
|
|||||||
})
|
})
|
||||||
}, 300);
|
}, 300);
|
||||||
});
|
});
|
||||||
|
// 英文截断处理
|
||||||
|
// 目标容器:富文本内容所在的元素
|
||||||
|
const contentContainer = $('#rendered-content');
|
||||||
|
|
||||||
|
// 遍历所有包含文本内容的标签(p、h1-h6、strong等)
|
||||||
|
contentContainer.find('*').each(function () {
|
||||||
|
const $element = $(this);
|
||||||
|
const htmlContent = $element.html();
|
||||||
|
|
||||||
|
// 条件1:排除内容仅为一个 的标签(如<p> </p>)
|
||||||
|
if (htmlContent.trim() === ' ') {
|
||||||
|
return; // 不处理,继续下一个元素
|
||||||
|
}
|
||||||
|
|
||||||
|
// 条件2:检查是否包含 且有实际文本内容
|
||||||
|
if (htmlContent.includes(' ')) {
|
||||||
|
// 将所有 替换为普通空格(有效占位符,支持单词完整换行)
|
||||||
|
const newContent = htmlContent.replace(/ /g, ' ');
|
||||||
|
$element.html(newContent);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
{block name="main"}
|
{block name="main"}
|
||||||
<div class="orico_Page_achievement">
|
<div class="orico_Page_achievement">
|
||||||
<div class="achievementMain">
|
<div class="achievementMain">
|
||||||
<img src="__IMAGES__/Achievement.png" class="acvImg" />
|
<img src="__IMAGES__/Achievement.webp" class="acvImg" />
|
||||||
<div class="achInfo">
|
<div class="achInfo">
|
||||||
<div class="title">{:lang_i18n('ORICO荣耀')}</div>
|
<div class="title">{:lang_i18n('ORICO荣耀')}</div>
|
||||||
{notempty name="achievement"}
|
{notempty name="achievement"}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@
|
|||||||
<p>{$detail.release_time|date_format_i18n}</p>
|
<p>{$detail.release_time|date_format_i18n}</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- 文本渲染-->
|
<!-- 文本渲染-->
|
||||||
<div class="blog_content">{$detail.content|raw}</div>
|
<div class="ql-container">
|
||||||
|
<div class="blog_content ql-editor">{$detail.content|raw}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 评论只显示前面五条--->
|
<!-- 评论只显示前面五条--->
|
||||||
{notempty name="comments"}
|
{notempty name="comments"}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<form action="{:url('attachment/index')}" method="get">
|
<form action="{:url('attachment/index')}" method="get">
|
||||||
<div class="search_all">
|
<div class="search_all">
|
||||||
<input type="hidden" name="id" value="{$Request.get.id}" />
|
<input type="hidden" name="id" value="{$Request.get.id??$categorys[0]['id']??''}" />
|
||||||
<input type="text" name="keyword" placeholder="{:lang_i18n('搜索')}" />
|
<input type="text" name="keyword" placeholder="{:lang_i18n('搜索')}" />
|
||||||
<button class="searchbtn" type="submit"><img src="__IMAGES__/search_blue.png" /></button>
|
<button class="searchbtn" type="submit"><img src="__IMAGES__/search_blue.png" /></button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<form action="{:url('attachment/video')}" method="get">
|
<form action="{:url('attachment/video')}" method="get">
|
||||||
<div class="search_all">
|
<div class="search_all">
|
||||||
<input type="hidden" name="id" value="{$Request.get.id}" />
|
<input type="hidden" name="id" value="{$Request.get.id??$video_categorys[0]['id']??''}" />
|
||||||
<input type="text" name="keyword" placeholder="{:lang_i18n('搜索')}" />
|
<input type="text" name="keyword" placeholder="{:lang_i18n('搜索')}" />
|
||||||
<button class="searchbtn" type="submit"><img src="__IMAGES__/search_blue.png" /></button>
|
<button class="searchbtn" type="submit"><img src="__IMAGES__/search_blue.png" /></button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -112,13 +112,13 @@
|
|||||||
<div class="sceneIntroduction">
|
<div class="sceneIntroduction">
|
||||||
{volist name="scenes" id="scene"}
|
{volist name="scenes" id="scene"}
|
||||||
<div class="sceneitem">
|
<div class="sceneitem">
|
||||||
<div class="sceneInfo">
|
<a class="sceneInfo" href="{$scene.link}">
|
||||||
<p class="scenetitle" {notempty name="scene.title_txt_color" }style="color:{$scene.title_txt_color};" {/notempty}>{$scene.title}</p>
|
<!-- <p class="scenetitle" {notempty name="scene.title_txt_color" }style="color:{$scene.title_txt_color};" {/notempty}>{$scene.title}</p>
|
||||||
<p class="subtitle" {notempty name="scene.desc_txt_color" }style="color:{$scene.desc_txt_color};" {/notempty}>
|
<p class="subtitle" {notempty name="scene.desc_txt_color" }style="color:{$scene.desc_txt_color};" {/notempty}>
|
||||||
{$scene.desc|raw}</p>
|
{$scene.desc|raw}</p>
|
||||||
<a class="sceneMore" href="{$scene.link}">{:lang_i18n('了解更多')} ></a>
|
<a class="sceneMore" href="{$scene.link}">{:lang_i18n('了解更多')} ></a> -->
|
||||||
</div>
|
|
||||||
<div style="background-image: url('{$scene.image}');" class="sceneimg"></div>
|
<div style="background-image: url('{$scene.image}');" class="sceneimg"></div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{/volist}
|
{/volist}
|
||||||
</div>
|
</div>
|
||||||
@@ -129,10 +129,10 @@
|
|||||||
<span class="otsbtitle">{:lang_i18n('强大功能、简单使用')}</span>
|
<span class="otsbtitle">{:lang_i18n('强大功能、简单使用')}</span>
|
||||||
<div class="beforeafter ba-slider">
|
<div class="beforeafter ba-slider">
|
||||||
<!-- 对比前的图片 -->
|
<!-- 对比前的图片 -->
|
||||||
<img src="__IMAGES__/indeximg1.jpg">
|
<img src="__IMAGES__/indeximg1.webp">
|
||||||
<div class="resize">
|
<div class="resize">
|
||||||
<!-- 对比后的图片 -->
|
<!-- 对比后的图片 -->
|
||||||
<img src="__IMAGES__/indeximg2.jpg">
|
<img src="__IMAGES__/indeximg2.webp">
|
||||||
</div>
|
</div>
|
||||||
<!-- 可拖动的分隔条 -->
|
<!-- 可拖动的分隔条 -->
|
||||||
<span class="handle"></span>
|
<span class="handle"></span>
|
||||||
|
|||||||
@@ -22,7 +22,11 @@
|
|||||||
<a class="pathname" href="/">{:lang_i18n('首页')}</a>
|
<a class="pathname" href="/">{:lang_i18n('首页')}</a>
|
||||||
{volist name="product_categorys" id="ca"}
|
{volist name="product_categorys" id="ca"}
|
||||||
<div class="arrow"></div>
|
<div class="arrow"></div>
|
||||||
|
{eq name="ca.pid" value="0"}
|
||||||
<a class="pathname" href="{:url('product/category', ['id' => $ca.id])}">{$ca.name}</a>
|
<a class="pathname" href="{:url('product/category', ['id' => $ca.id])}">{$ca.name}</a>
|
||||||
|
{else /}
|
||||||
|
<a class="pathname" href="{:url('product/subcategory', ['id' => $ca.id])}">{$ca.name}</a>
|
||||||
|
{/eq}
|
||||||
{/volist}
|
{/volist}
|
||||||
</div>
|
</div>
|
||||||
<!-- 产品主图切换和参数详情-->
|
<!-- 产品主图切换和参数详情-->
|
||||||
@@ -66,6 +70,11 @@
|
|||||||
<p>{$product.short_name|default=''}</p>
|
<p>{$product.short_name|default=''}</p>
|
||||||
<div class="proTfg">
|
<div class="proTfg">
|
||||||
<ul class="swt-Table">
|
<ul class="swt-Table">
|
||||||
|
<li class="Table-Row">
|
||||||
|
<div class="ms3 Table-Cell">{:lang_i18n('型号')}</div>
|
||||||
|
<div class="ms2 Table-Cell"></div>
|
||||||
|
<div class="ms4 Table-Cell">{$product.spu}</div>
|
||||||
|
</li>
|
||||||
{volist name="product_params" id="pp"}
|
{volist name="product_params" id="pp"}
|
||||||
<li class="Table-Row">
|
<li class="Table-Row">
|
||||||
<div class="ms3 Table-Cell">{$pp.name}</div>
|
<div class="ms3 Table-Cell">{$pp.name}</div>
|
||||||
@@ -107,6 +116,7 @@
|
|||||||
{volist name="product_purchase_links" id="ppp" key="k"}
|
{volist name="product_purchase_links" id="ppp" key="k"}
|
||||||
<a class="thebt bttype{$k}" href="{$ppp.link}">{$ppp.platform_name}</a>
|
<a class="thebt bttype{$k}" href="{$ppp.link}">{$ppp.platform_name}</a>
|
||||||
{/volist}
|
{/volist}
|
||||||
|
<br/>
|
||||||
{eq name=":cookie('think_lang')" value="en-us"}
|
{eq name=":cookie('think_lang')" value="en-us"}
|
||||||
<a class="thebt bttype3" id="open_form_modal">{:lang_i18n('发送查询')}</a>
|
<a class="thebt bttype3" id="open_form_modal">{:lang_i18n('发送查询')}</a>
|
||||||
{/eq}
|
{/eq}
|
||||||
@@ -123,10 +133,12 @@
|
|||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
<!-- 富文本渲染-->
|
<!-- 富文本渲染-->
|
||||||
<div class="products_des" id="detail">
|
<div class="ql-container">
|
||||||
|
<div class="products_des ql-editor" id="detail">
|
||||||
{$product.detail|default=''|raw}
|
{$product.detail|default=''|raw}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 关联产品 -->
|
<!-- 关联产品 -->
|
||||||
{notempty name="product_related"}
|
{notempty name="product_related"}
|
||||||
<div class="glcpmain" id="related">
|
<div class="glcpmain" id="related">
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div>{$page|raw}</div>
|
<div>{$page|raw}</div>
|
||||||
{else/}
|
{else/}
|
||||||
<div style="text-align: center; padding: 10%;">暂无数据</div>
|
<div style="text-align: center; padding: 10%;">{:lang_i18n('暂无数据')}</div>
|
||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -92,7 +92,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{eq name=":cookie('think_lang')" value="en-us"}
|
{eq name=":cookie('think_lang')" value="en-us"}
|
||||||
{notempty name="basic_config['navigation_store_url']['value']"}
|
{notempty name="basic_config['navigation_store_url']['value']"}
|
||||||
<a class="storetopbt" href="{$basic_config['navigation_store_url']['value']}">
|
<a class="storetopbt" href="{$basic_config['navigation_store_url']['value']}" target="_blank">
|
||||||
<img src="__IMAGES__/shopico.png" class="storeImgico" />{:lang_i18n('店铺')}
|
<img src="__IMAGES__/shopico.png" class="storeImgico" />{:lang_i18n('店铺')}
|
||||||
</a>
|
</a>
|
||||||
{/notempty}
|
{/notempty}
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
<div class="popmain">
|
<div class="popmain">
|
||||||
{volist name="header_hot_products" id="vo"}
|
{volist name="header_hot_products" id="vo"}
|
||||||
<div class="popitem">
|
<div class="popitem">
|
||||||
<a href="{:url('product/detail', ['id' => $vo.id])}"><img src="{$vo.cover_image}" class="popimg" /></a>
|
<a href="{:url('product/detail', ['id' => $vo.id])}"><img src="{:thumb($vo.cover_image)}" class="popimg" /></a>
|
||||||
<div class="productName">{$vo.name}</div>
|
<div class="productName">{$vo.name}</div>
|
||||||
<div class="produc-dec">{$vo.short_name}</div>
|
<div class="produc-dec">{$vo.short_name}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
<div class="ftcopyright">
|
<div class="ftcopyright">
|
||||||
<span>{$basic_config.website_powerby.value}</span>
|
<span>{$basic_config.website_powerby.value}</span>
|
||||||
{if condition="!empty($basic_config.website_icp)"}
|
{if condition="!empty($basic_config.website_icp)"}
|
||||||
<a href="https://beian.miit.gov.cn/">({$basic_config.website_icp.value})</a>
|
<a href="https://beian.miit.gov.cn/">{$basic_config.website_icp.value|raw}</a>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
<header class="narsPage-head">
|
<header class="narsPage-head">
|
||||||
<div class="headcenter">
|
<div class="headcenter">
|
||||||
|
{eq name=":cookie('think_lang')" value="zh-cn"}
|
||||||
|
<a href="{:url('/index/topic/nas/index')}">
|
||||||
|
{else/}
|
||||||
<a>
|
<a>
|
||||||
|
{/eq}
|
||||||
<img class="logico" style="cursor:pointer;" src="__IMAGES__/logo_nas_{:cookie('think_lang')}.png" />
|
<img class="logico" style="cursor:pointer;" src="__IMAGES__/logo_nas_{:cookie('think_lang')}.png" />
|
||||||
</a>
|
</a>
|
||||||
{notempty name="header_navigation"}
|
{notempty name="header_navigation"}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="narshelpCenterPc">
|
<div class="narshelpCenterPc">
|
||||||
<!-- banner-搜索 -->
|
<!-- banner-搜索 -->
|
||||||
<div class="pagetopbg">
|
<div class="pagetopbg">
|
||||||
<img src="__IMAGES__/nas_help_banner.jpg" class="hpbgimg" />
|
<img src="__IMAGES__/nas_help_banner.webp" class="hpbgimg" />
|
||||||
<div class='nhlp-search'>
|
<div class='nhlp-search'>
|
||||||
<input class="nhlp-ipt" id="search-input" placeholder="{:lang_i18n('请输入搜索关键字,如安装赛博云空间,影视库')}" autocomplete="off" />
|
<input class="nhlp-ipt" id="search-input" placeholder="{:lang_i18n('请输入搜索关键字,如安装赛博云空间,影视库')}" autocomplete="off" />
|
||||||
<img src="__IMAGES__/nas_help_search.png" class="searchimg" />
|
<img src="__IMAGES__/nas_help_search.png" class="searchimg" />
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<h1 class="helph1">{:lang_i18n('使用教程')}</h1>
|
<h1 class="helph1">{:lang_i18n('使用教程')}</h1>
|
||||||
<div class="nhlp-row">
|
<div class="nhlp-row">
|
||||||
{volist name="article_categorys" id="vo" key="idx"}
|
{volist name="article_categorys" id="vo" key="idx"}
|
||||||
<div class="nhlpit {gt name='idx' value='6'}nhlpit-w{/gt}">
|
<div class="nhlpit">
|
||||||
<div class="nhlptl">
|
<div class="nhlptl">
|
||||||
<img src="{$vo.icon}" class="bhlpicoimg" />{$vo.name}
|
<img src="{$vo.icon}" class="bhlpicoimg" />{$vo.name}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -58,7 +58,9 @@
|
|||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
<!--文章详情 -->
|
<!--文章详情 -->
|
||||||
<div class="nars-hlpdt-mm" id="rendered-content">{$article.content|raw|default=''}</div>
|
<div class="ql-container ">
|
||||||
|
<div class="nars-hlpdt-mm ql-editor" id="rendered-content">{$article.content|raw|default=''}</div>
|
||||||
|
</div>
|
||||||
<!--锚点定位 -->
|
<!--锚点定位 -->
|
||||||
<div class="nars-hlpdt-mr">
|
<div class="nars-hlpdt-mr">
|
||||||
<div id="title-list">
|
<div id="title-list">
|
||||||
@@ -119,11 +121,15 @@
|
|||||||
// 内容
|
// 内容
|
||||||
// 清空标题列表
|
// 清空标题列表
|
||||||
$("#title-list ul").empty();
|
$("#title-list ul").empty();
|
||||||
// 提取 h1 标题
|
// 提取 h3 标题
|
||||||
var h1Titles = $("#rendered-content").find("h3");
|
var h1Titles = $("#rendered-content").find("h3");
|
||||||
|
// 只有当找到h3标题且内容不为空时才进行处理
|
||||||
|
if (h1Titles.length > 0) {
|
||||||
h1Titles.each(function (index) {
|
h1Titles.each(function (index) {
|
||||||
var title = $(this);
|
var title = $(this);
|
||||||
var titleText = title.text();
|
var titleText = title.text().trim(); // 使用trim()去除空白字符
|
||||||
|
// 只有当标题文本不为空时才添加到列表
|
||||||
|
if (titleText) {
|
||||||
var titleId = "title-" + index;
|
var titleId = "title-" + index;
|
||||||
title.attr("id", titleId);
|
title.attr("id", titleId);
|
||||||
var listItem = $("<li>");
|
var listItem = $("<li>");
|
||||||
@@ -133,7 +139,9 @@
|
|||||||
});
|
});
|
||||||
listItem.append(link);
|
listItem.append(link);
|
||||||
$("#title-list ul").append(listItem);
|
$("#title-list ul").append(listItem);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
@@ -18,7 +18,7 @@ if (!function_exists('image_domain_concat')) {
|
|||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtrim($domain, '/') . '/' . ltrim($path, '/');
|
return url_join($domain, $path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ if (!function_exists('video_domain_concat')) {
|
|||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtrim($domain, '/') . '/' . ltrim($path, '/');
|
return url_join($domain, $path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ class Authorize
|
|||||||
$server = request()->server();
|
$server = request()->server();
|
||||||
$request = new Request([], $post, [], [], [], $server);
|
$request = new Request([], $post, [], [], [], $server);
|
||||||
$storage = new OAuthStorage;
|
$storage = new OAuthStorage;
|
||||||
$oauth = new OAuth2($storage);
|
$oauth = new OAuth2($storage, [
|
||||||
|
'access_token_lifetime' => intval(env('OPENAPI.ACCESS_TOKEN_LIFETIME', 3600)),
|
||||||
|
'refresh_token_lifetime' => intval(env('OPENAPI.REFRESH_TOKEN_LIFETIME', 1209600)),
|
||||||
|
]);
|
||||||
$token = $oauth->grantAccessToken($request);
|
$token = $oauth->grantAccessToken($request);
|
||||||
return success('success', json_decode($token->getContent(), true));
|
return success('success', json_decode($token->getContent(), true));
|
||||||
} catch (OAuth2ServerException $e) {
|
} catch (OAuth2ServerException $e) {
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ class Auth
|
|||||||
public function handle($request, \Closure $next)
|
public function handle($request, \Closure $next)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$oauth = new OAuth2(new OAuthStorage);
|
$oauth = new OAuth2(new OAuthStorage, [
|
||||||
|
'access_token_lifetime' => intval(env('OPENAPI.ACCESS_TOKEN_LIFETIME', 3600)),
|
||||||
|
'refresh_token_lifetime' => intval(env('OPENAPI.REFRESH_TOKEN_LIFETIME', 1209600)),
|
||||||
|
]);
|
||||||
$token = $oauth->getBearerToken();
|
$token = $oauth->getBearerToken();
|
||||||
$oauth->verifyAccessToken($token);
|
$oauth->verifyAccessToken($token);
|
||||||
} catch (OAuth2ServerException $e) {
|
} catch (OAuth2ServerException $e) {
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ class OAuthClientModel extends Model
|
|||||||
'client_secret' => 'string',
|
'client_secret' => 'string',
|
||||||
'redirect_uri' => 'string',
|
'redirect_uri' => 'string',
|
||||||
'enabled' => 'int',
|
'enabled' => 'int',
|
||||||
|
'expired_at' => 'datetime',
|
||||||
|
'remark' => 'string',
|
||||||
'created_at' => 'datetime',
|
'created_at' => 'datetime',
|
||||||
'updated_at' => 'datetime',
|
'updated_at' => 'datetime',
|
||||||
'deleted_at' => 'datetime'
|
'deleted_at' => 'datetime'
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ Route::group('v1', function() {
|
|||||||
->middleware(\app\openapi\middleware\Auth::class);
|
->middleware(\app\openapi\middleware\Auth::class);
|
||||||
})
|
})
|
||||||
->middleware(\think\middleware\Throttle::class, [
|
->middleware(\think\middleware\Throttle::class, [
|
||||||
|
'prefix' => 'throttle_',
|
||||||
'visit_rate' => '5/m',
|
'visit_rate' => '5/m',
|
||||||
|
'key' => function($throttle, $request) {
|
||||||
|
return '__CONTROLLER__/__ACTION__/__IP__';
|
||||||
|
},
|
||||||
'visit_fail_response' => function (\think\middleware\Throttle $throttle, \think\Request $request, int $wait_seconds) {
|
'visit_fail_response' => function (\think\middleware\Throttle $throttle, \think\Request $request, int $wait_seconds) {
|
||||||
return \think\Response::create('您的操作过于频繁, 请在 ' . $wait_seconds . ' 秒后再试。')->code(429);
|
return \think\Response::create('您的操作过于频繁, 请在 ' . $wait_seconds . ' 秒后再试。')->code(429);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.0.0",
|
"php": ">=8.0.0",
|
||||||
"topthink/framework": "^8.0",
|
"topthink/framework": "8.1.2",
|
||||||
"topthink/think-orm": "v3.0.34",
|
"topthink/think-orm": "v3.0.34",
|
||||||
"topthink/think-filesystem": "^2.0",
|
"topthink/think-filesystem": "^3.0",
|
||||||
"topthink/think-multi-app": "^1.1",
|
"topthink/think-multi-app": "^1.1",
|
||||||
"topthink/think-migration": "^3.1",
|
"topthink/think-migration": "^3.1",
|
||||||
"topthink/think-view": "^2.0",
|
"topthink/think-view": "^2.0",
|
||||||
@@ -34,7 +34,8 @@
|
|||||||
"topthink/think-cors": "^1.0",
|
"topthink/think-cors": "^1.0",
|
||||||
"phpoffice/phpspreadsheet": "^3.8",
|
"phpoffice/phpspreadsheet": "^3.8",
|
||||||
"friendsofsymfony/oauth2-php": "^1.3",
|
"friendsofsymfony/oauth2-php": "^1.3",
|
||||||
"mobiledetect/mobiledetectlib": "4.8.09"
|
"mobiledetect/mobiledetectlib": "4.8.09",
|
||||||
|
"qiniu/php-sdk": "^7.14"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"symfony/var-dumper": ">=4.2",
|
"symfony/var-dumper": ">=4.2",
|
||||||
|
|||||||
@@ -39,6 +39,60 @@ return [
|
|||||||
// 可见性
|
// 可见性
|
||||||
'visibility' => 'public',
|
'visibility' => 'public',
|
||||||
],
|
],
|
||||||
|
'public_qiniu' => [
|
||||||
|
// 磁盘类型
|
||||||
|
'type' => \filesystem\driver\Qiniu::class,
|
||||||
|
// bucker 名称
|
||||||
|
'bucket' => env('QINIU_CLOUD.BUCKET', 'orico-official-website'),
|
||||||
|
// 访问密钥
|
||||||
|
'access_key' => env('QINIU_CLOUD.ACCESS_KEY', 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms'),
|
||||||
|
// 密钥
|
||||||
|
'secret_key' => env('QINIU_CLOUD.SECRET_KEY', 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q'),
|
||||||
|
// 外部URL
|
||||||
|
'base_url' => env('QINIU_CLOUD.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' => env('QINIU_CLOUD.BUCKET', 'orico-official-website'),
|
||||||
|
// 访问密钥
|
||||||
|
'access_key' => env('QINIU_CLOUD.ACCESS_KEY', 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms'),
|
||||||
|
// 密钥
|
||||||
|
'secret_key' => env('QINIU_CLOUD.SECRET_KEY', 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q'),
|
||||||
|
// 外部URL
|
||||||
|
'base_url' => env('QINIU_CLOUD.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;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
]
|
||||||
// 更多的磁盘配置信息
|
// 更多的磁盘配置信息
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class CreateVideo extends Migrator
|
|||||||
$table = $this->table('video', ['engine' => 'MyISAM', 'comment' => '视频表']);
|
$table = $this->table('video', ['engine' => 'MyISAM', 'comment' => '视频表']);
|
||||||
$table->addColumn('language_id', 'integer', ['signed' => false , 'null' => false, 'comment' => '语言ID'])
|
$table->addColumn('language_id', 'integer', ['signed' => false , 'null' => false, 'comment' => '语言ID'])
|
||||||
->addColumn('category_id', 'integer', ['signed' => false , 'null' => false, 'comment' => '分类ID'])
|
->addColumn('category_id', 'integer', ['signed' => false , 'null' => false, 'comment' => '分类ID'])
|
||||||
->addColumn('name', 'string', ['limit' => 64 , 'null' => false, 'comment' => '名称'])
|
->addColumn('name', 'string', ['limit' => 128 , 'null' => false, 'comment' => '名称'])
|
||||||
->addColumn('desc', 'string', ['limit' => 512, 'null' => true, 'default' => null, 'comment' => '描述信息'])
|
->addColumn('desc', 'string', ['limit' => 512, 'null' => true, 'default' => null, 'comment' => '描述信息'])
|
||||||
->addColumn('image', 'string', ['limit' => 125, 'null' => true, 'default' => null, 'comment' => '封面图片'])
|
->addColumn('image', 'string', ['limit' => 125, 'null' => true, 'default' => null, 'comment' => '封面图片'])
|
||||||
->addColumn('video', 'string', ['limit' => 125, 'null' => true, 'default' => null, 'comment' => '视频地址'])
|
->addColumn('video', 'string', ['limit' => 125, 'null' => true, 'default' => null, 'comment' => '视频地址'])
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class CreateSysBannerItem extends Migrator
|
|||||||
->addColumn('extra_image', 'string', ['limit' => 255, 'null' => true, 'default' => null, 'comment' => '额外的图片'])
|
->addColumn('extra_image', 'string', ['limit' => 255, 'null' => true, 'default' => null, 'comment' => '额外的图片'])
|
||||||
->addColumn('video', 'string', ['limit' => 255, 'null' => true, 'default' => null, 'comment' => '视频'])
|
->addColumn('video', 'string', ['limit' => 255, 'null' => true, 'default' => null, 'comment' => '视频'])
|
||||||
->addColumn('link_to', 'string', ['limit' => 64, 'null' => true, 'default' => null, 'comment' => '链接到(类型): article:文章, article_category:文章分类, product:产品, product_category:产品分类, custom:自定义链接'])
|
->addColumn('link_to', 'string', ['limit' => 64, 'null' => true, 'default' => null, 'comment' => '链接到(类型): article:文章, article_category:文章分类, product:产品, product_category:产品分类, custom:自定义链接'])
|
||||||
->addColumn('link', 'string', ['limit' => 255, 'null' => true, 'default' => null, 'comment' => '链接'])
|
->addColumn('link', 'string', ['limit' => 510, 'null' => true, 'default' => null, 'comment' => '链接'])
|
||||||
->addColumn('sort', 'integer', ['limit' => 11, 'null' => false, 'default' => 0, 'comment' => '排序'])
|
->addColumn('sort', 'integer', ['limit' => 11, 'null' => false, 'default' => 0, 'comment' => '排序'])
|
||||||
->addColumn('status', 'boolean', ['limit' => 1, 'null' => false, 'default' => 1, 'comment' => '-1为禁用, 1为启用'])
|
->addColumn('status', 'boolean', ['limit' => 1, 'null' => false, 'default' => 1, 'comment' => '-1为禁用, 1为启用'])
|
||||||
->addColumn('created_at', 'timestamp', ['null' => false, 'default' =>'CURRENT_TIMESTAMP', 'comment' => '创建时间'])
|
->addColumn('created_at', 'timestamp', ['null' => false, 'default' =>'CURRENT_TIMESTAMP', 'comment' => '创建时间'])
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ class SysConfigInit extends Seeder
|
|||||||
["id" => 13, "group_id" => 7, "title" => "热线在线时段", "name" => "website_hotline_office_hours", "value" => "周一至周五:东部时间 9:00 - 18:00", "extra" => "", "type" => "textarea", "sort" => 2, "remark" => "售后与技术支持热线在线时段", "created_at" => "2025-04-08 16:11:10", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 13, "group_id" => 7, "title" => "热线在线时段", "name" => "website_hotline_office_hours", "value" => "周一至周五:东部时间 9:00 - 18:00", "extra" => "", "type" => "textarea", "sort" => 2, "remark" => "售后与技术支持热线在线时段", "created_at" => "2025-04-08 16:11:10", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
["id" => 14, "group_id" => 7, "title" => "售后与技术支持热线", "name" => "website_hotline_number", "value" => "售后与技术支持热线:400-6696-298", "extra" => "", "type" => "textarea", "sort" => 3, "remark" => "售后与技术支持热线号码", "created_at" => "2025-04-08 16:12:05", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 14, "group_id" => 7, "title" => "售后与技术支持热线", "name" => "website_hotline_number", "value" => "售后与技术支持热线:400-6696-298", "extra" => "", "type" => "textarea", "sort" => 3, "remark" => "售后与技术支持热线号码", "created_at" => "2025-04-08 16:12:05", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
["id" => 15, "group_id" => 7, "title" => "微信公众号二维码", "name" => "website_wx_qrcode", "value" => "/storage/images/webSet/20250408/073545e4b54f4f97c7c790498014d6a0.png", "extra" => "width:126px;height:126px;", "type" => "image", "sort" => 4, "remark" => "微信公众号二维码", "created_at" => "2025-04-08 16:13:58", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 15, "group_id" => 7, "title" => "微信公众号二维码", "name" => "website_wx_qrcode", "value" => "/storage/images/webSet/20250408/073545e4b54f4f97c7c790498014d6a0.png", "extra" => "width:126px;height:126px;", "type" => "image", "sort" => 4, "remark" => "微信公众号二维码", "created_at" => "2025-04-08 16:13:58", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
["id" => 16, "group_id" => 8, "title" => "Technical Support", "name" => "website_technical_support_email", "value" => "Technical Support:supports@orico.com.cn1", "extra" => "", "type" => "text", "sort" => 1, "remark" => "", "created_at" => "2025-04-08 16:18:24", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 16, "group_id" => 8, "title" => "Technical Support", "name" => "website_technical_support_email", "value" => "Technical Support:supports@orico.com.cn", "extra" => "", "type" => "text", "sort" => 1, "remark" => "", "created_at" => "2025-04-08 16:18:24", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 17, "group_id" => 8, "title" => "Business", "name" => "website_business_email", "value" => "Business:oversea-bu@orico.com.cn1", "extra" => "", "type" => "text", "sort" => 2, "remark" => "", "created_at" => "2025-04-08 16:20:12", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 17, "group_id" => 8, "title" => "Business", "name" => "website_business_email", "value" => "Business:oversea-bu@orico.com.cn", "extra" => "", "type" => "text", "sort" => 2, "remark" => "", "created_at" => "2025-04-08 16:20:12", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 18, "group_id" => 8, "title" => "ODM/OEM Service", "name" => "website_ODM/OEM_service_email", "value" => "ODM/OEM Service:odmmarket@orico.com.cn1", "extra" => "", "type" => "text", "sort" => 3, "remark" => "", "created_at" => "2025-04-08 16:27:00", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 18, "group_id" => 8, "title" => "ODM/OEM Service", "name" => "website_ODM/OEM_service_email", "value" => "ODM/OEM Service:odmmarket@orico.com.cn", "extra" => "", "type" => "text", "sort" => 3, "remark" => "", "created_at" => "2025-04-08 16:27:00", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 19, "group_id" => 8, "title" => "Monday-Friday", "name" => "website_hotline_office_hours", "value" => "Monday-Friday,9a.m.-6p.m.GMT+81", "extra" => "", "type" => "text", "sort" => 4, "remark" => "", "created_at" => "2025-04-08 16:28:52", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 19, "group_id" => 8, "title" => "Monday-Friday", "name" => "website_hotline_office_hours", "value" => "Monday-Friday,9a.m.-6p.m.GMT+81", "extra" => "", "type" => "text", "sort" => 4, "remark" => "", "created_at" => "2025-04-08 16:28:52", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 20, "group_id" => 9, "title" => "知呼Icon", "name" => "website_media_zhihu.image", "value" => "/storage/images/webSet/20250408/45ef8e4863d63620ab903cf6557c3469.png", "extra" => "width:30px;height:30px;", "type" => "image", "sort" => 1, "remark" => "", "created_at" => "2025-04-08 16:45:57", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 20, "group_id" => 9, "title" => "知呼Icon", "name" => "website_media_zhihu.image", "value" => "/storage/images/webSet/20250408/45ef8e4863d63620ab903cf6557c3469.png", "extra" => "width:30px;height:30px;", "type" => "image", "sort" => 1, "remark" => "", "created_at" => "2025-04-08 16:45:57", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
["id" => 21, "group_id" => 9, "title" => "小红书Icon", "name" => "website_media_xiaohongshu.image", "value" => "/storage/images/webSet/20250408/120f13d01c89864fd20df0e24212c214.png", "extra" => "width:30px;height:30px;", "type" => "image", "sort" => 3, "remark" => "", "created_at" => "2025-04-08 16:46:40", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 21, "group_id" => 9, "title" => "小红书Icon", "name" => "website_media_xiaohongshu.image", "value" => "/storage/images/webSet/20250408/120f13d01c89864fd20df0e24212c214.png", "extra" => "width:30px;height:30px;", "type" => "image", "sort" => 3, "remark" => "", "created_at" => "2025-04-08 16:46:40", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
@@ -78,7 +78,7 @@ class SysConfigInit extends Seeder
|
|||||||
["id" => 61, "group_id" => 1, "title" => "导航位置店铺URL", "name" => "navigation_store_url", "value" => "https://oricotechs.com/", "extra" => null, "type" => "text", "sort" => 6, "remark" => null, "created_at" => "2025-05-13 17:45:46", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 61, "group_id" => 1, "title" => "导航位置店铺URL", "name" => "navigation_store_url", "value" => "https://oricotechs.com/", "extra" => null, "type" => "text", "sort" => 6, "remark" => null, "created_at" => "2025-05-13 17:45:46", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
["id" => 62, "group_id" => 4, "title" => "导航位置店铺URL", "name" => "navigation_store_url", "value" => "https://oricotechs.com/", "extra" => null, "type" => "text", "sort" => 6, "remark" => null, "created_at" => "2025-05-13 17:45:46", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 62, "group_id" => 4, "title" => "导航位置店铺URL", "name" => "navigation_store_url", "value" => "https://oricotechs.com/", "extra" => null, "type" => "text", "sort" => 6, "remark" => null, "created_at" => "2025-05-13 17:45:46", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 63, "group_id" => 7, "title" => "邮箱", "name" => "website_email", "value" => "supports@orico.com.cn", "extra" => null, "type" => "text", "sort" => 1, "remark" => null, "created_at" => "2025-05-23 17:06:53", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 63, "group_id" => 7, "title" => "邮箱", "name" => "website_email", "value" => "supports@orico.com.cn", "extra" => null, "type" => "text", "sort" => 1, "remark" => null, "created_at" => "2025-05-23 17:06:53", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
["id" => 64, "group_id" => 8, "title" => "Technical Support", "name" => "website_email", "value" => "supports@orico.com.cn1", "extra" => null, "type" => "text", "sort" => 1, "remark" => null, "created_at" => "2025-05-23 17:06:53", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 64, "group_id" => 8, "title" => "Technical Support", "name" => "website_email", "value" => "supports@orico.com.cn", "extra" => null, "type" => "text", "sort" => 1, "remark" => null, "created_at" => "2025-05-23 17:06:53", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 65, "group_id" => 3, "title" => "是否开启", "name" => "watermark_enabled", "value" => "0", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 1, "remark" => "", "created_at" => "2025-06-10 15:41:54", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 65, "group_id" => 3, "title" => "是否开启", "name" => "watermark_enabled", "value" => "0", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 1, "remark" => "", "created_at" => "2025-06-10 15:41:54", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
["id" => 66, "group_id" => 3, "title" => "类型", "name" => "watermark_type", "value" => "TEXT", "extra" => "TEXT:文本['watermark_text_value','watermark_text_font','watermark_text_size','watermark_text_color']\nIMAGE:图片['watermark_image_value','watermark_image_width','watermark_image_height']", "type" => "radio", "sort" => 2, "remark" => "", "created_at" => "2025-06-10 15:44:15", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 66, "group_id" => 3, "title" => "类型", "name" => "watermark_type", "value" => "TEXT", "extra" => "TEXT:文本['watermark_text_value','watermark_text_font','watermark_text_size','watermark_text_color']\nIMAGE:图片['watermark_image_value','watermark_image_width','watermark_image_height']", "type" => "radio", "sort" => 2, "remark" => "", "created_at" => "2025-06-10 15:44:15", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
["id" => 67, "group_id" => 3, "title" => "水印文本", "name" => "watermark_text_value", "value" => "ORICO", "extra" => "", "type" => "text", "sort" => 3, "remark" => "中文情况下,请确认字体支持中文", "created_at" => "2025-06-10 15:48:38", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 67, "group_id" => 3, "title" => "水印文本", "name" => "watermark_text_value", "value" => "ORICO", "extra" => "", "type" => "text", "sort" => 3, "remark" => "中文情况下,请确认字体支持中文", "created_at" => "2025-06-10 15:48:38", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
@@ -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" => 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" => 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" => 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');
|
$table = $this->table('sys_config');
|
||||||
|
|||||||
295
extend/filesystem/adapter/QiniuAdapter.php
Normal file
295
extend/filesystem/adapter/QiniuAdapter.php
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
<?php
|
||||||
|
namespace filesystem\adapter;
|
||||||
|
|
||||||
|
use League\Flysystem\Config;
|
||||||
|
use League\Flysystem\FilesystemAdapter;
|
||||||
|
use League\Flysystem\FileAttributes;
|
||||||
|
use League\Flysystem\UnableToCopyFile;
|
||||||
|
use League\Flysystem\UnableToDeleteFile;
|
||||||
|
use League\Flysystem\UnableToMoveFile;
|
||||||
|
use League\Flysystem\UnableToReadFile;
|
||||||
|
use League\Flysystem\UnableToRetrieveMetadata;
|
||||||
|
use League\Flysystem\UnableToSetVisibility;
|
||||||
|
use League\Flysystem\UnableToWriteFile;
|
||||||
|
use Qiniu\Auth;
|
||||||
|
use Qiniu\Storage\UploadManager;
|
||||||
|
use Qiniu\Storage\BucketManager;
|
||||||
|
|
||||||
|
class QiniuAdapter implements FilesystemAdapter
|
||||||
|
{
|
||||||
|
protected ?Auth $authMgr;
|
||||||
|
protected ?UploadManager $uploadMgr;
|
||||||
|
protected ?BucketManager $bucketMgr;
|
||||||
|
|
||||||
|
public function __construct(protected string $access_key, protected string $secret_key, protected string $bucket, protected string $base_url, protected string $path)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAuthMgr(): Auth
|
||||||
|
{
|
||||||
|
return $this->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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
extend/filesystem/driver/Qiniu.php
Normal file
56
extend/filesystem/driver/Qiniu.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
namespace filesystem\driver;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use filesystem\adapter\QiniuAdapter;
|
||||||
|
use League\Flysystem\FilesystemAdapter;
|
||||||
|
|
||||||
|
class Qiniu extends \think\filesystem\Driver
|
||||||
|
{
|
||||||
|
protected function createAdapter(): FilesystemAdapter
|
||||||
|
{
|
||||||
|
return new QiniuAdapter(
|
||||||
|
$this->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,15 +78,18 @@ class OAuthStorage implements IOAuth2GrantCode, IOAuth2RefreshTokens, IOAuth2Gra
|
|||||||
public function getClient($client_id): IOAuth2Client
|
public function getClient($client_id): IOAuth2Client
|
||||||
{
|
{
|
||||||
// 实现获取客户端的逻辑
|
// 实现获取客户端的逻辑
|
||||||
$ret = OAuthClientModel::clientId($client_id)->find();
|
$client = OAuthClientModel::clientId($client_id)->find();
|
||||||
if (is_null($ret)) {
|
if (is_null($client)) {
|
||||||
throw new \Exception('客户端不存在');
|
throw new \Exception('客户端不存在');
|
||||||
}
|
}
|
||||||
if ($ret->enabled != 1) {
|
if ($client->enabled != 1) {
|
||||||
throw new \Exception('客户端已禁用');
|
throw new \Exception('客户端已禁用');
|
||||||
}
|
}
|
||||||
|
if (strtotime($client->expired_at) < time()) {
|
||||||
|
throw new \Exception('client_id 授权已过期');
|
||||||
|
}
|
||||||
|
|
||||||
return new OAuth2Client($ret->client_id, $ret->client_secret, [$ret->redirect_uri]);
|
return new OAuth2Client($client->client_id, $client->client_secret, [$client->redirect_uri]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkClientCredentials(IOAuth2Client $client, $client_secret = null): bool
|
public function checkClientCredentials(IOAuth2Client $client, $client_secret = null): bool
|
||||||
@@ -96,6 +99,9 @@ class OAuthStorage implements IOAuth2GrantCode, IOAuth2RefreshTokens, IOAuth2Gra
|
|||||||
if (is_null($client)) {
|
if (is_null($client)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (strtotime($client->expired_at) < time()) {
|
||||||
|
throw new \Exception('client_id 授权已过期');
|
||||||
|
}
|
||||||
|
|
||||||
return $client->client_secret == hash('sha1', $client->client_id . $client_secret . $this->salt);
|
return $client->client_secret == hash('sha1', $client->client_id . $client_secret . $this->salt);
|
||||||
}
|
}
|
||||||
|
|||||||
2
public/migrate_temp_images/.gitignore
vendored
2
public/migrate_temp_images/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: Montserrat-Bold, Montserrat;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
width: 212px;
|
/* width: 212px; */
|
||||||
/* height: 48px; */
|
/* height: 48px; */
|
||||||
padding: 15px 60px;
|
padding: 15px 60px;
|
||||||
background: #004bfa;
|
background: #004bfa;
|
||||||
|
|||||||
@@ -138,7 +138,7 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: Montserrat-Bold, Montserrat;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
width: 212px;
|
/* width: 212px; */
|
||||||
padding: 15px 60px;
|
padding: 15px 60px;
|
||||||
background: #004bfa;
|
background: #004bfa;
|
||||||
border-radius: 28px;
|
border-radius: 28px;
|
||||||
|
|||||||
@@ -200,11 +200,11 @@
|
|||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
padding-bottom: 0.5625rem;
|
padding-bottom: 0.5625rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
width: 70%;
|
/* width: 70%; */
|
||||||
white-space: nowrap;
|
/* white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
text-align: center;
|
text-align: center; */
|
||||||
|
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .narskfPage .narskf-content .narskf-ct-row .narskfit .narskf-sm {
|
.oricoEGapp-Contact .narskfPage .narskf-content .narskf-ct-row .narskfit .narskf-sm {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -101,7 +101,7 @@ address {
|
|||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
word-break: break-all;
|
/* word-break: break-all; */
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@@ -1278,7 +1278,7 @@ video img {
|
|||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
.foot-cate li {
|
.foot-cate li {
|
||||||
width: 50%;
|
min-width: 50%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
float: left;
|
float: left;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -2342,6 +2342,59 @@ video img {
|
|||||||
margin-bottom: 1.3rem;
|
margin-bottom: 1.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.products_des {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
.products_des img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.de_t_n {
|
||||||
|
font-size: 1.5em;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.detail_title {
|
||||||
|
text-align: center;
|
||||||
|
padding: 2% 0;
|
||||||
|
}
|
||||||
|
.detail_title p {
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
.detail_con_a {
|
||||||
|
margin: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.lj_detail_text,
|
||||||
|
.lj_detail_texts {
|
||||||
|
font-size: 0.875em;
|
||||||
|
}
|
||||||
|
.lj_detail_text p {
|
||||||
|
line-height: 1.6em;
|
||||||
|
padding: 0.5% 0;
|
||||||
|
}
|
||||||
|
/*seo-pro*/
|
||||||
|
.seo-pro h3 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
color: #333;
|
||||||
|
margin: 2% 0 1%;
|
||||||
|
line-height: 1.2;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.seo-pro p {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 0 11px;
|
||||||
|
}
|
||||||
|
.seo-pro a {
|
||||||
|
color: #333;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.sa_blue,
|
||||||
|
.sa_blue a,
|
||||||
|
.seo-pro a:hover {
|
||||||
|
color: #009fdf;
|
||||||
|
}
|
||||||
|
|
||||||
/*两列*/
|
/*两列*/
|
||||||
.list_two {
|
.list_two {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.narshelpCenterdetail-app .headtop .logoicoimg {
|
.narshelpCenterdetail-app .headtop .logoicoimg {
|
||||||
@@ -39,9 +40,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.narshelpCenterdetail-app .nhlp-app-content {
|
.narshelpCenterdetail-app .nhlp-app-content {
|
||||||
margin: 1.25rem;
|
/* margin: 1rem; */
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-top: 9.2vh;
|
margin-top: 9.2vh;
|
||||||
|
width: 90%;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-top: 5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.narshelpCenterdetail-app #rendered-content img {
|
.narshelpCenterdetail-app #rendered-content img {
|
||||||
@@ -51,7 +55,7 @@
|
|||||||
|
|
||||||
.narshelpCenterdetail-app .nhlpapp-search {
|
.narshelpCenterdetail-app .nhlpapp-search {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 2;
|
z-index: 12;
|
||||||
top: 0;
|
top: 0;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -40,11 +40,11 @@
|
|||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
padding-top: 1.6875rem;
|
padding-top: 1.6875rem;
|
||||||
padding-bottom: 0.375rem;
|
padding-bottom: 0.375rem;
|
||||||
width: 70%;
|
/* width: 70%; */
|
||||||
white-space: nowrap;
|
/* white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
text-align: center;
|
text-align: center; */
|
||||||
}
|
}
|
||||||
.narskfPage .narskf-content .narskf-ct-row .narskfit .narskf-sm {
|
.narskfPage .narskf-content .narskf-ct-row .narskfit .narskf-sm {
|
||||||
color: #9a9a9a;
|
color: #9a9a9a;
|
||||||
|
|||||||
@@ -361,7 +361,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 34rem;
|
height: 37rem;
|
||||||
margin-bottom: 1%;
|
margin-bottom: 1%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,15 +530,18 @@
|
|||||||
width: 50%;
|
width: 50%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-radius: 1.625rem;
|
border-radius: 1.625rem;
|
||||||
height: 42.625rem;
|
/* height: 42.625rem; */
|
||||||
transition: transform 0.3s ease-in-out;
|
transition: transform 0.3s ease-in-out;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.orico_Page_index .pageMain .brandStory .swiper-wrapper .bsitem .itmImg .bsImg {
|
.orico_Page_index .pageMain .brandStory .swiper-wrapper .bsitem .itmImg .bsImg {
|
||||||
margin-left: 1%;
|
margin-left: 1%;
|
||||||
border-radius: 26px 26px 26px 26px;
|
border-radius: 26px 26px 26px 26px;
|
||||||
width: 98%;
|
width: 98%;
|
||||||
height: 41.625rem;
|
/* height: 41.625rem; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.orico_Page_index .pageMain .brandStory .swiper-wrapper .bsitem .bsinf {
|
.orico_Page_index .pageMain .brandStory .swiper-wrapper .bsitem .bsinf {
|
||||||
@@ -910,6 +913,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
max-width: var(--max-width);
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.orico_Page_index .pageMain .oricofixd-info .ofiinfo {
|
.orico_Page_index .pageMain .oricofixd-info .ofiinfo {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
.header-PC #header {
|
.header-PC #header {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
height: 3.75rem;
|
height: 3.75rem;
|
||||||
width: 100%;
|
max-width: var(--max-width);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
z-index: 999;
|
z-index: 999;
|
||||||
background: white;
|
background: white;
|
||||||
color: black;
|
color: black;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
.header-PC #header .nav1 {
|
.header-PC #header .nav1 {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -211,6 +212,7 @@
|
|||||||
.header-PC #header .nav3 .choesCountry {
|
.header-PC #header .nav3 .choesCountry {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-left: 15%;
|
margin-left: 15%;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
.header-PC #header .nav3 .choesCountry .topCountry {
|
.header-PC #header .nav3 .choesCountry .topCountry {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -410,7 +410,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.orico_Page_prdetail .oriprdetail .oriprInfo img {
|
.orico_Page_prdetail .oriprdetail .oriprInfo img {
|
||||||
max-width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.orico_Page_prdetail .oriprdetail .oriprInfo .titleprinfo {
|
.orico_Page_prdetail .oriprdetail .oriprInfo .titleprinfo {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -608,13 +608,13 @@
|
|||||||
.scrollbutton_01.smallImgUp,
|
.scrollbutton_01.smallImgUp,
|
||||||
.scrollbutton_01.smallImgUp.disabled {
|
.scrollbutton_01.smallImgUp.disabled {
|
||||||
background: url(/static/index/pc/images/fl.png);
|
background: url(/static/index/pc/images/fl.png);
|
||||||
left: 0px;
|
left: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scrollbutton_01.smallImgDown,
|
.scrollbutton_01.smallImgDown,
|
||||||
.scrollbutton_01.smallImgDown.disabled {
|
.scrollbutton_01.smallImgDown.disabled {
|
||||||
background: url(/static/index/pc/images/rh.png);
|
background: url(/static/index/pc/images/rh.png);
|
||||||
right: 0px;
|
right: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scrollbutton.smallImgUp,
|
.scrollbutton.smallImgUp,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -89,7 +89,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.narshzhbPage .narshzhb-topinfo .narshzhb-topinfo-main .narshzhb-tif-top .hzcp1 {
|
.narshzhbPage .narshzhb-topinfo .narshzhb-topinfo-main .narshzhb-tif-top .hzcp1 {
|
||||||
width: 46.875rem;
|
/* width: 46.875rem; */
|
||||||
height: 22.5rem;
|
height: 22.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: #f9f9f9;
|
background: #f9f9f9;
|
||||||
}
|
}
|
||||||
|
.narshelpdetailPc .ql-container{
|
||||||
|
width: 81%;
|
||||||
|
}
|
||||||
.narshelpdetailPc .narsssmain {
|
.narshelpdetailPc .narsssmain {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -171,6 +173,7 @@
|
|||||||
.narshelpdetailPc .nars-help-content .nars-hlpdt-ml .sub-list li a.active {
|
.narshelpdetailPc .nars-help-content .nars-hlpdt-ml .sub-list li a.active {
|
||||||
color: #1f2635;
|
color: #1f2635;
|
||||||
border-bottom: 1px solid #1f2635;
|
border-bottom: 1px solid #1f2635;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.narshelpdetailPc .nars-help-content .nars-hlpdt-mm {
|
.narshelpdetailPc .nars-help-content .nars-hlpdt-mm {
|
||||||
@@ -181,6 +184,9 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
}
|
||||||
|
.narshelpdetailPc .nars-help-content .nars-hlpdt-mm img{
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
.narshelpdetailPc .nars-help-content .nars-hlpdt-mm p img{
|
.narshelpdetailPc .nars-help-content .nars-hlpdt-mm p img{
|
||||||
display: inline;
|
display: inline;
|
||||||
@@ -221,7 +227,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.narshelpdetailPc .nars-help-content .nars-hlpdt-mr #title-list ul li {
|
.narshelpdetailPc .nars-help-content .nars-hlpdt-mr #title-list ul li {
|
||||||
margin-bottom: 23px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.narshelpdetailPc .nars-help-content .nars-hlpdt-mr #title-list ul li a {
|
.narshelpdetailPc .nars-help-content .nars-hlpdt-mr #title-list ul li a {
|
||||||
|
|||||||
BIN
public/static/index/pc/images/Achievement.webp
Normal file
BIN
public/static/index/pc/images/Achievement.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
public/static/index/pc/images/indeximg1.webp
Normal file
BIN
public/static/index/pc/images/indeximg1.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
BIN
public/static/index/pc/images/indeximg2.webp
Normal file
BIN
public/static/index/pc/images/indeximg2.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
BIN
public/static/index/pc/images/nas_help_banner.webp
Normal file
BIN
public/static/index/pc/images/nas_help_banner.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Reference in New Issue
Block a user