135 Commits

Author SHA1 Message Date
ouzhiqiang
9d8e22d270 修改分类 2025-09-19 15:14:55 +08:00
ouzhiqiang
f154f3ddf6 修改分类 2025-09-19 14:59:45 +08:00
ouzhiqiang
2073a27ef7 修改分类 2025-09-19 14:48:10 +08:00
ouzhiqiang
e301fc7e94 修改分类 2025-09-19 14:47:05 +08:00
ouzhiqiang
f9251d944e 修改分类 2025-09-19 14:36:08 +08:00
ouzhiqiang
1e6187801d Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-09-19 14:32:27 +08:00
ouzhiqiang
346dcebba3 修改分类 2025-09-19 14:31:56 +08:00
ab7b23e5d1 Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-09-19 14:13:56 +08:00
325221bd67 1 2025-09-19 14:13:53 +08:00
ouzhiqiang
721e91dc31 修改分类 2025-09-19 11:37:41 +08:00
ouzhiqiang
12e51c6f46 修改分类 2025-09-19 11:22:25 +08:00
ouzhiqiang
8ba9006173 修改分类 2025-09-19 11:17:49 +08:00
ouzhiqiang
a7d413871b 修改分类 2025-09-19 11:09:29 +08:00
ouzhiqiang
ce6a882c17 修改分类 2025-09-19 10:41:41 +08:00
ouzhiqiang
7e7cfeacbc 修改分类 2025-09-19 10:36:26 +08:00
ouzhiqiang
e1961d2a83 修改分类 2025-09-19 10:29:25 +08:00
ouzhiqiang
d313617e2b 修改分类 2025-09-19 10:23:02 +08:00
ouzhiqiang
f0c82c848f 修改分类 2025-09-19 10:04:47 +08:00
ouzhiqiang
f606dc64a5 修改分类 2025-09-19 09:53:40 +08:00
ouzhiqiang
39dc3c4e1a 修改分类 2025-09-19 09:51:29 +08:00
ouzhiqiang
52b265f36e Merge branch 'ozq-dev' into dev 2025-09-18 17:50:21 +08:00
ouzhiqiang
5f9fb74696 修改分类 2025-09-18 17:50:05 +08:00
ouzhiqiang
b251c78b2f Merge branch 'ozq-dev' into dev 2025-09-18 17:47:43 +08:00
ouzhiqiang
2e1c83d46d 修改分类 2025-09-18 17:47:22 +08:00
ouzhiqiang
0265cb0629 Merge branch 'ozq-dev' into dev 2025-09-18 17:23:25 +08:00
ouzhiqiang
68d66b2925 修改分类 2025-09-18 17:23:07 +08:00
ouzhiqiang
601403bf3e Merge branch 'ozq-dev' into dev 2025-09-18 17:16:43 +08:00
ouzhiqiang
bbe2197b38 修改分类 2025-09-18 17:16:24 +08:00
ouzhiqiang
ee955a3674 Merge branch 'ozq-dev' into dev 2025-09-18 17:13:22 +08:00
ouzhiqiang
e45df84312 修改分类 2025-09-18 17:13:04 +08:00
ouzhiqiang
4e0891da97 Merge branch 'ozq-dev' into dev 2025-09-18 17:04:44 +08:00
ouzhiqiang
f9b895732e 修改分类 2025-09-18 17:04:29 +08:00
ouzhiqiang
e72ecd55f4 Merge branch 'ozq-dev' into dev 2025-09-18 17:01:25 +08:00
ouzhiqiang
558b418d18 修改分类 2025-09-18 17:01:08 +08:00
ouzhiqiang
78cbc5de6e Merge branch 'ozq-dev' into dev 2025-09-18 16:56:01 +08:00
ouzhiqiang
f7b610df72 修改分类 2025-09-18 16:55:47 +08:00
ouzhiqiang
b1522a365b Merge branch 'ozq-dev' into dev 2025-09-18 16:53:26 +08:00
ouzhiqiang
48906ec9cd 修改分类 2025-09-18 16:53:06 +08:00
ouzhiqiang
b57cb8dfd6 Merge branch 'ozq-dev' into dev 2025-09-18 16:49:16 +08:00
ouzhiqiang
7d70c55557 修改分类 2025-09-18 16:48:45 +08:00
ouzhiqiang
4fdda8435d Merge branch 'ozq-dev' into dev 2025-09-18 16:11:52 +08:00
ouzhiqiang
7a96809bfe 修改分类 2025-09-18 16:11:36 +08:00
ouzhiqiang
62b3e2798f Merge branch 'ozq-dev' into dev 2025-09-18 16:08:29 +08:00
ouzhiqiang
bfeac736ea 修改分类 2025-09-18 16:08:05 +08:00
ouzhiqiang
74ea50b7e4 Merge branch 'ozq-dev' into dev 2025-09-18 16:01:20 +08:00
ouzhiqiang
8a617c06e9 修改分类 2025-09-18 16:00:49 +08:00
ouzhiqiang
efa8acaf12 Merge branch 'ozq-dev' into dev 2025-09-18 15:39:28 +08:00
ouzhiqiang
d3ff726e90 修改分类 2025-09-18 15:38:59 +08:00
ouzhiqiang
7880c18e85 Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-09-18 15:26:19 +08:00
ouzhiqiang
e80ba5ac7d 修改分类 2025-09-18 15:25:29 +08:00
20b5fd901b 1 2025-09-18 11:59:32 +08:00
e38c00f59c 1 2025-09-18 11:57:52 +08:00
a18706f7d4 分类补充 2025-09-18 11:56:48 +08:00
4ff2ee4a76 移动端帮助中心三级菜单 2025-09-18 11:52:52 +08:00
2ca708fd4a 帮助中心文档三级菜单 2025-09-18 11:21:50 +08:00
29761f551d Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-09-18 11:15:12 +08:00
fdb75e4888 feat: 添加open api client管理命令 2025-09-17 17:48:27 +08:00
5fde7159e0 Merge branch 'dev' 2025-08-26 14:53:55 +08:00
6068efa03f refactor: 去掉多余目录 2025-08-26 14:53:38 +08:00
738b293ea2 fix: 修复“检测文件地址并根据情况转换为文件系统地址”url为null情况报错问题 2025-08-26 14:53:17 +08:00
a1be105c31 Merge branch 'dev' 2025-08-08 09:18:33 +08:00
03374856e4 fix: 修复产品目录分类树数据问题 2025-08-08 09:18:13 +08:00
f07741ff19 Merge branch 'dev' 2025-08-07 17:08:12 +08:00
c64450d74c fix: admapi - 产品目录同步分类更新时bug修复 2025-08-07 17:07:52 +08:00
e462b38ff9 Merge branch 'dev' 2025-08-07 11:38:17 +08:00
b96021d21d Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-08-07 11:37:49 +08:00
12d6fdc3a6 style:底部样式修改 2025-08-07 11:36:56 +08:00
cd3f651a2a Merge branch 'dev' 2025-08-07 10:20:10 +08:00
1e4b416cac fix: mobile - 底部“联系我们”取值问题 2025-08-07 10:19:45 +08:00
e38446f3fd Merge branch 'dev' 2025-08-07 10:18:06 +08:00
06b9d42ae4 fix: mobile - 底部“联系我们”取值问题 2025-08-07 10:17:24 +08:00
99d78069d5 Merge branch 'dev' 2025-08-07 10:12:04 +08:00
342a3754aa fix: mobile - 底部“联系我们”取值问题 2025-08-07 10:03:50 +08:00
51e9c8ced1 Merge branch 'dev' 2025-08-06 15:35:50 +08:00
b13d481e1e perf openapi 图片地址拼接 2025-08-06 15:35:35 +08:00
da8f204167 Merge branch 'dev' 2025-08-06 12:45:49 +08:00
c1979da1af fix: 后台 - 修改各导出图片等文件地址拼接问题 2025-08-06 11:56:53 +08:00
1802f57906 fix: 后台 产品导出数据问题 2025-08-06 11:40:44 +08:00
3fa3b8fb63 fix: 后台 产品导出数据问题 2025-08-06 11:40:09 +08:00
fb2b1455bc fix: mobile下视频分类地址错误 2025-07-31 10:55:26 +08:00
cc497b2ebc fix: 获取文件系统磁盘未判断“//”情况 2025-07-31 09:03:49 +08:00
2b450a2e9c fix: 首页“场景介绍”无法点击 2025-07-31 09:03:48 +08:00
e266e89a97 1 2025-07-30 17:08:22 +08:00
2a94a7ecec 1 2025-07-30 17:07:37 +08:00
9137335ce3 1 2025-07-30 16:48:54 +08:00
b8946f223a 1 2025-07-30 16:47:15 +08:00
3a8440c2b9 1 2025-07-30 16:44:32 +08:00
c2bba7fb56 1 2025-07-30 16:40:36 +08:00
052570fefa Merge branch 'dev' 2025-07-30 16:33:15 +08:00
09b1f9f14c style:产品详情 2025-07-30 16:13:37 +08:00
37825f88ba .ql-editor 2025-07-30 15:43:42 +08:00
1c7434b591 .ql-editor 2025-07-30 15:42:52 +08:00
585da730ea style:产品详情样式 2025-07-30 15:35:16 +08:00
2ecc51d8a9 Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-07-30 15:25:01 +08:00
ad7148ccfc style:详情样式 2025-07-30 15:24:58 +08:00
1e00db6c97 fix: 字段长度限制 2025-07-30 11:13:17 +08:00
5ed692a672 fix: 字段长度限制 2025-07-30 11:12:13 +08:00
5f7156470e Merge branch 'dev' 2025-07-29 17:52:13 +08:00
3aafcd3f3b refactor: 修改后台banner的“链接地址”长度限制为510 2025-07-29 17:51:56 +08:00
9b339d6364 Merge branch 'dev' 2025-07-29 16:48:16 +08:00
09f9bfd301 Merge branch 'dev' 2025-07-29 16:47:31 +08:00
910a07ea47 1 2025-07-29 14:16:51 +08:00
c27d529b82 Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-07-29 14:14:29 +08:00
b6724c0361 视频宽度限制 2025-07-29 14:14:27 +08:00
d4fa15f671 文章视频限制 2025-07-29 14:13:34 +08:00
60229ae058 fix: migrations/seeds 2025-07-29 14:08:30 +08:00
6cf27d8b9c fix: 产品详情-分类路径bug 2025-07-29 12:00:22 +08:00
6ba7181e3f 文章详情样式调整 2025-07-28 14:50:26 +08:00
4334c2db66 Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-07-28 14:34:41 +08:00
d7e93567d9 style:宽度调整 2025-07-28 14:25:01 +08:00
e19ba6a315 chore: composer.json 2025-07-28 11:13:56 +08:00
a8e7ad2430 perf: migrations/seeds 2025-07-28 10:33:44 +08:00
55c8762255 perf: 七牛云存储 2025-07-28 10:16:03 +08:00
43a4f5f706 refactor: .gitignore 2025-07-25 18:00:14 +08:00
c6cff2e97d refactor: 七牛云上传 2025-07-25 17:57:31 +08:00
5d53c26c5c 文章详情样式调整 2025-07-25 13:47:37 +08:00
857bb4ad21 Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-07-24 10:00:18 +08:00
b3dfb8655b 1 2025-07-24 10:00:14 +08:00
10c1f86708 feat: 七牛云上传开发 2025-07-23 17:55:34 +08:00
62a67bf7a0 perf: 自定义语言检测中间件 2025-07-23 17:55:34 +08:00
4dc4932ac7 补充 2025-07-23 17:25:57 +08:00
b99c07ef4a .ql-editor 关于tab切换的样式同步 2025-07-23 17:20:11 +08:00
f8dc645048 样式修改 2025-07-22 16:48:22 +08:00
051b4ed7e7 Merge branch 'dev' 2025-07-21 17:32:36 +08:00
142e29f131 fix: pc 产品,附件,视频搜索去除首尾空格 2025-07-21 17:31:17 +08:00
7f58f1ff83 fix: pc 视频搜索 2025-07-21 16:55:06 +08:00
5650ccfb87 fix: pc 视频搜索 2025-07-21 16:54:43 +08:00
439c9073b8 Merge branch 'dev' 2025-07-19 10:48:27 +08:00
f78f164326 fix: 图片上传命名问题 2025-07-19 10:48:07 +08:00
5fb2abe818 Merge branch 'master' of https://gitea.f2b211.com/jsasg/orico-official-website 2025-07-18 15:19:02 +08:00
1f3b646495 1 2025-07-18 15:16:09 +08:00
a1ea5c6752 标题提取空过滤 样式修改 2025-07-18 15:15:13 +08:00
beb86140a6 Merge branch 'dev' of https://gitea.f2b211.com/jsasg/orico-official-website into dev 2025-07-18 14:42:10 +08:00
0d442fb63a Merge branch 'dev' 2025-07-18 14:40:20 +08:00
af139f6bf4 fix: nas 文章详情页分类排序问题 2025-07-18 14:40:02 +08:00
48 changed files with 1663 additions and 361 deletions

View File

@@ -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
@@ -47,8 +54,15 @@ 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
@@ -63,4 +77,20 @@ RULE_QUERY_VALUE = 1
RULE_DOMAIN_SCHEME[] = http 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

2
.gitignore vendored
View File

@@ -8,6 +8,8 @@ Thumbs.db
.env.local .env.local
.env.prod .env.prod
public/dist
public/opendoc
/.idea /.idea
/.vscode /.vscode
/vendor /vendor

View File

@@ -99,18 +99,20 @@ class ReceiveProductSync
} }
$category = ProductCategoryModel::language($lang_id)->tcoId($tco_category['id'])->find(); $category = ProductCategoryModel::language($lang_id)->tcoId($tco_category['id'])->find();
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find(); if (!empty($category)) {
if (!empty($tco_parent)) { $tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find(); if (!empty($tco_parent)) {
if ($parent->isEmpty()) { $parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
throw new \Exception('产品分类父级不存在'); if ($parent->isEmpty()) {
throw new \Exception('产品分类父级不存在');
}
$category['pid'] = $parent['id'];
$category['path'] = $parent['path'] . $parent['pid'];
$category['level'] = $parent['level'] + 1;
}
if (!$category->save()) {
throw new \Exception('产品分类更新失败');
} }
$category['pid'] = $parent['id'];
$category['path'] = $parent['path'] . $parent['pid'];
$category['level'] = $parent['level'] + 1;
}
if (!$category->save($category)) {
throw new \Exception('产品分类更新失败');
} }
} }

View File

@@ -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;
}); });

View File

@@ -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;
});
} }
// 删除 // 删除

View File

@@ -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()) {
// 产品参数 // 产品参数

View File

@@ -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'));
} }
} }

View File

@@ -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
]); ]);

View File

@@ -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;

View File

@@ -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'
]; ];
@@ -54,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'
]; ];

View File

@@ -17,7 +17,7 @@ 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:512', 'desc' => 'max:512',
'image' => 'max:125', 'image' => 'max:125',
'video' => 'max:125', 'video' => 'max:125',
@@ -43,7 +43,7 @@ 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' => '描述不能超过512个字符', 'desc.max' => '描述不能超过512个字符',
'image.max' => '图片不能超过125个字符', 'image.max' => '图片不能超过125个字符',
'video.max' => '视频不能超过125个字符', 'video.max' => '视频不能超过125个字符',

View File

@@ -0,0 +1,42 @@
<?php
declare (strict_types = 1);
namespace app\command\OpenApiMgr;
use oauth\OAuthStorage;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
class AddClient extends Command
{
protected function configure()
{
// 指令配置
$this->setName('OpenApiMgr:AddClient')
->addArgument('salt', Argument::OPTIONAL, "开放API的client_secret密钥的盐值")
->setDescription('开放API的client管理');
}
protected function execute(Input $input, Output $output)
{
$salt = $input->getArgument('salt');
$salt = empty($salt) ? null : trim($salt);
// 指令输出
$oauth = new OAuthStorage($salt);
$client_id = random_str(13, 'all', 0);
$client_secret = random_str(32, 'all', 0);
$ok = $oauth->addClient($client_id, $client_secret, null);
if (!$ok) {
$output->writeln("添加失败");
return;
}
$output->writeln("添加成功:\nClientID: {$client_id}\nClientSecret: {$client_secret}\n");
}
}

View File

@@ -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;
} }
@@ -144,4 +144,91 @@ 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;
}
} }

View File

@@ -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') {

View File

@@ -21,9 +21,9 @@ 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);

View File

@@ -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([

View File

@@ -192,6 +192,8 @@ class TopicNas extends Common
{ {
// 获取文章分类及文章数据 // 获取文章分类及文章数据
$parent = ArticleCategoryModel::uniqueLabel('CATEGORY_681182e0a4529')->language($this->lang_id)->value('id'); $parent = ArticleCategoryModel::uniqueLabel('CATEGORY_681182e0a4529')->language($this->lang_id)->value('id');
$parent_two = ArticleCategoryModel::parent($parent)->language($this->lang_id)->column('id');//二级分类id
array_push($parent_two,$parent);
$article_categorys = ArticleCategoryModel::with(['article' => function($query) { $article_categorys = ArticleCategoryModel::with(['article' => function($query) {
$query->field(['id', 'title', 'category_id']) $query->field(['id', 'title', 'category_id'])
->order(['sort' => 'asc', 'id' => 'desc']) ->order(['sort' => 'asc', 'id' => 'desc'])
@@ -199,15 +201,48 @@ class TopicNas extends Common
}]) }])
->field([ ->field([
'id', 'id',
'pid',
'name', 'name',
'icon' 'icon'
]) ])
->language($this->lang_id) ->language($this->lang_id)
->parent($parent) // ->parent($parent)
->parentChild($parent_two)
->isShow(true) ->isShow(true)
->order(['sort' => 'asc', 'id' => 'desc']) ->order(['sort' => 'asc', 'id' => 'desc'])
->select(); ->select();
View::assign('article_categorys', $article_categorys); //查询三级分类
$article_categorys_new = [];
$article_categorys_two = [];
// dump($article_categorys->toArray());exit;
if (!$article_categorys->isEmpty()) {
foreach ($article_categorys->toArray() as $kk=>$vv) {
if ( $parent == $vv['pid'] ) {
array_push($article_categorys_new,$vv);
} else {
$article_categorys_two[$vv['pid']][] = $vv;
}
}
if ( !empty($article_categorys_two) ) {
foreach ($article_categorys_new as &$vvv) {
$articles = $vvv['article'];
if ( isset($article_categorys_two[$vvv['id']]) ) {
foreach ($article_categorys_two[$vvv['id']] as $v) {
foreach ($v['article'] as $av) {
if ( count($articles) < 3 ) {
array_push($articles,$av);
}
}
}
}
$vvv['article'] = $articles;
}
}
}
View::assign('article_categorys', $article_categorys_new);
// View::assign('article_categorys', $article_categorys);
$contacts = []; $contacts = [];
// 获取banner数据 // 获取banner数据
@@ -246,19 +281,46 @@ class TopicNas extends Common
// 获取文章分类及文章数据 // 获取文章分类及文章数据
$parent = ArticleCategoryModel::uniqueLabel('CATEGORY_681182e0a4529')->language($this->lang_id)->value('id'); $parent = ArticleCategoryModel::uniqueLabel('CATEGORY_681182e0a4529')->language($this->lang_id)->value('id');
$parent_two = ArticleCategoryModel::parent($parent)->language($this->lang_id)->column('id');//二级分类id
array_push($parent_two,$parent);
$article_categorys = ArticleCategoryModel::with(['article' => function ($query) { $article_categorys = ArticleCategoryModel::with(['article' => function ($query) {
$query->field(['id', 'title', 'category_id'])->order(['sort' => 'asc', 'id' => 'desc']); $query->field(['id', 'title', 'category_id'])->order(['sort' => 'asc', 'id' => 'desc']);
}]) }])
->field([ ->field([
'id', 'id',
'pid',
'name', 'name',
'icon' 'icon'
]) ])
->language($this->lang_id) ->language($this->lang_id)
->parent($parent) // ->parent($parent)
->parentChild($parent_two)
->isShow(true) ->isShow(true)
->order(['sort' => 'asc', 'id' => 'desc'])
->select(); ->select();
View::assign('article_categorys', $article_categorys); // dump($article_categorys->toArray());exit;
//查询三级分类
$article_categorys_new = [];
$article_categorys_two = [];
if (!$article_categorys->isEmpty()) {
foreach ($article_categorys->toArray() as $kk=>$vv) {
if ( $parent == $vv['pid'] ) {
$vv['child'] = '';
array_push($article_categorys_new,$vv);
} else {
$article_categorys_two[$vv['pid']][] = $vv;
}
}
if ( !empty($article_categorys_two) ) {
foreach ($article_categorys_new as &$vvv) {
$vvv['child'] = isset($article_categorys_two[$vvv['id']])?$article_categorys_two[$vvv['id']]:'';
}
}
}
// dump($article_categorys_new);exit;
// dump($article_categorys_two);exit;
View::assign('article_categorys', $article_categorys_new);
return View::fetch('help_detail'); return View::fetch('help_detail');
} }
@@ -316,8 +378,18 @@ class TopicNas extends Common
->language($this->lang_id) ->language($this->lang_id)
->where('category_id', 'IN', array_column($categorys, 'id')) ->where('category_id', 'IN', array_column($categorys, 'id'))
->select(); ->select();
//查询上级id
$parent_two = ArticleCategoryModel::parentColumn(array_column($categorys, 'id'))->language($this->lang_id)->column('pid','id');//二级分类id
$articles_data = $articles->toArray();
foreach ($articles_data as &$v) {
$v['pid'] = 0;
if ( $parent_two[$v['category_id']] !== $parent ) {
$v['pid'] = $v['category_id'];
$v['category_id'] = $parent_two[$v['category_id']];
}
}
return success('success', $articles->toArray()); return success('success', $articles_data);
} }
/** /**

View File

@@ -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,
]; ];

View 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()] ?? '';
}
}

View File

@@ -46,6 +46,27 @@ class ArticleCategoryModel extends ArticleCategoryBaseModel
$query->where('pid', '=', $parent); $query->where('pid', '=', $parent);
} }
// 所属上级分类范围查询
public function scopeParentChild($query, $parent)
{
if (is_array($parent)) {
$query->where('pid', 'IN', $parent);
return;
}
$query->where('pid', '=', $parent);
}
// 所属上级分类查询
public function scopeParentColumn($query, $parent)
{
if (is_array($parent)) {
$query->where('id', 'IN', $parent);
return;
}
$query->where('id', '=', $parent);
}
// 所属子分类范围查询 // 所属子分类范围查询
public function scopeChild($query, $id, $merge_self = false) public function scopeChild($query, $id, $merge_self = false)
{ {

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -57,6 +57,8 @@
<div class="nars-hlpdt-ml"> <div class="nars-hlpdt-ml">
{notempty name="article_categorys"} {notempty name="article_categorys"}
<div class="nav-tree"> <div class="nav-tree">
{volist name="article_categorys" id="ac" key="idx"} {volist name="article_categorys" id="ac" key="idx"}
<div class="categoryhelp"> <div class="categoryhelp">
<div class="categoryhelp-title"> <div class="categoryhelp-title">
@@ -67,6 +69,24 @@
<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.child" id="ad"}
<li class="two-mues">
<a href="#" class="two-a">
<div><img src="__IMAGES__/nars-jt.png"
class="arrow {if condition='$ad.id == $Request.get.pid'}rotate{/if}">
</div>
<span>{$ad.name}</span>
</a>
<ul class="thress-mues" {if condition='$ad.id == $Request.get.pid' }style="display: block;" {/if}>
{volist name="ad.article" id="ae"}
<li>
<a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id ,'pid' => $ad.id, 'id' => $ae.id])}"
style="margin-left:18%;padding: 0.4rem;">{$ae.title}</a>
</li>
{/volist}
</ul>
</li>
{/volist}
{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])}" <a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id , 'id' => $ar.id])}"
@@ -78,6 +98,9 @@
</ul> </ul>
</div> </div>
{/volist} {/volist}
</div> </div>
{/notempty} {/notempty}
</div> </div>
@@ -128,6 +151,17 @@
$(this).next('.sub-list').slideToggle(); $(this).next('.sub-list').slideToggle();
$(this).find('.arrow').toggleClass('rotate'); $(this).find('.arrow').toggleClass('rotate');
}); });
//分类二三级交互
$('.two-a').click(function(e) {
e.preventDefault();
e.stopPropagation(); // 阻止事件冒泡
// 切换当前二级菜单的箭头方向
$(this).find('.arrow').toggleClass('rotate');
// 切换对应的三级菜单显示/隐藏
$(this).siblings('.thress-mues').slideToggle();
});
// 点击顶部搜索图标-点击取消关闭 // 点击顶部搜索图标-点击取消关闭
$('#ssico').click(function () { $('#ssico').click(function () {
$('.nhlpapp-pagescate').hide(); $('.nhlpapp-pagescate').hide();

View File

@@ -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"}

View File

@@ -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>

View File

@@ -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>

View File

@@ -117,8 +117,8 @@
<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 style="background-image: url('{$scene.image}');" class="sceneimg"></div>
</a> </a>
<div style="background-image: url('{$scene.image}');" class="sceneimg"></div>
</div> </div>
{/volist} {/volist}
</div> </div>

View File

@@ -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>
<!-- 产品主图切换和参数详情--> <!-- 产品主图切换和参数详情-->
@@ -129,8 +133,10 @@
{/notempty} {/notempty}
</div> </div>
<!-- 富文本渲染--> <!-- 富文本渲染-->
<div class="products_des" id="detail"> <div class="ql-container">
{$product.detail|default=''|raw} <div class="products_des ql-editor" id="detail">
{$product.detail|default=''|raw}
</div>
</div> </div>
</div> </div>
<!-- 关联产品 --> <!-- 关联产品 -->

View File

@@ -58,7 +58,7 @@
{else/} {else/}
<a href="javascript:void(0);" class="fline"> <a href="javascript:void(0);" class="fline">
{$vo.value} {$vo.value}
{/if} {/if}
</a> </a>
</li> </li>
{/volist} {/volist}

View File

@@ -26,13 +26,13 @@
<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>
<div class="nhlp-tx-list"> <div class="nhlp-tx-list">
{volist name="vo.article" id="va" key="index"} {volist name="vo.article" id="va" key="index"}
<a class="txrow" href="{:url('/index/topic/nas/help_detail', ['cid' => $vo.id, 'id' => $va.id])}"> <a class="txrow" href="{:url('/index/topic/nas/help_detail', ['pid' => $va.category_id,'cid' => $vo.id, 'id' => $va.id])}">
<div class="nhlp-point"></div> <div class="nhlp-point"></div>
<span class="nhlpsp">{$va.title}</span> <span class="nhlpsp">{$va.title}</span>
<span class="narhelpgoimg"> <span class="narhelpgoimg">
@@ -41,7 +41,7 @@
</a> </a>
{/volist} {/volist}
{if condition="count($vo.article) >= 3"} {if condition="count($vo.article) >= 3"}
<a class="ckgdbt" href="{:url('/index/topic/nas/help_detail', ['cid' => $vo.id, 'id' => isset($vo.article[0])?$vo.article[0]['id']:0])}"> <a class="ckgdbt" href="{:url('/index/topic/nas/help_detail', ['cid' => $vo.id, 'id' => isset($vo.article[0])?$vo.article[0]['id']:0,'pid' => isset($vo.article[0])?$vo.article[0]['category_id']:0])}">
{:lang_i18n('查看更多')} > {:lang_i18n('查看更多')} >
</a> </a>
{/if} {/if}

View File

@@ -1,17 +1,17 @@
{extend name="public/nas_base" /} {extend name="public/nas_base" /}
{block name="title"} {block name="title"}
{notempty name="article.seo_title"}<title>{$article.seo_title}</title>{else /}{__BLOCK__}{/notempty} {notempty name="article.seo_title"}<title>{$article.seo_title}</title>{else /}{__BLOCK__}{/notempty}
{/block} {/block}
{block name="seo"} {block name="seo"}
{notempty name="article.seo_keywords"} {notempty name="article.seo_keywords"}
<meta name="keywords" content="{$article.seo_keywords}" /> <meta name="keywords" content="{$article.seo_keywords}" />
<meta name="description" content="{$article.seo_desc}" /> <meta name="description" content="{$article.seo_desc}" />
{else /} {else /}
{__BLOCK__} {__BLOCK__}
{/notempty} {/notempty}
{/block} {/block}
{block name="style"} {block name="style"}
<link rel="stylesheet" href="__CSS__/topic_nas_help-detail.css"/> <link rel="stylesheet" href="__CSS__/topic_nas_help-detail.css" />
{/block} {/block}
{block name="main"} {block name="main"}
<div class="orico_Page_index"> <div class="orico_Page_index">
@@ -32,28 +32,42 @@
<div class="nars-hlpdt-ml"> <div class="nars-hlpdt-ml">
{notempty name="article_categorys"} {notempty name="article_categorys"}
<div class="nav-tree"> <div class="nav-tree">
<!-- start 三级菜单 -->
{volist name="article_categorys" id="ac"} {volist name="article_categorys" id="ac"}
<div class="category"> <div class="category">
<!-- 一级 -->
<div class="category-title"> <div class="category-title">
<div class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}"> <div class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}"><img src="__IMAGES__/nas-jt.png" class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}" /></div>
<img src="__IMAGES__/nas-jt.png" class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}" />
</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}> <!-- 二级-->
{volist name="ac.article" id="ar"} <ul class="sub-list" {if condition='$ac.id == $Request.get.cid' }style="display: block;" {/if}>
<li> {volist name="ac.child" id="ad"}
<a <li class="two-mues">
href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id, 'id' => $ar.id])}" <a href="#" class="two-a">
{eq name="ar.id" value="$Request.get.id"}class="active"{/eq} <div class="arrow {if condition='$ad.id == $Request.get.pid'}rotate{/if}"><img src="__IMAGES__/nas-jt.png" class="arrow {if condition='$ad.id == $Request.get.pid'}rotate{/if}" /></div>
> <span>{$ad.name}</span>
{$ar.title}
</a> </a>
<ul class="thress-mues" {if condition='$ad.id == $Request.get.pid' }style="display: block;" {/if}>
{volist name="ad.article" id="ae"}
<li><a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id,'pid' => $ad.id, 'id' => $ae.id])}" style="padding-top: 6px;padding-left: 30px;" {eq
name="ae.id" value="$Request.get.id" }class="active" {/eq}>{$ae.title}</a></li>
{/volist}
</ul>
<!-- 三级-->
</li> </li>
{/volist} {/volist}
{volist name="ac.article" id="ar"}
<li><a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id, 'id' => $ar.id])}" style="padding-top: 6px;" {eq
name="ar.id" value="$Request.get.id" }class="active" {/eq}>{$ar.title}</a></li>
{/volist}
</ul> </ul>
</div> </div>
{/volist} {/volist}
<!-- end 三级菜单 -->
</div> </div>
{/notempty} {/notempty}
</div> </div>
@@ -75,10 +89,22 @@
{block name="script"} {block name="script"}
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function () { $(document).ready(function () {
// 一级菜单点击事件
$('.category-title').click(function () { $('.category-title').click(function () {
$(this).next('.sub-list').slideToggle(); $(this).next('.sub-list').slideToggle();
$(this).find('.arrow').toggleClass('rotate'); $(this).find('.arrow').toggleClass('rotate');
}); });
// 二级菜单点击事件
$('.two-a').click(function(e) {
e.preventDefault();
e.stopPropagation(); // 阻止事件冒泡
// 切换当前二级菜单的箭头方向
$(this).find('.arrow').toggleClass('rotate');
// 切换对应的三级菜单显示/隐藏
$(this).siblings('.thress-mues').slideToggle();
});
// 搜索 // 搜索
$(document).on('click', function (e) { $(document).on('click', function (e) {
var target = $(e.target); var target = $(e.target);
@@ -109,7 +135,7 @@
html = '<ul>' html = '<ul>'
$.each(r.data, function (k, v) { $.each(r.data, function (k, v) {
html += html +=
'<li><a href="{:url(\'/index/topic/nas/help_detail\')}?cid=' + v.category_id + '&id=' + v.id + '">' + v.title + '</a></li>' '<li><a href="{:url(\'/index/topic/nas/help_detail\')}?cid=' + v.category_id + '&id=' + v.id + '&pid=' + v.pid + '">' + v.title + '</a></li>'
}) })
html += '</ul>' html += '</ul>'
} }
@@ -121,21 +147,27 @@
// 内容 // 内容
// 清空标题列表 // 清空标题列表
$("#title-list ul").empty(); $("#title-list ul").empty();
// 提取 h1 标题 // 提取 h3 标题
var h1Titles = $("#rendered-content").find("h3"); var h1Titles = $("#rendered-content").find("h3");
h1Titles.each(function (index) { // 只有当找到h3标题且内容不为空时才进行处理
var title = $(this); if (h1Titles.length > 0) {
var titleText = title.text(); h1Titles.each(function (index) {
var titleId = "title-" + index; var title = $(this);
title.attr("id", titleId); var titleText = title.text().trim(); // 使用trim()去除空白字符
var listItem = $("<li>"); // 只有当标题文本不为空时才添加到列表
var link = $("<a>", { if (titleText) {
href: "#" + titleId, var titleId = "title-" + index;
text: titleText title.attr("id", titleId);
var listItem = $("<li>");
var link = $("<a>", {
href: "#" + titleId,
text: titleText
});
listItem.append(link);
$("#title-list ul").append(listItem);
}
}); });
listItem.append(link); }
$("#title-list ul").append(listItem);
});
}); });
</script> </script>
{/block} {/block}

View File

@@ -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);
} }
} }

View File

@@ -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",

View File

@@ -2,9 +2,12 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | 控制台配置 // | 控制台配置
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
return [ return [
// 指令定义 // 指令定义
'commands' => [ 'commands' => [
'data:migrate' => \app\command\DataMigration::class, 'data:migrate' => \app\command\DataMigration::class,
'openapi:addclient' => \app\command\OpenApiMgr\AddClient::class,
], ],
]; ];

View File

@@ -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;
};
},
]
// 更多的磁盘配置信息 // 更多的磁盘配置信息
], ],
]; ];

View File

@@ -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' => '视频地址'])

View File

@@ -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' => '创建时间'])

View File

@@ -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');

View 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);
}
}
}

View 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;
}
}

View File

@@ -1,2 +0,0 @@
*
!.gitignore

View File

@@ -161,7 +161,9 @@ body {
.ql-editor>* { .ql-editor>* {
cursor: text cursor: text
} }
.ql-editor video{
max-width: 100% !important;
}
.ql-editor p,.ql-editor ol,.ql-editor ul,.ql-editor pre,.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6 { .ql-editor p,.ql-editor ol,.ql-editor ul,.ql-editor pre,.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6 {
margin: 0; margin: 0;
padding: 0; padding: 0;

View File

@@ -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%;

View File

@@ -219,4 +219,32 @@
.narshelpCenterdetail-app .nhlpapp-pagescate .nars-hlpdt-ml .sub-list li a:hover { .narshelpCenterdetail-app .nhlpapp-pagescate .nars-hlpdt-ml .sub-list li a:hover {
color: #1f2635; color: #1f2635;
border-bottom: 1px solid #1f2635; border-bottom: 1px solid #1f2635;
}
/*9.18 添加三级样式*/
.narshelpCenterdetail-app .nhlpapp-pagescate .nars-hlpdt-ml .sub-list .two-mues {
position: relative;
}
.narshelpCenterdetail-app .nhlpapp-pagescate .nars-hlpdt-ml .sub-list .two-mues .two-a {
position: relative;
padding-top: 6px;
display: flex;
font-size: 0.95rem !important;
flex-direction: row;
}
.narshelpCenterdetail-app .nhlpapp-pagescate .nars-hlpdt-ml .sub-list .two-mues .two-a:hover {
border-bottom: none;
}
.narshelpCenterdetail-app .nhlpapp-pagescate .nars-hlpdt-ml .sub-list .thress-mues {
display: none;
}
.narshelpCenterdetail-app .nhlpapp-pagescate .nars-hlpdt-ml .sub-list .thress-mues a {
padding-top: 0.375rem;
padding-left: 1.875rem;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -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;
} }

View File

@@ -4,7 +4,7 @@
background: #f9f9f9; background: #f9f9f9;
} }
.narshelpdetailPc .ql-container{ .narshelpdetailPc .ql-container{
width: 95%; width: 81%;
} }
.narshelpdetailPc .narsssmain { .narshelpdetailPc .narsssmain {
width: 100%; width: 100%;
@@ -135,6 +135,7 @@
transform: rotate(0deg); transform: rotate(0deg);
display: flex; display: flex;
justify-content: center; justify-content: center;
flex-direction: column-reverse;
} }
.narshelpdetailPc .nars-help-content .nars-hlpdt-ml .arrow .nars-jt { .narshelpdetailPc .nars-help-content .nars-hlpdt-ml .arrow .nars-jt {
@@ -173,6 +174,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 {
@@ -214,7 +216,7 @@
} }
.narshelpdetailPc .nars-help-content .nars-hlpdt-mr #title-list .tt { .narshelpdetailPc .nars-help-content .nars-hlpdt-mr #title-list .tt {
font-size: 14px; font-size: 15px;
padding-top: 33px; padding-top: 33px;
padding-bottom: 1rem; padding-bottom: 1rem;
margin: 0; margin: 0;
@@ -226,7 +228,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 {
@@ -256,4 +258,28 @@
all: revert; all: revert;
/* 将所有属性设置为初始值 */ /* 将所有属性设置为初始值 */
/* 或者使用 all: revert; 恢复到浏览器默认样式,但该属性兼容性不如 initial */ /* 或者使用 all: revert; 恢复到浏览器默认样式,但该属性兼容性不如 initial */
} }
/*9.18 添加三级样式*/
.narshelpdetailPc .nars-help-content .nars-hlpdt-ml .sub-list .two-mues{
position: relative;
}
.narshelpdetailPc .nars-help-content .nars-hlpdt-ml .sub-list .two-mues .two-a{
position: relative;
padding-top: 6px;
padding-bottom: 0.375rem;
display: flex;
font-size: 14px !important;
flex-direction: row;
}
.narshelpdetailPc .nars-help-content .nars-hlpdt-ml .sub-list .two-mues .two-a:hover{
border-bottom:none;
}
.narshelpdetailPc .nars-help-content .nars-hlpdt-ml .sub-list .thress-mues{
display: none;
}
.narshelpdetailPc .nars-help-content .nars-hlpdt-ml .sub-list .thress-mues .thress-mues a{
padding-top: 0.375rem;
padding-left: 1.875rem;
}