Compare commits
358 Commits
receive_sy
...
三级分类
| Author | SHA1 | Date | |
|---|---|---|---|
| 80678c23e2 | |||
| 53e56b4649 | |||
|
|
75977040f1 | ||
|
|
cf5a1280ee | ||
|
|
30d99619b2 | ||
|
|
7e877920ee | ||
|
|
04ede65c93 | ||
|
|
7524a9d572 | ||
|
|
9b5cf2147d | ||
| 9d898b1be3 | |||
| 834114261c | |||
|
|
2dc787bbfd | ||
|
|
5d61b4995f | ||
|
|
6800332b5b | ||
|
|
1c1d075f5e | ||
|
|
34821fd0bc | ||
|
|
3492d55707 | ||
|
|
5b901fe43c | ||
|
|
e6d299df83 | ||
|
|
5d5a338b55 | ||
|
|
4cd2f4ad26 | ||
|
|
14f899bf62 | ||
|
|
f82888c8e3 | ||
|
|
43c61a1ab5 | ||
|
|
4f2edf5d30 | ||
|
|
4ca59e81e3 | ||
|
|
9cd7b4f508 | ||
|
|
e02ad39620 | ||
|
|
0ce0c0a27a | ||
|
|
db72a5643c | ||
|
|
60fb6a5336 | ||
|
|
987e98279a | ||
|
|
9b926f1bf8 | ||
|
|
810b581d87 | ||
|
|
6bbc7c55c9 | ||
|
|
36de45c2e8 | ||
|
|
fd7e136c3a | ||
|
|
c9987373a4 | ||
|
|
5386610bf9 | ||
|
|
f1696a88d2 | ||
|
|
7e96a0e538 | ||
|
|
1f1cc6145d | ||
|
|
610377172a | ||
|
|
0d5593e173 | ||
|
|
6dbeb59b36 | ||
|
|
e54fccca65 | ||
|
|
1a92627ab9 | ||
|
|
88a7f06499 | ||
|
|
d6e58c78d4 | ||
|
|
46e78cff08 | ||
|
|
48c589babf | ||
|
|
72f974c083 | ||
| 9def4960c4 | |||
| 622f9f1665 | |||
| db7c34f4ad | |||
| f79dbc1121 | |||
| f3de8b4a26 | |||
| 85ccecb5bf | |||
| fa60ec4fcb | |||
| cb128a32a8 | |||
| 705566b376 | |||
| 0b13ec05dc | |||
| 7f765f40ee | |||
| 2a9c3332f7 | |||
| 12822ccb6b | |||
| 4872574eb0 | |||
| fa893d6b53 | |||
| f9445b6f49 | |||
| fea5f233a9 | |||
| e2b65856d2 | |||
| 3733ce720d | |||
| 0b82dbbf5f | |||
| 74d70fe815 | |||
| 0f2dc12752 | |||
| 499e86f52b | |||
| b24987fbd2 | |||
| 19aecea497 | |||
| 9060ed8274 | |||
| 54d15595ce | |||
| 101c1ae807 | |||
| ed7f274c6e | |||
| 1288ffd51b | |||
| 62e43375ab | |||
| 9f01db7d54 | |||
| ac06090792 | |||
| 6e6e4ac47c | |||
| 8ccc4b0cd5 | |||
| 55cd7f2b62 | |||
| 43e1ae0422 | |||
| 7fcb78dde0 | |||
| 6872a13141 | |||
| 234658f443 | |||
| 9f9a384075 | |||
| 047d7979ff | |||
| 3544c08005 | |||
| 2ff6d274d9 | |||
| d31d2359c6 | |||
| 6f9c89da7b | |||
| 9c6659830c | |||
| 4c906723df | |||
| d93aa62fbf | |||
| f216ba82b4 | |||
| bcd537ef25 | |||
| 589a099cdd | |||
| e13b30bbb2 | |||
| eb924d42d4 | |||
| 9378efe401 | |||
| 84dd8ea84b | |||
| 4c2441b1b6 | |||
| db8e0803c1 | |||
| 72b8230d5a | |||
| 5a8f32e0f8 | |||
| 517c2e954b | |||
| eee40e6010 | |||
| a7882da734 | |||
| 64ea309b30 | |||
| 708fee0490 | |||
| 5623c4160e | |||
| b660d82c94 | |||
| 8f5d3ed60f | |||
| 0f7e768bc4 | |||
| 1d84ba373b | |||
| 76e8372059 | |||
| fdb91466ca | |||
| 133c58c268 | |||
| c2ad978614 | |||
| 865fe2fc44 | |||
| 0f4c7fec5d | |||
| 1cfae69a27 | |||
| aa00a24b89 | |||
| 0b2c408525 | |||
| e6b255b824 | |||
| d7e8fe1d6e | |||
| 2a31e22ad8 | |||
| 99765a6112 | |||
| 5ae6d5681d | |||
| d2b274b559 | |||
| 3cb4eacff4 | |||
| 2a4349daab | |||
| 4e8320e871 | |||
| 3c8f9773be | |||
| d04343e9c8 | |||
| ed24f4fcd0 | |||
| c340155bca | |||
| 78616faa73 | |||
| abd3072ada | |||
| 17f11559d8 | |||
| 7b28b2ef20 | |||
| 3790816964 | |||
| 03fe4ee0ed | |||
| 21f600270f | |||
| 43d153c004 | |||
| 83468671f1 | |||
| f6e52294f0 | |||
| fd64633761 | |||
| 19d6944c06 | |||
| 7e66a9ecfb | |||
| 6925061380 | |||
| 77b988c6b7 | |||
| 35723f59a4 | |||
| 567798643c | |||
| 912d770c33 | |||
| 856ce0e7cc | |||
| 7c3c75b22e | |||
| 17ea1ea832 | |||
| 693c442060 | |||
| 4079574575 | |||
| 314fb66112 | |||
| d0b4d74b46 | |||
| 44e759564f | |||
| 84bf7662e9 | |||
| 0b71bb0254 | |||
| 5f5c7d7cf4 | |||
| 5e9ace5832 | |||
| e00fb9eadb | |||
| 99734ab92a | |||
| b1fb932aae | |||
| 97b851e8a6 | |||
| e736271536 | |||
| 74d1524d8d | |||
| 3bb1909ecd | |||
| 2870cbb544 | |||
| 710d6244d4 | |||
| b5b27f0555 | |||
| 3a2631b99a | |||
| 6ddb7df8aa | |||
| 09b28a1159 | |||
| 5949e576ed | |||
| e04b66295f | |||
| 7802c80009 | |||
| ce347c514b | |||
| 3d991abcd5 | |||
| fa1f6a70db | |||
| fb0a3f9371 | |||
| fc6079ef32 | |||
| 82a6b171b9 | |||
| 4891b07ba2 | |||
| 9789cec2bf | |||
| a59bb22c65 | |||
| 5b1a281e0f | |||
| d168e5bb93 | |||
| 76685ce103 | |||
| db38224b14 | |||
| a52fb091a8 | |||
| 13b4464473 | |||
| 2b8f8c8294 | |||
| f18afbe6ca | |||
| 12422f06b4 | |||
| 6b4612cd09 | |||
| 70ed7d917f | |||
| 3c994973c1 | |||
| 4672f76264 | |||
| 98ec9cdc49 | |||
| 0ad2a41ab3 | |||
| 1553a1f2ed | |||
| 9bdb290760 | |||
| b2014b104f | |||
| 791380e53c | |||
| 1c3aa90c3a | |||
| 425140d4ac | |||
| e32f75234a | |||
| 103fc4dd24 | |||
| 6eac1e5d7b | |||
| c171073174 | |||
| 5c0e96df27 | |||
| 4a91a4f673 | |||
| 9e22cde6ba | |||
| 7ee92398cf | |||
| f2c09736de | |||
| 7957b56f29 | |||
| dcfa73bdc1 | |||
| 3b4f747cb1 | |||
| 401683be6b | |||
| a8e80dfa26 | |||
| ca38a3a7b6 | |||
| 6b1ec81bd0 | |||
| 01952774b1 | |||
| ee35e2ce4b | |||
| d20e703bfe | |||
| 2ac0708ac1 | |||
| f292e68b5b | |||
| fe1a07f56a | |||
| be7d256007 | |||
| d3c8ffaeb1 | |||
| 14f0cc0607 | |||
| ae52ae7de5 | |||
| 510f89b84c | |||
| 0aa4e82095 | |||
| 14e611d02e | |||
| 8c1ff8da6e | |||
| bb37146be8 | |||
| 5fbdbda62d | |||
| 3688c0efd4 | |||
| 1de9769edb | |||
| e0dd787bf3 | |||
| a9681677a9 | |||
| 761a033b46 | |||
| 554a87d0cf | |||
| 26c60ae751 | |||
| 902f40e28c | |||
| d8744d2070 | |||
| f23ab69761 | |||
| 470a3e1687 | |||
| 932f2b8705 | |||
| b14a75c3a2 | |||
| f0b02ba83b | |||
| a36633a559 | |||
| 7daaf12908 | |||
| 4111e05957 | |||
| ce665b9ea4 | |||
| 082ed00d74 | |||
| 6c3f6247f8 | |||
| 881ce98a72 | |||
| 51ceeff0d7 | |||
| c0bd15cbd9 | |||
| e26b0094ee | |||
| afc70e1b68 | |||
| a96e3780fb | |||
| 7c781f4eaa | |||
| c938438838 | |||
| 10024e40c2 | |||
| 612fb44215 | |||
| b9ed1a7328 | |||
| 9c71a45f8b | |||
| a751f3aa97 | |||
|
|
bb8f42774f | ||
|
|
d902abe57d | ||
| 873d873b4e | |||
| 3dd4aa231e | |||
| 87d943fc63 | |||
| d6f5c19616 | |||
| 2fc9e7650a | |||
| 0cc4ea2936 | |||
| 1ce367999e | |||
| f15f27e17a | |||
| 31d4e641f8 | |||
| 9b211f804f | |||
| c3e1f08908 | |||
| 76bd01e458 | |||
| 7dbe56da33 | |||
| f5bc3980dd | |||
| b37d795818 | |||
| 4b64eb35aa | |||
| ee161ee7f6 | |||
| b0d241c22e | |||
| 9ac90d3fef | |||
| 17ce193e43 | |||
| 8c64c35afd | |||
| 8d4163ed88 | |||
| 91a38dee28 | |||
| ca6296a276 | |||
| b1fd726226 | |||
| d924716d6a | |||
| a383d56291 | |||
| c1a443efba | |||
| e77b72381b | |||
| 91883e132f | |||
| 91b2474981 | |||
| a19e8f6e34 | |||
| 895f2040aa | |||
| b6174e1055 | |||
| 040237447a | |||
| 7df2727fed | |||
| 0fb0c35d1d | |||
| db05632769 | |||
| f1af59b09a | |||
| 861ecabcac | |||
| 3117a5b047 | |||
| d90acae078 | |||
| 26b1f21e86 | |||
| 555996d72e | |||
| 9f9941f45d | |||
| fd1db5134a | |||
| ff83880144 | |||
| 21c295b26a | |||
| 673f208792 | |||
| 7a82081af2 | |||
| 68e56eead0 | |||
| d8ac9530d8 | |||
| 63c3d47f3d | |||
| 8116315a6d | |||
| b892a1346d | |||
| 4942af1fae | |||
| b0935db1b8 | |||
| 3d83c95a72 | |||
| 96bd1fc4c2 | |||
| 45218f85af | |||
| 27f23cd321 | |||
| aba102d63c | |||
| 326ea8ae7e | |||
| bc87c88b25 | |||
| c08900c694 | |||
| 401658981c | |||
| b6115b7a16 | |||
| e9d40dcd82 | |||
| e36660c93e | |||
| 4a84558d2e | |||
| 08862ff98e |
5
.env
5
.env
@@ -1,5 +0,0 @@
|
|||||||
|
|
||||||
[JWT]
|
|
||||||
TTL=3600
|
|
||||||
REFRESH_TTL=20160
|
|
||||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
|
||||||
32
.env.dev
32
.env.dev
@@ -1,32 +0,0 @@
|
|||||||
APP_DEBUG = true
|
|
||||||
|
|
||||||
DB_TYPE = mysql
|
|
||||||
DB_HOST = localhost
|
|
||||||
DB_NAME = orico-official-website
|
|
||||||
DB_USER = orico-ow
|
|
||||||
DB_PASS = 14Xi17NIK8V2qAXE8oMataHEsaR8lE
|
|
||||||
DB_PORT = 3306
|
|
||||||
DB_CHARSET = utf8mb4
|
|
||||||
DB_PREFIX = ow_
|
|
||||||
|
|
||||||
DEFAULT_LANG = zh-cn
|
|
||||||
|
|
||||||
# 前端代理服务器ip(影响使用代理访问情况下的客户端ip获取)
|
|
||||||
PROXY_SERVER_IP[] = 120.79.27.160
|
|
||||||
|
|
||||||
[JWT]
|
|
||||||
TTL=3600
|
|
||||||
REFRESH_TTL=20160
|
|
||||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
|
||||||
|
|
||||||
# 后台不需要登录的接口
|
|
||||||
[ADMIN_AUTH]
|
|
||||||
WHITE_LIST[] = v1/user/login
|
|
||||||
WHITE_LIST[] = v1/user/captcha
|
|
||||||
|
|
||||||
# 不需记录日志的接口
|
|
||||||
[ADMIN_API]
|
|
||||||
IGNORE_LOGGING_LIST[] = v1/OperateLog/index
|
|
||||||
MAX_IMAGE_SIZE = 5mb # 图片上传最大限制
|
|
||||||
MAX_VIDEO_SIZE = 150mb # 视频上传最大限制
|
|
||||||
MAX_ATTACHMENT_SIZE = 100mb # 附件上传最大限制
|
|
||||||
55
.env.local
55
.env.local
@@ -1,55 +0,0 @@
|
|||||||
APP_DEBUG = true
|
|
||||||
|
|
||||||
DB_TYPE = mysql
|
|
||||||
DB_HOST = 127.0.0.1
|
|
||||||
DB_NAME = orico-official-website
|
|
||||||
DB_USER = orico-official-website
|
|
||||||
DB_PASS = 14Xi17NIK8V2qAXE8oMataHEsaR8lE
|
|
||||||
DB_PORT = 3306
|
|
||||||
DB_CHARSET = utf8mb4
|
|
||||||
DB_PREFIX = ow_
|
|
||||||
|
|
||||||
DEFAULT_LANG = zh-cn
|
|
||||||
|
|
||||||
# 前端代理服务器ip(影响使用代理访问情况下的客户端ip获取)
|
|
||||||
PROXY_SERVER_IP[] = 120.79.27.160
|
|
||||||
|
|
||||||
[JWT]
|
|
||||||
TTL=3600
|
|
||||||
REFRESH_TTL=20160
|
|
||||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
|
||||||
|
|
||||||
# 后台不需要登录的接口
|
|
||||||
[ADMIN_AUTH]
|
|
||||||
WHITE_LIST[] = v1/user/login
|
|
||||||
WHITE_LIST[] = v1/user/captcha
|
|
||||||
|
|
||||||
# 不需记录日志的接口
|
|
||||||
[ADMIN_API]
|
|
||||||
IGNORE_LOGGING_LIST[] = v1/OperateLog/index
|
|
||||||
MAX_IMAGE_SIZE = 5mb; # 图片上传最大限制
|
|
||||||
MAX_VIDEO_SIZE = 150mb; # 视频上传最大限制
|
|
||||||
MAX_ATTACHMENT_SIZE = 100mb; # 附件上传最大限制
|
|
||||||
|
|
||||||
# 开放API
|
|
||||||
[OPENAPI]
|
|
||||||
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
|
|
||||||
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
|
|
||||||
|
|
||||||
# 视图模板规则配置
|
|
||||||
[VIEW_TPL]
|
|
||||||
# 视图目录
|
|
||||||
# query 规则:URL参数 mtpl=1 表示移动端访问
|
|
||||||
# 例如:http://xxxx.com?mtpl=1
|
|
||||||
# domain 规则:根据特定域名,判断是否移动端访问
|
|
||||||
# 例如:http://mobile.orico.cn
|
|
||||||
RULE = query
|
|
||||||
# query 规则参数名
|
|
||||||
RULE_QUERY_NAME = mtpl
|
|
||||||
# query 规则参数值
|
|
||||||
RULE_QUERY_VALUE = 1
|
|
||||||
# domain 规则协议
|
|
||||||
RULE_DOMAIN_SCHEME[] = http
|
|
||||||
RULE_DOMAIN_SCHEME[] = https
|
|
||||||
# domain 规则域名
|
|
||||||
RULE_DOMAIN_HOST = mobile.orico.cn
|
|
||||||
95
.example.env
95
.example.env
@@ -1,11 +1,96 @@
|
|||||||
APP_DEBUG = true
|
APP_DEBUG = true
|
||||||
|
|
||||||
DB_TYPE = mysql
|
DB_TYPE = mysql
|
||||||
DB_HOST = 127.0.0.1
|
DB_HOST = localhost
|
||||||
DB_NAME = test
|
DB_NAME = orico-official-website
|
||||||
DB_USER = username
|
DB_USER = orico-ow
|
||||||
DB_PASS = password
|
DB_PASS = 14Xi17NIK8V2qAXE8oMataHEsaR8lE
|
||||||
DB_PORT = 3306
|
DB_PORT = 3306
|
||||||
DB_CHARSET = utf8
|
DB_CHARSET = utf8mb4
|
||||||
|
DB_PREFIX = ow_
|
||||||
|
DB_VERSION = 8
|
||||||
|
|
||||||
DEFAULT_LANG = zh-cn
|
DEFAULT_LANG = zh-cn
|
||||||
|
|
||||||
|
# 前端代理服务器ip(影响使用代理访问情况下的客户端ip获取)
|
||||||
|
PROXY_SERVER_IP[] = 120.79.27.160
|
||||||
|
|
||||||
|
# redis 配置
|
||||||
|
REDIS_HOST = 127.0.0.1
|
||||||
|
REDIS_PORT = 6379
|
||||||
|
REDIS_PASSWORD = ''
|
||||||
|
REDIS_PREFIX = ow:
|
||||||
|
|
||||||
|
[JWT]
|
||||||
|
TTL=3600
|
||||||
|
REFRESH_TTL=20160
|
||||||
|
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
||||||
|
|
||||||
|
# 七牛云存储配置
|
||||||
|
[QINIU_CLOUD]
|
||||||
|
BUCKET = orico-official-website
|
||||||
|
BASE_URL = //ow.static.f2b211.com
|
||||||
|
ACCESS_KEY = dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms
|
||||||
|
SECRET_KEY = KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q
|
||||||
|
|
||||||
|
# 后台不需要登录的接口
|
||||||
|
[ADMIN_AUTH]
|
||||||
|
WHITE_LIST[] = v1/user/login
|
||||||
|
WHITE_LIST[] = v1/user/captcha
|
||||||
|
WHITE_LIST[] = receive_sync/category
|
||||||
|
WHITE_LIST[] = receive_sync/product
|
||||||
|
|
||||||
|
# 不需记录日志的接口
|
||||||
|
[ADMIN_API]
|
||||||
|
IGNORE_LOGGING_LIST[] = v1/OperateLog/index
|
||||||
|
MAX_IMAGE_SIZE = 5mb; # 图片上传最大限制
|
||||||
|
MAX_VIDEO_SIZE = 150mb; # 视频上传最大限制
|
||||||
|
MAX_ATTACHMENT_SIZE = 100mb; # 附件上传最大限制
|
||||||
|
|
||||||
|
# 开放API
|
||||||
|
[OPENAPI]
|
||||||
|
ACCESS_TOKEN_LIFETIME = 3600; # 访问令牌有效期
|
||||||
|
REFRESH_TOKEN_LIFETIME = 1209600; # 刷新令牌有效期
|
||||||
|
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
|
||||||
|
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
|
||||||
|
|
||||||
|
# 七牛云存储配置
|
||||||
|
[QINUI]
|
||||||
|
BUCKET = orico
|
||||||
|
BASE_URL = http://local.orico.com
|
||||||
|
ACCESS_KEY = 1234567890
|
||||||
|
SECRET_KEY = 1234567890
|
||||||
|
|
||||||
|
# 前台视图模板规则配置
|
||||||
|
[INDEX_VIEW_TPL]
|
||||||
|
# 视图目录
|
||||||
|
# query 规则:URL参数 mtpl=1 表示移动端访问
|
||||||
|
# 例如:http://xxxx.com?mtpl=1
|
||||||
|
# domain 规则:根据特定域名,判断是否移动端访问
|
||||||
|
# 例如:http://mobile.orico.cn
|
||||||
|
RULE = query
|
||||||
|
# query 规则参数名
|
||||||
|
RULE_QUERY_NAME = mtpl
|
||||||
|
# query 规则参数值
|
||||||
|
RULE_QUERY_VALUE = 1
|
||||||
|
# domain 规则协议
|
||||||
|
RULE_DOMAIN_SCHEME[] = http
|
||||||
|
RULE_DOMAIN_SCHEME[] = https
|
||||||
|
# domain 规则域名
|
||||||
|
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
|
||||||
|
|||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -3,7 +3,13 @@ composer.phar
|
|||||||
composer.lock
|
composer.lock
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
.env
|
||||||
|
.env.dev
|
||||||
|
.env.local
|
||||||
|
.env.prod
|
||||||
|
|
||||||
|
public/dist
|
||||||
|
public/opendoc
|
||||||
/.idea
|
/.idea
|
||||||
/.vscode
|
/.vscode
|
||||||
/vendor
|
/vendor
|
||||||
|
|||||||
219
app/admin/controller/ReceiveProductSync.php
Normal file
219
app/admin/controller/ReceiveProductSync.php
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller;
|
||||||
|
|
||||||
|
use app\admin\model\v1\LanguageModel;
|
||||||
|
use app\admin\model\v1\ProductCategoryModel;
|
||||||
|
use app\admin\model\v1\ProductModel;
|
||||||
|
use app\admin\model\v1\ProductTcoCategoryModel;
|
||||||
|
use think\facade\Db;
|
||||||
|
|
||||||
|
class Operate_Of_ReceiveSync
|
||||||
|
{
|
||||||
|
const Add = 'add';
|
||||||
|
const Update = 'update';
|
||||||
|
const Enable = 'enable';
|
||||||
|
const Disable = 'disable';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收产品相关同步数据
|
||||||
|
*/
|
||||||
|
class ReceiveProductSync
|
||||||
|
{
|
||||||
|
// 接收产品目录分类同步数据
|
||||||
|
public function category()
|
||||||
|
{
|
||||||
|
$data = request()->post();
|
||||||
|
if (empty($data)) return error('请确认同步数据');
|
||||||
|
|
||||||
|
$validate = validate([
|
||||||
|
'name|分类名称' => 'require',
|
||||||
|
'erp_code|分类ERP编码' => 'require',
|
||||||
|
]);
|
||||||
|
if (!$validate->check($data)) {
|
||||||
|
return error((string)$validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取对应语言ID
|
||||||
|
$lang_id = LanguageModel::where('code', $data['lang'])->value('id');
|
||||||
|
if (empty($lang_id)) {
|
||||||
|
return error('语言不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
Db::startTrans();
|
||||||
|
try {
|
||||||
|
$tco_category_data = [
|
||||||
|
'language_id' => $lang_id,
|
||||||
|
'name' => $data['name'],
|
||||||
|
'tco_id' => $data['tco_id'],
|
||||||
|
'tco_pid' => $data['tco_pid'],
|
||||||
|
'tco_path' => $data['tco_path'],
|
||||||
|
'erp_id' => $data['erp_id'],
|
||||||
|
'erp_pid' => $data['erp_pid'],
|
||||||
|
'erp_code' => $data['erp_code'],
|
||||||
|
'erp_path' => $data['erp_path'],
|
||||||
|
'disabled' => Operate_Of_ReceiveSync::Disable == $data['operate'] ? 1 : 0,
|
||||||
|
'sync_time' => strtotime($data['created_at'])
|
||||||
|
];
|
||||||
|
$tco_category = ProductTcoCategoryModel::language($lang_id)->erpCode($tco_category_data['erp_code'])->find();
|
||||||
|
if (empty($tco_category)) {
|
||||||
|
$tco_category = ProductTcoCategoryModel::create($tco_category_data);
|
||||||
|
if ($tco_category->isEmpty()) {
|
||||||
|
throw new \Exception('产品目录分类创建失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
$category_data = [
|
||||||
|
'language_id' => $lang_id,
|
||||||
|
'unique_id' => uniqid('PRO_CATE_'),
|
||||||
|
'pid' => 0,
|
||||||
|
'path' => '',
|
||||||
|
'name' => $tco_category_data['name'],
|
||||||
|
'icon' => '',
|
||||||
|
'desc' => '',
|
||||||
|
'related_tco_category' => $tco_category['id'],
|
||||||
|
'sort' => 0,
|
||||||
|
'level' => 1,
|
||||||
|
'is_show' => 1,
|
||||||
|
];
|
||||||
|
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
|
||||||
|
if (!empty($tco_parent)) {
|
||||||
|
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
|
||||||
|
if ($parent->isEmpty()) {
|
||||||
|
throw new \Exception('产品分类父级不存在');
|
||||||
|
}
|
||||||
|
$category_data['pid'] = $parent['id'];
|
||||||
|
$category_data['path'] = $parent['path'] . $parent['pid'];
|
||||||
|
$category_data['level'] = $parent['level'] + 1;
|
||||||
|
}
|
||||||
|
$category = ProductCategoryModel::create($category_data);
|
||||||
|
if ($category->isEmpty()) {
|
||||||
|
throw new \Exception('产品分类创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($tco_category['sync_time'] < $tco_category_data['sync_time']) {
|
||||||
|
$success = $tco_category->save($tco_category_data);
|
||||||
|
if (!$success) {
|
||||||
|
throw new \Exception('产品目录分类更新失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
$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();
|
||||||
|
if (!empty($tco_parent)) {
|
||||||
|
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
|
||||||
|
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('产品分类更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Db::commit();
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Db::rollback();
|
||||||
|
return error(sprintf('%s %s:%d', $th->getMessage(), $th->getFile(), $th->getLine()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('同步成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收产品同步数据
|
||||||
|
public function product()
|
||||||
|
{
|
||||||
|
$data = request()->post();
|
||||||
|
if (empty($data)) {
|
||||||
|
return error('请确认同步数据');
|
||||||
|
}
|
||||||
|
|
||||||
|
$validate = validate([
|
||||||
|
'spu' => 'require',
|
||||||
|
'name' => 'require',
|
||||||
|
'category_erp_code' => 'require',
|
||||||
|
'lang' => 'require',
|
||||||
|
'created_at' => 'require',
|
||||||
|
]);
|
||||||
|
if (!$validate->check($data)) {
|
||||||
|
return error((string)$validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取对应语言ID
|
||||||
|
$lang_id = LanguageModel::where('code', $data['lang'])->value('id');
|
||||||
|
if (empty($lang_id)) {
|
||||||
|
return error('语言不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 spu_before_modification 存在则根据 spu_before_modification 更新型号
|
||||||
|
$product = null;
|
||||||
|
if (!empty($data['spu_before_modification'])) {
|
||||||
|
$product = ProductModel::language($lang_id)->spu($data['spu_before_modification'])->find();
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(empty($data['spu_before_modification']) && !empty($data['spu']))
|
||||||
|
// 避免 spu_before_modification 更新型号时,人为删除了旧型号导致的新增,从而出现重复型号问题,而进行再次验证
|
||||||
|
|| (!empty($data['spu_before_modification']) && empty($product))
|
||||||
|
) {
|
||||||
|
$product = ProductModel::language($lang_id)->spu($data['spu'])->find();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$product_tco_category = ProductTcoCategoryModel::language($lang_id)->erpCode($data['category_erp_code'])->find();
|
||||||
|
if (empty($product_tco_category)) {
|
||||||
|
throw new \Exception('官网未找到产品目录同步分类');
|
||||||
|
}
|
||||||
|
|
||||||
|
$product_category = ProductCategoryModel::language($lang_id)->tcoId($product_tco_category['id'])->find();
|
||||||
|
if (empty($product_category)) {
|
||||||
|
throw new \Exception('官网未找到产品目录同步分类关联的分类');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($product)) {
|
||||||
|
$product = ProductModel::create([
|
||||||
|
'language_id' => $lang_id,
|
||||||
|
'category_id' => $product_category['id'],
|
||||||
|
'spu' => $data['spu'],
|
||||||
|
'name' => $data['name'],
|
||||||
|
'short_name' => '',
|
||||||
|
'cover_image' => '',
|
||||||
|
'desc' => '',
|
||||||
|
'video_img' => '',
|
||||||
|
'video_url' => '',
|
||||||
|
'is_sale' => 1,
|
||||||
|
'is_new' => 0,
|
||||||
|
'is_hot' => 0,
|
||||||
|
'is_show' => 0,
|
||||||
|
'sort' => 0,
|
||||||
|
'detail' => '',
|
||||||
|
'status' => Operate_Of_ReceiveSync::Disable == $data['operate'] ? -1 : 1,
|
||||||
|
'seo_title' => '',
|
||||||
|
'seo_keywords' => '',
|
||||||
|
'seo_desc' => '',
|
||||||
|
'updated_at' => $data['created_at'],
|
||||||
|
]);
|
||||||
|
if ($product->isEmpty()) {
|
||||||
|
throw new \Exception('产品创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strtotime($product['updated_at']) < strtotime($data['created_at'])) {
|
||||||
|
$product->spu = $data['spu'];
|
||||||
|
$product->name = $data['name'];
|
||||||
|
$product->category_id = $product_category['id'];
|
||||||
|
$product->status = Operate_Of_ReceiveSync::Disable == $data['operate'] ? -1 : 1;
|
||||||
|
if (!$product->save()) {
|
||||||
|
throw new \Exception('产品更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return error(sprintf('%s %s:%d', $th->getMessage(), $th->getFile(), $th->getLine()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('同步成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare (strict_types = 1);
|
|
||||||
|
|
||||||
namespace app\admin\controller;
|
|
||||||
|
|
||||||
use app\admin\model\v1\LanguageModel;
|
|
||||||
use app\admin\model\v1\ProductCategoryModel;
|
|
||||||
use app\admin\model\v1\ProductTcoCategoryModel;
|
|
||||||
use think\facade\Db;
|
|
||||||
|
|
||||||
class Operate_Of_ReceiveSync
|
|
||||||
{
|
|
||||||
const Add = 'add';
|
|
||||||
const Update = 'update';
|
|
||||||
const Enable = 'enable';
|
|
||||||
const Disable = 'disable';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 接收同步数据
|
|
||||||
*/
|
|
||||||
class ReceiveSync
|
|
||||||
{
|
|
||||||
public function product_category()
|
|
||||||
{
|
|
||||||
$data = request()->post();
|
|
||||||
if (empty($data)) return error('请确认同步数据');
|
|
||||||
|
|
||||||
$lang_id = LanguageModel::where('code', $data['lang'])->value('id');
|
|
||||||
$record = [
|
|
||||||
'language_id' => $lang_id,
|
|
||||||
'name' => $data['name'],
|
|
||||||
'tco_id' => $data['tco_id'],
|
|
||||||
'tco_pid' => $data['tco_pid'],
|
|
||||||
'tco_path' => $data['tco_path'],
|
|
||||||
'erp_id' => $data['erp_id'],
|
|
||||||
'erp_pid' => $data['erp_pid'],
|
|
||||||
'erp_code' => $data['erp_code'],
|
|
||||||
'erp_path' => $data['erp_path'],
|
|
||||||
'disabled' => 0,
|
|
||||||
'sync_time' => strtotime($data['created_at'])
|
|
||||||
];
|
|
||||||
|
|
||||||
if (Operate_Of_ReceiveSync::Disable == $data['operate']) {
|
|
||||||
$record['disabled'] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$validate = validate([
|
|
||||||
'name|分类名称' => 'require',
|
|
||||||
'erp_code|分类ERP编码' => 'require',
|
|
||||||
]);
|
|
||||||
if (!$validate->check($record)) {
|
|
||||||
throw new \Exception((string)$validate->getError());
|
|
||||||
}
|
|
||||||
|
|
||||||
$category = ProductTcoCategoryModel::language($lang_id)->erpCode($record['erp_code'])->find();
|
|
||||||
Db::startTrans();
|
|
||||||
try {
|
|
||||||
if (empty($category)) {
|
|
||||||
ProductTcoCategoryModel::create($record);
|
|
||||||
ProductCategoryModel::where
|
|
||||||
} else {
|
|
||||||
$category->save($record);
|
|
||||||
}
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
Db::rollback();
|
|
||||||
throw $th;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件上传控制器
|
* 文件上传控制器
|
||||||
@@ -45,17 +46,39 @@ class Upload
|
|||||||
// 获取图片上传配置
|
// 获取图片上传配置
|
||||||
list(
|
list(
|
||||||
'filename_keep' => $filename_keep,
|
'filename_keep' => $filename_keep,
|
||||||
'filemd5_unique' => $filemd5_unique
|
'filemd5_unique' => $filemd5_unique,
|
||||||
|
'filetype_to' => $filetype_to,
|
||||||
) = $this->getUploadOptions('upload_image');
|
) = $this->getUploadOptions('upload_image');
|
||||||
|
|
||||||
|
// 获取文件大小
|
||||||
|
$file_size = $file->getSize();
|
||||||
|
// 获取文件mime类型
|
||||||
|
$mime_type = $file->getOriginalMime();
|
||||||
|
|
||||||
// 是否需要根据文件MD5值检查文件是否已存在
|
// 是否需要根据文件MD5值检查文件是否已存在
|
||||||
$image_model = $filemd5_unique ? SysImageUploadRecordModel::md5($filemd5)->find() : null;
|
$image_model = $filemd5_unique ? SysImageUploadRecordModel::md5($filemd5)->find() : null;
|
||||||
if (is_null($image_model)) {
|
if (is_null($image_model)) {
|
||||||
// 检查是否需要保留原文件名生成器
|
// 检查是否需要保留原文件名生成器
|
||||||
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
||||||
$filename = Filesystem::disk('image')->putFile($param['module'], $file, $name_rule());
|
|
||||||
// 处理图片
|
// 处理图片
|
||||||
$image_manager = ImageManager::imagick();
|
$image_manager = ImageManager::gd();
|
||||||
|
if ($filetype_to == 'original') {
|
||||||
|
$filename = Filesystem::disk('image')->putFile($param['module'], $file, $name_rule());
|
||||||
$image = $image_manager->read('.' . $storage . '/' . $filename);
|
$image = $image_manager->read('.' . $storage . '/' . $filename);
|
||||||
|
}
|
||||||
|
else if ($filetype_to == 'webp') {
|
||||||
|
$image = $image_manager->read($file->getRealPath());
|
||||||
|
// 转换为webp格式
|
||||||
|
$webp = $image->toWebp(75);
|
||||||
|
$root = config('filesystem.disks.image.root');
|
||||||
|
$filename = $param['module'] . '/' . ($name_rule() ? $name_rule()() : date('Ymd') . '/' . md5((string)time() . random_str(8))) . '.webp';
|
||||||
|
$webp->save($this->checkPath($root . '/' . $filename));
|
||||||
|
// 获取webp文件大小
|
||||||
|
$file_size = $webp->size();
|
||||||
|
// 获取webp文件mime类型
|
||||||
|
$mime_type = $webp->mimetype();
|
||||||
|
}
|
||||||
|
|
||||||
// 水印
|
// 水印
|
||||||
list(
|
list(
|
||||||
@@ -131,10 +154,10 @@ 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->getSize();
|
$image_model->file_size = $file_size;
|
||||||
$image_model->file_type = $file->getOriginalMime();
|
$image_model->file_type = $mime_type;
|
||||||
$image_model->file_md5 = $filemd5;
|
$image_model->file_md5 = $filemd5;
|
||||||
$image_model->file_sha1 = $filesha1;
|
$image_model->file_sha1 = $filesha1;
|
||||||
if (!$image_model->save()) {
|
if (!$image_model->save()) {
|
||||||
@@ -143,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
|
||||||
]);
|
]);
|
||||||
@@ -154,6 +177,30 @@ class Upload
|
|||||||
|
|
||||||
return error('上传失败');
|
return error('上传失败');
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 检查路径
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function checkPath($path): string
|
||||||
|
{
|
||||||
|
$ok = true;
|
||||||
|
$filename = basename($path);
|
||||||
|
$dirname = dirname($path);
|
||||||
|
if (!is_dir($dirname)) {
|
||||||
|
$ok = @mkdir($dirname, 0755, true);
|
||||||
|
}
|
||||||
|
else if (!is_writable($dirname)) {
|
||||||
|
$ok = @chmod($dirname,0755);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ok) {
|
||||||
|
return $dirname . '/' . $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \Exception("上传目标目录不可用");
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 文件名生成回调
|
* 文件名生成回调
|
||||||
*
|
*
|
||||||
@@ -175,10 +222,12 @@ class Upload
|
|||||||
$config_model = new \app\admin\controller\v1\SiteConfig;
|
$config_model = new \app\admin\controller\v1\SiteConfig;
|
||||||
$config = $config_model->getByGroupUniqueLabel('upload');
|
$config = $config_model->getByGroupUniqueLabel('upload');
|
||||||
$options = data_get($config, $module, []);
|
$options = data_get($config, $module, []);
|
||||||
throw_if(empty($options), '上传配置错误');
|
|
||||||
return [
|
return [
|
||||||
'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'),
|
||||||
|
'save_to' => data_get($options, 'save_to.value', 'local'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -220,7 +269,7 @@ class Upload
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 计算文体水印偏移量
|
* 计算文本水印偏移量
|
||||||
*
|
*
|
||||||
* @param string $position
|
* @param string $position
|
||||||
* @param integer $offset_x
|
* @param integer $offset_x
|
||||||
@@ -298,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;
|
||||||
@@ -322,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
|
||||||
]);
|
]);
|
||||||
@@ -352,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;
|
||||||
@@ -380,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;
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ class ProductCategoryModel extends ProductCategoryBaseModel
|
|||||||
$query->where('language_id', '=', $value);
|
$query->where('language_id', '=', $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 所属产品目录分类id查询
|
||||||
|
public function scopeTcoId($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('related_tco_category', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据是否显示查询
|
* 根据是否显示查询
|
||||||
* @param $query
|
* @param $query
|
||||||
|
|||||||
@@ -80,6 +80,12 @@ class ProductModel extends ProductBaseModel
|
|||||||
$query->where('category_id', '=', $value);
|
$query->where('category_id', '=', $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 规格型号查询
|
||||||
|
public function scopeSpu($query, $spu)
|
||||||
|
{
|
||||||
|
$query->where('spu', '=', $spu);
|
||||||
|
}
|
||||||
|
|
||||||
// 启用状态查询
|
// 启用状态查询
|
||||||
public function scopeEnabled($query)
|
public function scopeEnabled($query)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ class ProductTcoCategoryModel extends ProductTcoCategoryBaseModel
|
|||||||
$query->where('language_id', '=', $value);
|
$query->where('language_id', '=', $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据 tco_id 查询
|
||||||
|
public function scopeTcoId($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('tco_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
// 根据ERP Code查询
|
// 根据ERP Code查询
|
||||||
public function scopeErpCode($query, $value)
|
public function scopeErpCode($query, $value)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -616,6 +616,12 @@ Route::group('v1', function () {
|
|||||||
});
|
});
|
||||||
})->prefix('v1.');
|
})->prefix('v1.');
|
||||||
|
|
||||||
|
// 接收产品目录同步数据
|
||||||
|
Route::group('receive_sync', function () {
|
||||||
|
Route::post('category', 'ReceiveProductSync/category');
|
||||||
|
Route::post('product', 'ReceiveProductSync/product');
|
||||||
|
});
|
||||||
|
|
||||||
Route::miss(function() {
|
Route::miss(function() {
|
||||||
return '404 Not Found!';
|
return '404 Not Found!';
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -64,7 +64,10 @@ class ArticleCategoryValidate extends Validate
|
|||||||
if ($value == 0) {
|
if ($value == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$children = [];
|
||||||
$table_name = (new ArticleCategoryModel)->getTable();
|
$table_name = (new ArticleCategoryModel)->getTable();
|
||||||
|
if (env('DB_VERSION', '5') == '8') {
|
||||||
$children = Db::query(
|
$children = Db::query(
|
||||||
preg_replace(
|
preg_replace(
|
||||||
'/\s+/u',
|
'/\s+/u',
|
||||||
@@ -77,6 +80,20 @@ class ArticleCategoryValidate extends Validate
|
|||||||
SELECT id FROM article_tree_by WHERE id <> {$data['id']};"
|
SELECT id FROM article_tree_by WHERE id <> {$data['id']};"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
$children = \think\facade\Db::query("
|
||||||
|
SELECT t2.id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
@r AS _id, (SELECT @r := GROUP_CONCAT(id) FROM $table_name WHERE FIND_IN_SET(pid, _id)) AS parent_id
|
||||||
|
FROM
|
||||||
|
(SELECT @r := {$data['id']}) vars, $table_name h
|
||||||
|
WHERE @r <> 0) t1
|
||||||
|
JOIN $table_name t2
|
||||||
|
ON FIND_IN_SET(t2.pid, t1._id)
|
||||||
|
ORDER BY t2.id;
|
||||||
|
");
|
||||||
|
}
|
||||||
if (!empty($children) && in_array($data['pid'], array_column($children, 'id'))) {
|
if (!empty($children) && in_array($data['pid'], array_column($children, 'id'))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ class ArticleValidate extends Validate
|
|||||||
'sort' => 'integer',
|
'sort' => 'integer',
|
||||||
'recommend' => 'require|in:0,1',
|
'recommend' => 'require|in:0,1',
|
||||||
'release_time' => 'dateFormat:Y-m-d H:i:s',
|
'release_time' => 'dateFormat:Y-m-d H:i:s',
|
||||||
'seo_title' => 'max:255',
|
'seo_title' => 'max:512',
|
||||||
'seo_keywords' => 'max:255',
|
'seo_keywords' => 'max:512',
|
||||||
'seo_desc' => 'max:255'
|
'seo_desc' => 'max:1024'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,8 +48,8 @@ class ArticleValidate extends Validate
|
|||||||
'recommend.require' => '推荐状态不能为空',
|
'recommend.require' => '推荐状态不能为空',
|
||||||
'recommend.in' => '推荐状态的值必须是0或1',
|
'recommend.in' => '推荐状态的值必须是0或1',
|
||||||
'release_time.dateFormat' => '发布时间格式不正确',
|
'release_time.dateFormat' => '发布时间格式不正确',
|
||||||
'seo_title.max' => 'SEO标题长度不能超过255个字符',
|
'seo_title.max' => 'SEO标题长度不能超过512个字符',
|
||||||
'seo_keywords.max' => 'SEO关键字长度不能超过255个字符',
|
'seo_keywords.max' => 'SEO关键字长度不能超过512个字符',
|
||||||
'seo_desc.max' => 'SEO描述长度不能超过255个字符'
|
'seo_desc.max' => 'SEO描述长度不能超过1024个字符'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,10 @@ class AttachmentCategoryValidate extends Validate
|
|||||||
if ($value == 0) {
|
if ($value == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$children = [];
|
||||||
$table_name = (new AttachmentCategoryModel)->getTable();
|
$table_name = (new AttachmentCategoryModel)->getTable();
|
||||||
|
if (env('DB_VERSION', '5') == '8') {
|
||||||
$children = Db::query(
|
$children = Db::query(
|
||||||
preg_replace(
|
preg_replace(
|
||||||
'/\s+/u',
|
'/\s+/u',
|
||||||
@@ -62,6 +65,20 @@ class AttachmentCategoryValidate extends Validate
|
|||||||
SELECT id FROM attachment_tree_by WHERE id <> {$data['id']};"
|
SELECT id FROM attachment_tree_by WHERE id <> {$data['id']};"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
$children = \think\facade\Db::query("
|
||||||
|
SELECT t2.id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
@r AS _id, (SELECT @r := GROUP_CONCAT(id) FROM $table_name WHERE FIND_IN_SET(pid, _id)) AS parent_id
|
||||||
|
FROM
|
||||||
|
(SELECT @r := {$data['id']}) vars, $table_name h
|
||||||
|
WHERE @r <> 0) t1
|
||||||
|
JOIN $table_name t2
|
||||||
|
ON FIND_IN_SET(t2.pid, t1._id)
|
||||||
|
ORDER BY t2.id;
|
||||||
|
");
|
||||||
|
}
|
||||||
if (!empty($children) && in_array($data['pid'], array_column($children, 'id'))) {
|
if (!empty($children) && in_array($data['pid'], array_column($children, 'id'))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ class NavigationItemValidate extends Validate
|
|||||||
if ($value == 0) {
|
if ($value == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$children = [];
|
||||||
$table_name = (new SysNavigationItemModel)->getTable();
|
$table_name = (new SysNavigationItemModel)->getTable();
|
||||||
|
if (env('DB_VERSION', '5') == '8') {
|
||||||
$children = Db::query(
|
$children = Db::query(
|
||||||
preg_replace(
|
preg_replace(
|
||||||
'/\s+/u',
|
'/\s+/u',
|
||||||
@@ -74,6 +77,20 @@ class NavigationItemValidate extends Validate
|
|||||||
SELECT id FROM tree_by WHERE id <> {$data['id']};"
|
SELECT id FROM tree_by WHERE id <> {$data['id']};"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
$children = \think\facade\Db::query("
|
||||||
|
SELECT t2.id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
@r AS _id, (SELECT @r := GROUP_CONCAT(id) FROM $table_name WHERE FIND_IN_SET(pid, _id)) AS parent_id
|
||||||
|
FROM
|
||||||
|
(SELECT @r := {$data['id']}) vars, $table_name h
|
||||||
|
WHERE @r <> 0) t1
|
||||||
|
JOIN $table_name t2
|
||||||
|
ON FIND_IN_SET(t2.pid, t1._id)
|
||||||
|
ORDER BY t2.id;
|
||||||
|
");
|
||||||
|
}
|
||||||
if (!empty($children) && in_array($data['pid'], array_column($children, 'id'))) {
|
if (!empty($children) && in_array($data['pid'], array_column($children, 'id'))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -74,7 +74,10 @@ class SysMenuValidate extends Validate
|
|||||||
if ($value == 0) {
|
if ($value == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$children = [];
|
||||||
$table_name = (new SysMenuModel)->getTable();
|
$table_name = (new SysMenuModel)->getTable();
|
||||||
|
if (env('DB_VERSION', '5') == '8') {
|
||||||
$children = Db::query(
|
$children = Db::query(
|
||||||
preg_replace(
|
preg_replace(
|
||||||
'/\s+/u',
|
'/\s+/u',
|
||||||
@@ -87,6 +90,20 @@ class SysMenuValidate extends Validate
|
|||||||
SELECT id FROM menu_tree_by WHERE id <> {$data['id']};"
|
SELECT id FROM menu_tree_by WHERE id <> {$data['id']};"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
$children = \think\facade\Db::query("
|
||||||
|
SELECT t2.id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
@r AS _id, (SELECT @r := GROUP_CONCAT(id) FROM $table_name WHERE FIND_IN_SET(pid, _id)) AS parent_id
|
||||||
|
FROM
|
||||||
|
(SELECT @r := {$data['id']}) vars, $table_name h
|
||||||
|
WHERE @r <> 0) t1
|
||||||
|
JOIN $table_name t2
|
||||||
|
ON FIND_IN_SET(t2.pid, t1._id)
|
||||||
|
ORDER BY t2.id;
|
||||||
|
");
|
||||||
|
}
|
||||||
if (!empty($children) && in_array($data['pid'], array_column($children, 'id'))) {
|
if (!empty($children) && in_array($data['pid'], array_column($children, 'id'))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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' => '链接格式错误',
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ class DataMigration extends Command
|
|||||||
|
|
||||||
// 迁移文章
|
// 迁移文章
|
||||||
// $this->migrateArticle([
|
// $this->migrateArticle([
|
||||||
|
// 16 => 7,
|
||||||
|
// 31 => 9,
|
||||||
|
// 32 => 8,
|
||||||
// 68 => 10,
|
// 68 => 10,
|
||||||
// 69 => 11,
|
// 69 => 11,
|
||||||
// 70 => 12,
|
// 70 => 12,
|
||||||
@@ -290,14 +293,15 @@ class DataMigration extends Command
|
|||||||
$old_db = Db::connect('old');
|
$old_db = Db::connect('old');
|
||||||
|
|
||||||
$success_map = [];
|
$success_map = [];
|
||||||
$success_arr = include_once(runtime_path() . 'product_success.php');
|
$success_arr = []; // include_once(runtime_path() . 'product_success.php');
|
||||||
foreach ($success_arr as $so) {
|
foreach ($success_arr as $so) {
|
||||||
$success_map['p_' . $so['cod_product_id']] = $so;
|
$success_map['p_' . $so['cod_product_id']] = $so;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$arr = include_once(runtime_path() . 'product_ids.php');
|
||||||
$products = $old_db->name('product')
|
$products = $old_db->name('product')
|
||||||
->where('country_code', 'in', ['ZH', 'US'])
|
->where('country_code', 'in', ['ZH', 'US'])
|
||||||
->where('id', '>', 15789)
|
->where('id', 'in', array_unique(array_column($arr, 'cod_product_id')))
|
||||||
->order(['id' => 'asc'])
|
->order(['id' => 'asc'])
|
||||||
->cursor();
|
->cursor();
|
||||||
|
|
||||||
@@ -374,7 +378,16 @@ class DataMigration extends Command
|
|||||||
'deleted_at' => $v['stat'] == -1 ? date('Y-m-d H:i:s') : null,
|
'deleted_at' => $v['stat'] == -1 ? date('Y-m-d H:i:s') : null,
|
||||||
];
|
];
|
||||||
// 保存产品数据
|
// 保存产品数据
|
||||||
|
$prod = Db::name('product')
|
||||||
|
->where('language_id', '=', $item['language_id'])
|
||||||
|
->where('spu', '=', $item['spu'])
|
||||||
|
->find();
|
||||||
|
if (!empty($prod)) {
|
||||||
|
$id = $prod['id'];
|
||||||
|
Db::name('product')->where('id', '=', $prod['id'])->update($item);
|
||||||
|
} else {
|
||||||
$id = Db::name('product')->insertGetId($item);
|
$id = Db::name('product')->insertGetId($item);
|
||||||
|
}
|
||||||
|
|
||||||
// 保存产品参数数据
|
// 保存产品参数数据
|
||||||
if (!empty($v['product_view'])) {
|
if (!empty($v['product_view'])) {
|
||||||
@@ -387,7 +400,21 @@ class DataMigration extends Command
|
|||||||
'value' => $p['desc_desc']
|
'value' => $p['desc_desc']
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
$old_params = Db::name('product_params')
|
||||||
|
->where('product_id', '=', $id)
|
||||||
|
->select();
|
||||||
|
if ($old_params->isEmpty()) {
|
||||||
Db::name('product_params')->insertAll($prarms);
|
Db::name('product_params')->insertAll($prarms);
|
||||||
|
} else {
|
||||||
|
foreach ($old_params as $op) {
|
||||||
|
Db::name('product_params')
|
||||||
|
->where('product_id', '=', $id)
|
||||||
|
->where('name', '=', $op['name'])
|
||||||
|
->update([
|
||||||
|
'value' => $op['value']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存sku数据
|
// 保存sku数据
|
||||||
@@ -444,7 +471,7 @@ class DataMigration extends Command
|
|||||||
if ($k != 'sort') {
|
if ($k != 'sort') {
|
||||||
$attr_value = $at;
|
$attr_value = $at;
|
||||||
if (in_array($k, ['颜色', 'Color'])) {
|
if (in_array($k, ['颜色', 'Color'])) {
|
||||||
if ($k == 'Color') $k = '颜色';
|
// if ($k == 'Color') $k = '颜色';
|
||||||
$attr_value = '/static/common/images/colors/' . $at . '.png';
|
$attr_value = '/static/common/images/colors/' . $at . '.png';
|
||||||
}
|
}
|
||||||
$images[$pkey]['color'] = $at;
|
$images[$pkey]['color'] = $at;
|
||||||
@@ -468,7 +495,7 @@ class DataMigration extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$attr_arr = [
|
$attr_arr = [
|
||||||
'attr_id' => $attrs_map[$v['country_code']]['颜色'],
|
'attr_id' => $attrs_map[$v['country_code']][$v['country_code'] == 'ZH' ? '颜色' : 'Color'],
|
||||||
'attr_value' => $attr_value,
|
'attr_value' => $attr_value,
|
||||||
];
|
];
|
||||||
if (
|
if (
|
||||||
@@ -514,7 +541,7 @@ class DataMigration extends Command
|
|||||||
$skus[] = [
|
$skus[] = [
|
||||||
'main_image' => $ti['image_url'],
|
'main_image' => $ti['image_url'],
|
||||||
'attrs' => [[
|
'attrs' => [[
|
||||||
'attr_id' => $attrs_map[$v['country_code']]['颜色'],
|
'attr_id' => $attrs_map[$v['country_code']][$v['country_code'] == 'ZH' ? '颜色' : 'Color'],
|
||||||
'attr_value' => $ti['image_color'],
|
'attr_value' => $ti['image_color'],
|
||||||
]],
|
]],
|
||||||
'pkey' => $tpkey
|
'pkey' => $tpkey
|
||||||
@@ -575,6 +602,7 @@ class DataMigration extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($skus as $sku) {
|
foreach ($skus as $sku) {
|
||||||
|
Db::name('product_sku')->where('product_id', '=', $sku['product_id'])->delete();
|
||||||
$sku_id = Db::name('product_sku')->insertGetId([
|
$sku_id = Db::name('product_sku')->insertGetId([
|
||||||
'product_id' => $sku['product_id'],
|
'product_id' => $sku['product_id'],
|
||||||
'sku' => $sku['sku']??'',
|
'sku' => $sku['sku']??'',
|
||||||
@@ -584,6 +612,7 @@ class DataMigration extends Command
|
|||||||
if (!empty($sku['attrs'])) {
|
if (!empty($sku['attrs'])) {
|
||||||
foreach ($sku['attrs'] as $attr) {
|
foreach ($sku['attrs'] as $attr) {
|
||||||
if (!empty($sku_id)) {
|
if (!empty($sku_id)) {
|
||||||
|
Db::name('product_sku_attr')->where('sku_id', '=', $sku_id)->delete();
|
||||||
Db::name('product_sku_attr')->insert([
|
Db::name('product_sku_attr')->insert([
|
||||||
'sku_id' => $sku_id,
|
'sku_id' => $sku_id,
|
||||||
'attr_id' => $attr['attr_id'],
|
'attr_id' => $attr['attr_id'],
|
||||||
@@ -601,7 +630,7 @@ class DataMigration extends Command
|
|||||||
sprintf('["ow_product_id" => %d, "cod_product_id" => %d]'.PHP_EOL, $id, $v['id']),
|
sprintf('["ow_product_id" => %d, "cod_product_id" => %d]'.PHP_EOL, $id, $v['id']),
|
||||||
FILE_APPEND
|
FILE_APPEND
|
||||||
);
|
);
|
||||||
$this->println(sprintf('迁移产品ID:%s => %s 【耗时:%s】', $v['id'], 0, round(microtime(true) - $start, 2) . 's'));
|
$this->println(sprintf('迁移产品ID:%s => %s 【耗时:%s】', $v['id'], $id, round(microtime(true) - $start, 2) . 's'));
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
Db::rollback();
|
Db::rollback();
|
||||||
file_put_contents(
|
file_put_contents(
|
||||||
@@ -694,9 +723,12 @@ class DataMigration extends Command
|
|||||||
throw new \Exception('请确认分类ID');
|
throw new \Exception('请确认分类ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1634
|
||||||
$article = Db::connect('old')
|
$article = Db::connect('old')
|
||||||
->name('article')
|
->name('article')
|
||||||
|
->where('country_code', 'in', ['ZH', 'US'])
|
||||||
->where('cid', 'in', array_keys($category_map))
|
->where('cid', 'in', array_keys($category_map))
|
||||||
|
->where('id', '=', 351)
|
||||||
->order(['id' => 'asc'])
|
->order(['id' => 'asc'])
|
||||||
->cursor();
|
->cursor();
|
||||||
|
|
||||||
@@ -745,7 +777,16 @@ class DataMigration extends Command
|
|||||||
'release_time' => date('Y-m-d H:i:s', $v['createtime']),
|
'release_time' => date('Y-m-d H:i:s', $v['createtime']),
|
||||||
'deleted_at' => $v['stat'] == -1 ? date('Y-m-d H:i:s') : null
|
'deleted_at' => $v['stat'] == -1 ? date('Y-m-d H:i:s') : null
|
||||||
];
|
];
|
||||||
|
$ret = Db::name('article')
|
||||||
|
->where('language_id', '=', $item['language_id'])
|
||||||
|
->where('title', '=', $item['title'])
|
||||||
|
->find();
|
||||||
|
if (empty($ret)) {
|
||||||
$id = Db::name('article')->insertGetId($item);
|
$id = Db::name('article')->insertGetId($item);
|
||||||
|
} else {
|
||||||
|
$id = $ret['id'];
|
||||||
|
Db::name('article')->where('id', '=', $ret['id'])->update($item);
|
||||||
|
}
|
||||||
|
|
||||||
$this->println(sprintf('迁移文章ID:%s => %s', $v['id'], $id));
|
$this->println(sprintf('迁移文章ID:%s => %s', $v['id'], $id));
|
||||||
}
|
}
|
||||||
@@ -779,7 +820,15 @@ class DataMigration extends Command
|
|||||||
'recommend' => $val['is_home'],
|
'recommend' => $val['is_home'],
|
||||||
'sort' => $val['sort'] == 9999 ? 0 : $val['sort']
|
'sort' => $val['sort'] == 9999 ? 0 : $val['sort']
|
||||||
];
|
];
|
||||||
|
$ret = Db::name('faq')
|
||||||
|
->where('language_id', '=', $item['language_id'])
|
||||||
|
->where('question', '=', $item['question'])
|
||||||
|
->find();
|
||||||
|
if (empty($ret)) {
|
||||||
Db::name('faq')->insert($item);
|
Db::name('faq')->insert($item);
|
||||||
|
} else {
|
||||||
|
Db::name('faq')->where('id', '=', $ret['id'])->update($item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,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();
|
||||||
@@ -921,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']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -929,7 +988,7 @@ class DataMigration extends Command
|
|||||||
|
|
||||||
class UploadMannager
|
class UploadMannager
|
||||||
{
|
{
|
||||||
const UPLOAD_BASE_API = 'http://dev.ow.f2b211.com';
|
const UPLOAD_BASE_API = 'http://ow.f2b211.com';
|
||||||
const DOWNLOAD_BASE_API = 'http://www.orico.com.cn';
|
const DOWNLOAD_BASE_API = 'http://www.orico.com.cn';
|
||||||
const DOWNLOAD_TEMP_PATH = '/var/www/html/orico-official-website/public/migrate_temp_images';
|
const DOWNLOAD_TEMP_PATH = '/var/www/html/orico-official-website/public/migrate_temp_images';
|
||||||
private $username = 'admin';
|
private $username = 'admin';
|
||||||
@@ -942,7 +1001,7 @@ class UploadMannager
|
|||||||
{
|
{
|
||||||
// 登录获取token
|
// 登录获取token
|
||||||
$this->token = $this->getAuthorization();
|
$this->token = $this->getAuthorization();
|
||||||
$this->maps = include_once(runtime_path() . 'fiber_product_image_mapping.php');
|
$this->maps = []; // include_once(runtime_path() . 'fiber_product_image_mapping.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下载图片
|
// 下载图片
|
||||||
@@ -1062,6 +1121,7 @@ class UploadMannager
|
|||||||
print($http_code . PHP_EOL);
|
print($http_code . PHP_EOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_put_contents(runtime_path() . 'upload.txt', $response . PHP_EOL, FILE_APPEND);
|
||||||
$ret = json_decode($response, true);
|
$ret = json_decode($response, true);
|
||||||
if (empty($ret)) {
|
if (empty($ret)) {
|
||||||
throw new \Exception($response);
|
throw new \Exception($response);
|
||||||
|
|||||||
42
app/command/OpenApiMgr/AddClient.php
Normal file
42
app/command/OpenApiMgr/AddClient.php
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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') {
|
||||||
@@ -226,18 +226,18 @@ if (!function_exists('get_platform')) {
|
|||||||
if (!function_exists('highlight_keywords')) {
|
if (!function_exists('highlight_keywords')) {
|
||||||
/**
|
/**
|
||||||
* 高亮关键词
|
* 高亮关键词
|
||||||
* @param string $item
|
* @param string $text // 要处理的文本
|
||||||
* @param string $keywords
|
* @param string $keyword // 关键词
|
||||||
* @param array $class
|
* @param string|callable $repalce // 替换函数或字符串
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function highlight_keywords(string $text, string $keywords, array $class=[]): string
|
function highlight_keywords(string $text, string $keyword, string|callable $replace): string
|
||||||
{
|
{
|
||||||
return preg_replace_callback('/' . preg_quote($keywords, '/') . '+/i', function($match) use($text, $class) {
|
return preg_replace_callback('/' . preg_quote($keyword, '/') . '+/i', function($match) use($text, $replace) {
|
||||||
if (empty($match)) {
|
if (empty($match)) return $text;
|
||||||
return $text;
|
if (is_string($replace)) return '<strong>' . $match[0] . '</strong>';
|
||||||
}
|
if (is_callable($replace)) return $replace($match[0]);
|
||||||
return '<strong class="' . implode(' ', $class) . '">' . $match[0] . '</strong>';
|
return $match[0];
|
||||||
}, $text);
|
}, $text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,9 +170,9 @@ class Article extends Common
|
|||||||
]);
|
]);
|
||||||
$ret = ArticleLeaveMessageModel::create($data);
|
$ret = ArticleLeaveMessageModel::create($data);
|
||||||
if ($ret->isEmpty()) {
|
if ($ret->isEmpty()) {
|
||||||
return error(lang('留言提交失败'));
|
return error(lang('信息提交失败!'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return success(lang('留言提交成功'));
|
return success(lang('信息已成功提交!'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ abstract class Common extends BaseController
|
|||||||
'language_id' => $language,
|
'language_id' => $language,
|
||||||
'status' => 1
|
'status' => 1
|
||||||
])
|
])
|
||||||
|
->where('status', '=', 1)
|
||||||
->order(['sort' => 'asc', 'id' => 'asc'])
|
->order(['sort' => 'asc', 'id' => 'asc'])
|
||||||
->select();
|
->select();
|
||||||
if ($nav->isEmpty()) {
|
if ($nav->isEmpty()) {
|
||||||
|
|||||||
@@ -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([
|
||||||
@@ -299,9 +299,10 @@ class Product extends Common
|
|||||||
'query' => request()->param()
|
'query' => request()->param()
|
||||||
])
|
])
|
||||||
->each(function ($item) use($keywords) {
|
->each(function ($item) use($keywords) {
|
||||||
$item['spu'] = highlight_keywords($item['spu'], $keywords, ['redpoint']);
|
$replace = fn($txt) => '<strong class="redpoint">' . $txt . '</strong>';
|
||||||
$item['name'] = highlight_keywords($item['name'], $keywords, ['redpoint']);
|
$item['spu'] = highlight_keywords($item['spu'], $keywords, $replace);
|
||||||
$item['short_name'] = highlight_keywords($item['short_name'], $keywords, ['redpoint']);
|
$item['name'] = highlight_keywords($item['name'], $keywords, $replace);
|
||||||
|
$item['short_name'] = highlight_keywords($item['short_name'], $keywords, $replace);
|
||||||
return $item;
|
return $item;
|
||||||
});
|
});
|
||||||
View::assign('products', $products);
|
View::assign('products', $products);
|
||||||
@@ -395,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) {
|
||||||
|
|||||||
@@ -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,14 +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'])
|
||||||
->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数据
|
||||||
@@ -245,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');
|
||||||
}
|
}
|
||||||
@@ -274,7 +337,9 @@ class TopicNas extends Common
|
|||||||
->value('id');
|
->value('id');
|
||||||
|
|
||||||
// 获取帮且中心分类子分类
|
// 获取帮且中心分类子分类
|
||||||
|
$categorys = [];
|
||||||
$table_name = (new ArticleCategoryModel)->getTable();
|
$table_name = (new ArticleCategoryModel)->getTable();
|
||||||
|
if (env('DB_VERSION', '5') == '8') {
|
||||||
$categorys = \think\facade\Db::query(preg_replace(
|
$categorys = \think\facade\Db::query(preg_replace(
|
||||||
'/\s+/u',
|
'/\s+/u',
|
||||||
' ',
|
' ',
|
||||||
@@ -285,6 +350,20 @@ class TopicNas extends Common
|
|||||||
)
|
)
|
||||||
SELECT id FROM article_tree_by WHERE id <> {$parent}"
|
SELECT id FROM article_tree_by WHERE id <> {$parent}"
|
||||||
));
|
));
|
||||||
|
} else {
|
||||||
|
$categorys = \think\facade\Db::query("
|
||||||
|
SELECT t2.id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
@r AS _id, (SELECT @r := GROUP_CONCAT(id) FROM $table_name WHERE FIND_IN_SET(pid, _id)) AS parent_id
|
||||||
|
FROM
|
||||||
|
(SELECT @r := $parent) vars, $table_name h
|
||||||
|
WHERE @r <> 0) t1
|
||||||
|
JOIN $table_name t2
|
||||||
|
ON FIND_IN_SET(t2.pid, t1._id)
|
||||||
|
ORDER BY t2.id;
|
||||||
|
");
|
||||||
|
}
|
||||||
if (empty($categorys)) return success('success', []);
|
if (empty($categorys)) return success('success', []);
|
||||||
|
|
||||||
// 获取文章数据
|
// 获取文章数据
|
||||||
@@ -299,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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()] ?? '';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -37,6 +41,13 @@
|
|||||||
<img src="{$photo}" alt="" />
|
<img src="{$photo}" alt="" />
|
||||||
</div>
|
</div>
|
||||||
{/volist}
|
{/volist}
|
||||||
|
{if condition="!empty($product.video_img) && !empty($product.video_url) && $idx == 1"}
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<video poster="{$product.video_img}" autoplay="autoplay" muted="muted" loop="loop" id="video" controls>
|
||||||
|
<source src="{$product.video_url}" type="video/mp4"/>
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<!-- 如果需要分页器 -->
|
<!-- 如果需要分页器 -->
|
||||||
<div class="swiper-pagination"></div>
|
<div class="swiper-pagination"></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,13 +11,12 @@
|
|||||||
<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}
|
||||||
<link rel="stylesheet" href="https://unpkg.com/swiper@9/swiper-bundle.min.css">
|
<link rel="stylesheet" href="__JS__/swiper-bundle9.4.1.min.css" />
|
||||||
<script type="text/javascript" src='https://code.jquery.com/jquery-3.6.0.min.js'></script>
|
<script src="__JS__/jquery-3.6.0.min.js"></script>
|
||||||
<script type="text/javascript" src="https://unpkg.com/swiper@9.4.1/swiper-bundle.min.js"></script>
|
<script type="text/javascript" src="__JS__/swiper-bundle9.4.1.min.js"></script>
|
||||||
<!-- Matomo -->
|
<!-- Matomo -->
|
||||||
<script>
|
<script>
|
||||||
var _paq = window._paq = window._paq || [];
|
var _paq = window._paq = window._paq || [];
|
||||||
@@ -27,7 +26,7 @@
|
|||||||
(function() {
|
(function() {
|
||||||
var u="//analytics.f2b211.com/";
|
var u="//analytics.f2b211.com/";
|
||||||
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||||
_paq.push(['setSiteId', '1']);
|
_paq.push(['setSiteId', '2']);
|
||||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||||
})();
|
})();
|
||||||
@@ -37,7 +36,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
<!-- Matomo Image Tracker-->
|
<!-- Matomo Image Tracker-->
|
||||||
<img referrerpolicy="no-referrer-when-downgrade" src="https://analytics.f2b211.com/matomo.php?idsite=1&rec=1" style="border:0" alt="" />
|
<img referrerpolicy="no-referrer-when-downgrade" src="https://analytics.f2b211.com/matomo.php?idsite=2&rec=1" style="border:0" alt="" />
|
||||||
<!-- End Matomo -->
|
<!-- End Matomo -->
|
||||||
</noscript>
|
</noscript>
|
||||||
{block name="header"}
|
{block name="header"}
|
||||||
|
|||||||
@@ -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,22 +12,30 @@
|
|||||||
<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">
|
||||||
<div class="it-ct">
|
|
||||||
<div class="it-1"><a href="/">{:lang_i18n('首页')}</a></div>
|
|
||||||
</div>
|
|
||||||
<div class="it-ct">
|
|
||||||
<div class="it-1">
|
|
||||||
<div class="it-1-more">{:lang_i18n('产品列表')}<i class="icon-arrow"></i></div>
|
|
||||||
{notempty name="header_categorys"}
|
|
||||||
{volist name="header_categorys" id="ca"}
|
|
||||||
<div class="it-1-2"><a href="{:url('product/category', ['id' => $ca.id])}">{$ca.name}</a></div>
|
|
||||||
{/volist}
|
|
||||||
{/notempty}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{notempty name="header_navigation"}
|
{notempty name="header_navigation"}
|
||||||
{volist name="header_navigation" id="nav"}
|
{volist name="header_navigation" id="nav"}
|
||||||
<div class="it-ct">
|
<div class="it-ct">
|
||||||
@@ -59,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>
|
||||||
@@ -54,18 +57,40 @@
|
|||||||
<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">
|
||||||
<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.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])}" 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>
|
||||||
@@ -73,10 +98,34 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{/volist}
|
{/volist}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{/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}
|
||||||
@@ -102,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();
|
||||||
@@ -110,6 +170,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 +209,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"}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="orico_Page_brand">
|
<div class="orico_Page_brand">
|
||||||
<!--内容 -->
|
<!--内容 -->
|
||||||
<div class="brandMain">
|
<div class="brandMain">
|
||||||
<img src="__IMAGES__/OurBrand.png" class="img-responsive" />
|
<img src="__IMAGES__/OurBrand.webp" class="img-responsive" />
|
||||||
{notempty name="banners"}
|
{notempty name="banners"}
|
||||||
<div class="our_brand_con">
|
<div class="our_brand_con">
|
||||||
{volist name="banners" id="ba" offset="0" length="2"}
|
{volist name="banners" id="ba" offset="0" length="2"}
|
||||||
|
|||||||
@@ -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"}
|
||||||
|
|||||||
@@ -7,14 +7,14 @@
|
|||||||
<!-- 内容 -->
|
<!-- 内容 -->
|
||||||
<div class="downloadMain">
|
<div class="downloadMain">
|
||||||
<div class="topimg">
|
<div class="topimg">
|
||||||
<img src="__IMAGES__/banner_01.png" />
|
<img src="__IMAGES__/banner_01.webp" />
|
||||||
<div class="banner_title">{:lang_i18n('软件和驱动程序')}</div>
|
<div class="banner_title">{:lang_i18n('软件和驱动程序')}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="contact_c">
|
<div class="contact_c">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<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>
|
||||||
|
|||||||
@@ -7,14 +7,14 @@
|
|||||||
<!-- 内容 -->
|
<!-- 内容 -->
|
||||||
<div class="downloadMain">
|
<div class="downloadMain">
|
||||||
<div class="topimg">
|
<div class="topimg">
|
||||||
<img src="__IMAGES__/banner_01.png" />
|
<img src="__IMAGES__/banner_01.webp" />
|
||||||
<div class="banner_title">{:lang_i18n('软件和驱动程序')}</div>
|
<div class="banner_title">{:lang_i18n('软件和驱动程序')}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="contact_c">
|
<div class="contact_c">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<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>
|
||||||
<!-- 产品主图切换和参数详情-->
|
<!-- 产品主图切换和参数详情-->
|
||||||
@@ -35,33 +39,26 @@
|
|||||||
<!-- 左边切换按钮 -->
|
<!-- 左边切换按钮 -->
|
||||||
<div class="scrollbutton smallImgUp disabled"></div>
|
<div class="scrollbutton smallImgUp disabled"></div>
|
||||||
<!-- 小图片预览 -->
|
<!-- 小图片预览 -->
|
||||||
<div id="imageMenu">
|
<div id="imageMenu_{$sku.id}" class="imageMenu">
|
||||||
<ul class="image_list">
|
<ul class="image_list">
|
||||||
|
{volist name="sku.photo_album" id="photo"}
|
||||||
|
<li class="onlickImg"><img src="{:thumb($photo)}" data-url="{$photo}" /></li>
|
||||||
|
{/volist}
|
||||||
{if condition="!empty($product.video_img) && !empty($product.video_url) && $idx == 1"}
|
{if condition="!empty($product.video_img) && !empty($product.video_url) && $idx == 1"}
|
||||||
<!-- 产品视频 -->
|
<!-- 产品视频 -->
|
||||||
<li id="onlickImg"><img src="{:thumb($product.video_img)}" data-url="{$product.video_url}" /></li>
|
<li class="onlickImg"><img src="{:thumb($product.video_img)}" data-url="{$product.video_url}" /></li>
|
||||||
{/if}
|
{/if}
|
||||||
{volist name="sku.photo_album" id="photo"}
|
|
||||||
<li id="onlickImg"><img src="{:thumb($photo)}" data-url="{$photo}" /></li>
|
|
||||||
{/volist}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<!-- 右边切换按钮 -->
|
<!-- 右边切换按钮 -->
|
||||||
<div class="scrollbutton smallImgDown"></div>
|
<div class="scrollbutton smallImgDown"></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 产品大图 -->
|
<!-- 产品大图 -->
|
||||||
<div class="bigImg" id="vertical">
|
<div class="bigImg" id="vertical" style="width: 75%;">
|
||||||
<!-- 主图 -->
|
<!-- 主图 -->
|
||||||
{if condition="!empty($product.video_img) && !empty($product.video_url) && $idx == 1"}
|
|
||||||
<!-- 如果有视频情况下默认先显示视频 -->
|
|
||||||
<video poster="{$product.video_img}" autoplay="autoplay" muted="muted" loop="loop" id="video" controls style="width: 510px;height: 510px; position: relative;z-index: 998;">
|
|
||||||
<source src="{$product.video_url}" type="video/mp4"/>
|
|
||||||
</video>
|
|
||||||
{else/}
|
|
||||||
{notempty name="sku.photo_album[0]"}
|
{notempty name="sku.photo_album[0]"}
|
||||||
<img src="{$sku.photo_album[0]}" id="midimg" />
|
<img src="{$sku.photo_album[0]}" id="midimg" />
|
||||||
{/notempty}
|
{/notempty}
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/volist}
|
{/volist}
|
||||||
@@ -73,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>
|
||||||
@@ -114,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}
|
||||||
@@ -130,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">
|
||||||
@@ -225,7 +230,7 @@
|
|||||||
<textarea name="message" id="message"></textarea>
|
<textarea name="message" id="message"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" id="send" class="submit-btn">{:lang_i18n('提交')}</button>
|
<button type="submit" class="submit-btn">{:lang_i18n('提交')}</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -273,21 +278,12 @@
|
|||||||
// 处理表单提交
|
// 处理表单提交
|
||||||
modal.find("form").submit(function(e) {
|
modal.find("form").submit(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
var form = $(this)
|
||||||
var formData = $(this).serialize();
|
var formData = $(this).serialize();
|
||||||
// 这里可以添加代码将formData发送到服务器
|
|
||||||
// 例如通过AJAX
|
|
||||||
console.log("提交的数据: " + formData);
|
|
||||||
// 提交成功后可以选择关闭模态框
|
|
||||||
modal.hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 提交询盘
|
|
||||||
$('#send').click(function() {
|
|
||||||
var form = $(this).parents('form');
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "{:url('product/inquiry')}",
|
url: "{:url('product/inquiry')}",
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: form.serialize(),
|
data: formData,
|
||||||
success: function(r) {
|
success: function(r) {
|
||||||
if (r.code == 0) {
|
if (r.code == 0) {
|
||||||
form[0].reset(); // 重置表单
|
form[0].reset(); // 重置表单
|
||||||
@@ -297,6 +293,7 @@
|
|||||||
},
|
},
|
||||||
error: function(e) {
|
error: function(e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
modal.hide();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<!-- 搜索结果列表-->
|
<!-- 搜索结果列表-->
|
||||||
|
{notempty name="products"}
|
||||||
<ul class="seul">
|
<ul class="seul">
|
||||||
{volist name="products" id="pro"}
|
{volist name="products" id="pro"}
|
||||||
<a href="{:url('product/detail', ['id' => $pro['id']])}">
|
<a href="{:url('product/detail', ['id' => $pro['id']])}">
|
||||||
@@ -32,6 +33,10 @@
|
|||||||
</a>
|
</a>
|
||||||
{/volist}
|
{/volist}
|
||||||
</ul>
|
</ul>
|
||||||
|
<div>{$page|raw}</div>
|
||||||
|
{else/}
|
||||||
|
<div style="text-align: center; padding: 10%;">{:lang_i18n('暂无数据')}</div>
|
||||||
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
@@ -24,23 +24,19 @@
|
|||||||
// 直接输出对应的 HTML 标签
|
// 直接输出对应的 HTML 标签
|
||||||
if (isUCBrowser()) {
|
if (isUCBrowser()) {
|
||||||
document.write(`
|
document.write(`
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@8.4.7/swiper-bundle.min.css">
|
<link rel="stylesheet" href="__JS__/swiper-bundle8.4.7.min.css">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/swiper@8.4.7/swiper-bundle.min.js"><\/script>
|
<script type="text/javascript" src="__JS__/swiper-bundle8.4.7.min.js"><\/script>
|
||||||
`);
|
`);
|
||||||
} else {
|
} else {
|
||||||
document.write(`
|
document.write(`
|
||||||
<link rel="stylesheet" href="https://unpkg.com/swiper@9.4.1/swiper-bundle.min.css">
|
<link rel="stylesheet" href="__JS__/swiper-bundle9.4.1.min.css">
|
||||||
<script src="https://unpkg.com/swiper@9.4.1/swiper-bundle.min.js"><\/script>
|
<script type="text/javascript" src="__JS__/swiper-bundle9.4.1.min.js"><\/script>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- 你的 jQuery 和其他脚本 -->
|
<!-- 你的 jQuery 和其他脚本 -->
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script src="__JS__/jquery-3.6.0.min.js"></script>
|
||||||
<!-- <link rel="stylesheet" href="https://unpkg.com/swiper@9/swiper-bundle.min.css">
|
|
||||||
<script type="text/javascript" src="https://unpkg.com/swiper@9.4.1/swiper-bundle.min.js"></script> -->
|
|
||||||
<script type="text/javascript" src='https://code.jquery.com/jquery-3.6.0.min.js'></script>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="__JS__/before-after.min.js"></script>
|
<script type="text/javascript" src="__JS__/before-after.min.js"></script>
|
||||||
<script type="text/javascript" src="__JS__/large.js"></script>
|
<script type="text/javascript" src="__JS__/large.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@@ -112,7 +108,7 @@
|
|||||||
(function() {
|
(function() {
|
||||||
var u="//analytics.f2b211.com/";
|
var u="//analytics.f2b211.com/";
|
||||||
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||||
_paq.push(['setSiteId', '1']);
|
_paq.push(['setSiteId', '2']);
|
||||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||||
})();
|
})();
|
||||||
@@ -124,7 +120,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
<!-- Matomo Image Tracker-->
|
<!-- Matomo Image Tracker-->
|
||||||
<img referrerpolicy="no-referrer-when-downgrade" src="https://analytics.f2b211.com/matomo.php?idsite=1&rec=1" style="border:0" alt="" />
|
<img referrerpolicy="no-referrer-when-downgrade" src="https://analytics.f2b211.com/matomo.php?idsite=2&rec=1" style="border:0" alt="" />
|
||||||
<!-- End Matomo -->
|
<!-- End Matomo -->
|
||||||
</noscript>
|
</noscript>
|
||||||
{block name="header"}
|
{block name="header"}
|
||||||
|
|||||||
@@ -27,7 +27,9 @@
|
|||||||
<p class="ftitle">{:lang_i18n('产品')}</p>
|
<p class="ftitle">{:lang_i18n('产品')}</p>
|
||||||
<ul>
|
<ul>
|
||||||
{volist name="header_categorys" id="vo"}
|
{volist name="header_categorys" id="vo"}
|
||||||
|
{if condition="!empty($vo.name)"}
|
||||||
<li><a href="{:url('product/category', ['id' => $vo.id])}" class="fline">{$vo.name}</a></li>
|
<li><a href="{:url('product/category', ['id' => $vo.id])}" class="fline">{$vo.name}</a></li>
|
||||||
|
{/if}
|
||||||
{/volist}
|
{/volist}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,7 +40,7 @@
|
|||||||
{if condition="!empty($vo.children)"}
|
{if condition="!empty($vo.children)"}
|
||||||
<ul>
|
<ul>
|
||||||
{volist name="vo.children" id="vc"}
|
{volist name="vo.children" id="vc"}
|
||||||
<li><a href="{$vc.link}" class="fline">{$vc.name}</a></li>
|
<li><a href="{$vc.link}" class="fline" target="{$vc.blank==1?'_blank':'_self'}">{$vc.name}</a></li>
|
||||||
{/volist}
|
{/volist}
|
||||||
</ul>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -80,7 +82,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}
|
||||||
@@ -89,12 +91,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
{eq name=":cookie('think_lang')" value="zh-cn"}
|
|
||||||
<div class="backtop">
|
<div class="backtop">
|
||||||
<img src="__IMAGES__/ic-backtop.png" class="ictop" />
|
<img src="__IMAGES__/ic-backtop.png" class="ictop" />
|
||||||
<span>返回顶部</span>
|
<span>{eq name=":cookie('think_lang')" value="en-us"}TOP{else /}返回顶部{/eq}</span>
|
||||||
</div>
|
</div>
|
||||||
{/eq}
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
// 获取窗口高度
|
// 获取窗口高度
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -155,26 +155,53 @@
|
|||||||
|
|
||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 封装一个函数用于处理鼠标悬停显示和隐藏内容
|
// 封装一个函数用于处理鼠标悬停显示和隐藏内容
|
||||||
function handleHover($element, $content) {
|
function handleHover($element, $content) {
|
||||||
$element.mouseenter(function () {
|
// 同时支持鼠标悬停和点击事件
|
||||||
|
$element
|
||||||
|
.mouseenter(function () {
|
||||||
$content.stop(true, true).slideDown(60);
|
$content.stop(true, true).slideDown(60);
|
||||||
}).mouseleave(function () {
|
})
|
||||||
|
.mouseleave(function () {
|
||||||
$content.stop(true, true).slideUp(60);
|
$content.stop(true, true).slideUp(60);
|
||||||
|
})
|
||||||
|
.click(function (e) {
|
||||||
|
// 阻止链接默认跳转(如果有链接的话)
|
||||||
|
if ($content.is(':visible')) {
|
||||||
|
$content.stop(true, true).slideUp(60);
|
||||||
|
} else {
|
||||||
|
$content.stop(true, true).slideDown(60);
|
||||||
|
}
|
||||||
|
// 防止点击事件冒泡到a标签
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 处理第一个导航项
|
|
||||||
handleHover($('.navItem').eq(0), $('.navItem').eq(0).find('.navItemConten'));
|
// 处理产品列表的下拉菜单
|
||||||
// 鼠标移入navItem_cyleft里面的li标签添加类,移除其他li的类
|
var $firstNav = $('.navItem').eq(0);
|
||||||
|
if ($firstNav.find('.navItemConten').length) {
|
||||||
|
handleHover($firstNav, $firstNav.find('.navItemConten'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 鼠标移入左侧子菜单切换显示
|
||||||
$('.navItem_cyleft li').mouseenter(function () {
|
$('.navItem_cyleft li').mouseenter(function () {
|
||||||
$(this).addClass('it_active').siblings().removeClass('it_active');
|
$(this).addClass('it_active').siblings().removeClass('it_active');
|
||||||
$('.navItem_cyright').hide();
|
$('.navItem_cyright').hide();
|
||||||
$('.navItem_cyright').eq($(this).index()).show();
|
$('.navItem_cyright').eq($(this).index()).show();
|
||||||
});
|
});
|
||||||
// 处理第5 - 8个导航项
|
|
||||||
for (let i = 4; i < 8; i++) {
|
// 动态处理所有带有navItemConten1的导航项
|
||||||
handleHover($('.navItem').eq(i), $('.navItem').eq(i).find('.navItemConten1'));
|
$('.navItem').each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var $dropdown = $this.find('.navItemConten1');
|
||||||
|
// 只给有下拉菜单的导航项绑定事件
|
||||||
|
if ($dropdown.length) {
|
||||||
|
handleHover($this, $dropdown);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 点击搜索
|
// 点击搜索
|
||||||
$('#openModalBtn').click(function () {
|
$('#openModalBtn').click(function () {
|
||||||
$('#scmodal').toggle();
|
$('#scmodal').toggle();
|
||||||
@@ -182,8 +209,20 @@
|
|||||||
$('.close-btn').click(function () {
|
$('.close-btn').click(function () {
|
||||||
$('#scmodal').hide();
|
$('#scmodal').hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 点击空白处关闭下拉菜单
|
||||||
|
$(document).click(function () {
|
||||||
|
$('.navItemConten, .navItemConten1, #top-country').slideUp(60);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 防止下拉菜单内部点击触发空白处关闭事件
|
||||||
|
$('.navItemConten, .navItemConten1, #top-country').click(function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
// 搜索历史记录回显
|
// 搜索历史记录回显
|
||||||
history();
|
history();
|
||||||
|
|
||||||
// 执行搜索
|
// 执行搜索
|
||||||
$('#serrchinput').keydown(function (event) {
|
$('#serrchinput').keydown(function (event) {
|
||||||
if (event.originalEvent.keyCode == 13) {
|
if (event.originalEvent.keyCode == 13) {
|
||||||
@@ -198,9 +237,11 @@
|
|||||||
window.location.href = "{:url('product/search')}" + '?keywords=' + keywords;
|
window.location.href = "{:url('product/search')}" + '?keywords=' + keywords;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 点击选择国家
|
// 点击选择国家
|
||||||
$('#countrycheck').click(function () {
|
$('#countrycheck').click(function (e) {
|
||||||
$('#top-country').toggle();
|
$('#top-country').toggle();
|
||||||
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
$('.closecountrybt').click(function () {
|
$('.closecountrybt').click(function () {
|
||||||
$('#top-country').hide();
|
$('#top-country').hide();
|
||||||
|
|||||||
@@ -13,7 +13,27 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="__CSS__/topic_nas_header.css" />
|
<link rel="stylesheet" type="text/css" href="__CSS__/topic_nas_header.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="__CSS__/orico_footer.css" />
|
<link rel="stylesheet" type="text/css" href="__CSS__/orico_footer.css" />
|
||||||
{block name="style"}{/block}
|
{block name="style"}{/block}
|
||||||
<script type="text/javascript" src='https://code.jquery.com/jquery-3.6.0.min.js'></script>
|
<script src="__JS__/jquery-3.6.0.min.js"></script>
|
||||||
|
<script>
|
||||||
|
// 增强型 UC 浏览器检测
|
||||||
|
function isUCBrowser() {
|
||||||
|
const ua = navigator.userAgent.toLowerCase();
|
||||||
|
return ua.includes('ubrowser');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接输出对应的 HTML 标签
|
||||||
|
if (isUCBrowser()) {
|
||||||
|
document.write(`
|
||||||
|
<link rel="stylesheet" href="__JS__/swiper-bundle8.4.7.min.css">
|
||||||
|
<script type="text/javascript" src="__JS__/swiper-bundle8.4.7.min.js"><\/script>
|
||||||
|
`);
|
||||||
|
} else {
|
||||||
|
document.write(`
|
||||||
|
<link rel="stylesheet" href="__JS__/swiper-bundle9.4.1.min.css">
|
||||||
|
<script type="text/javascript" src="__JS__/swiper-bundle9.4.1.min.js"><\/script>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<script>
|
<script>
|
||||||
$(window).ready(function () {
|
$(window).ready(function () {
|
||||||
if ($(window).width() < 1024) {
|
if ($(window).width() < 1024) {
|
||||||
@@ -35,7 +55,7 @@
|
|||||||
(function() {
|
(function() {
|
||||||
var u="//analytics.f2b211.com/";
|
var u="//analytics.f2b211.com/";
|
||||||
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||||
_paq.push(['setSiteId', '1']);
|
_paq.push(['setSiteId', '2']);
|
||||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||||
})();
|
})();
|
||||||
@@ -45,7 +65,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
<!-- Matomo Image Tracker-->
|
<!-- Matomo Image Tracker-->
|
||||||
<img referrerpolicy="no-referrer-when-downgrade" src="https://analytics.f2b211.com/matomo.php?idsite=1&rec=1" style="border:0" alt="" />
|
<img referrerpolicy="no-referrer-when-downgrade" src="https://analytics.f2b211.com/matomo.php?idsite=2&rec=1" style="border:0" alt="" />
|
||||||
<!-- End Matomo -->
|
<!-- End Matomo -->
|
||||||
</noscript>
|
</noscript>
|
||||||
{block name="header"}
|
{block name="header"}
|
||||||
|
|||||||
@@ -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"}
|
||||||
@@ -17,9 +21,10 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
$('.headnav .navitem').each(function(idx, item) {
|
$('.headnav .navitem').each(function(idx, item) {
|
||||||
$(item).removeClass('hover');
|
var _item = $(item);
|
||||||
if (compareUrls(location.href, item.href)) {
|
_item.removeClass('hover');
|
||||||
$(item).addClass('hover').siblings();
|
if (_item.attr('href') && compareUrls(location.href, _item.get(0).href)) {
|
||||||
|
_item.addClass('hover').siblings();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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,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}
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
$('#dropdown').hide();
|
$('#dropdown').hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$('.nhlplxwmit:not(:first)').hover(function () {
|
$('.nhlplxwmit').hover(function () {
|
||||||
// 当鼠标移入时,显示.lxewmimg 并隐藏.lximg
|
// 当鼠标移入时,显示.lxewmimg 并隐藏.lximg
|
||||||
var lxe = $(this).find('.lxewmimg');
|
var lxe = $(this).find('.lxewmimg');
|
||||||
var lxi = $(this).find('.lximg');
|
var lxi = $(this).find('.lximg');
|
||||||
|
|||||||
@@ -32,33 +32,49 @@
|
|||||||
<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}>
|
<ul class="sub-list" {if condition='$ac.id == $Request.get.cid' }style="display: block;" {/if}>
|
||||||
{volist name="ac.article" id="ar"}
|
{volist name="ac.child" id="ad"}
|
||||||
<li>
|
<li class="two-mues">
|
||||||
<a
|
<a href="#" class="two-a">
|
||||||
href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id, 'id' => $ar.id])}"
|
<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>
|
||||||
{eq name="ar.id" value="$Request.get.id"}class="active"{/eq}
|
<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 style="margin-left: 30px;"><a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id,'pid' => $ad.id, 'id' => $ae.id])}" style="padding-top: 6px;" {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>
|
||||||
<!--文章详情 -->
|
<!--文章详情 -->
|
||||||
<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">
|
||||||
@@ -73,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);
|
||||||
@@ -107,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>'
|
||||||
}
|
}
|
||||||
@@ -119,11 +147,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 +165,9 @@
|
|||||||
});
|
});
|
||||||
listItem.append(link);
|
listItem.append(link);
|
||||||
$("#title-list ul").append(listItem);
|
$("#title-list ul").append(listItem);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
{block name="script"}
|
{block name="script"}
|
||||||
<script type="text/javascript" src="https://unpkg.com/swiper@9.4.1/swiper-bundle.min.js"></script>
|
<!-- <script type="text/javascript" src="https://unpkg.com/swiper@9.4.1/swiper-bundle.min.js"></script> -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
// banner轮播
|
// banner轮播
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ class Article
|
|||||||
])
|
])
|
||||||
->withoutField([
|
->withoutField([
|
||||||
'language_id',
|
'language_id',
|
||||||
|
'author',
|
||||||
|
'source',
|
||||||
'seo_title',
|
'seo_title',
|
||||||
'seo_keywords',
|
'seo_keywords',
|
||||||
'seo_desc',
|
'seo_desc',
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ class ArticleCategory
|
|||||||
$categories = ArticleCategoryModel::withoutField([
|
$categories = ArticleCategoryModel::withoutField([
|
||||||
'language_id',
|
'language_id',
|
||||||
'unique_label',
|
'unique_label',
|
||||||
|
'short_name',
|
||||||
|
'desc',
|
||||||
'created_at',
|
'created_at',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class Product
|
|||||||
*/
|
*/
|
||||||
public function list()
|
public function list()
|
||||||
{
|
{
|
||||||
|
|
||||||
$params = request()->get([
|
$params = request()->get([
|
||||||
'category_id',
|
'category_id',
|
||||||
'language' => 'zh-cn',
|
'language' => 'zh-cn',
|
||||||
@@ -34,7 +35,6 @@ class Product
|
|||||||
'name',
|
'name',
|
||||||
'short_name',
|
'short_name',
|
||||||
'cover_image',
|
'cover_image',
|
||||||
'desc',
|
|
||||||
'deleted_at'
|
'deleted_at'
|
||||||
])
|
])
|
||||||
->where(function($query) use($params) {
|
->where(function($query) use($params) {
|
||||||
@@ -47,7 +47,7 @@ class Product
|
|||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
->hidden(['category_id'])
|
->hidden(['category_id'])
|
||||||
->paginate([
|
->paginate([
|
||||||
'list_row' => $params['size'],
|
'list_rows' => $params['size'],
|
||||||
'page' => $params['page']
|
'page' => $params['page']
|
||||||
])
|
])
|
||||||
->each(function($item) {
|
->each(function($item) {
|
||||||
@@ -75,14 +75,16 @@ class Product
|
|||||||
'params' => fn($query) => $query->field(['product_id', 'name', 'value'])
|
'params' => fn($query) => $query->field(['product_id', 'name', 'value'])
|
||||||
->hidden(['product_id']),
|
->hidden(['product_id']),
|
||||||
// 关联sku
|
// 关联sku
|
||||||
'skus' => fn($query) => $query->withoutField(['created_at', 'updated_at'])
|
'skus' => fn($query) => $query->withoutField(['sort', 'created_at', 'updated_at'])
|
||||||
->with([
|
->with([
|
||||||
'sku_attr' => fn($query) => $query->with('attr')->hidden(['sku_id', 'attr_id'])
|
'sku_attr' => fn($query) => $query->with('attr')->hidden(['sku_id', 'attr_id'])
|
||||||
])
|
])
|
||||||
->hidden(['id', 'product_id']),
|
->hidden(['id', 'product_id']),
|
||||||
// 关联购买链接
|
// 关联购买链接
|
||||||
'links' => fn($query) => $query->field(['product_id', 'platform_id', 'link'])
|
'links' => fn($query) => $query->field(['product_id', 'platform_id', 'link'])
|
||||||
->with(['platform' => fn($query) => $query->field(['id', 'platform'])])
|
->with([
|
||||||
|
'platforms' => fn($query) => $query->field(['id', 'platform'])
|
||||||
|
])
|
||||||
->hidden(['product_id', 'platform_id']),
|
->hidden(['product_id', 'platform_id']),
|
||||||
// 关联相关产品
|
// 关联相关产品
|
||||||
'related' => fn($query) => $query->field(['product_id', 'related_product_id'])
|
'related' => fn($query) => $query->field(['product_id', 'related_product_id'])
|
||||||
@@ -98,6 +100,7 @@ class Product
|
|||||||
])
|
])
|
||||||
->withoutField([
|
->withoutField([
|
||||||
'language_id',
|
'language_id',
|
||||||
|
'desc',
|
||||||
'stock_qty',
|
'stock_qty',
|
||||||
'seo_title',
|
'seo_title',
|
||||||
'seo_keywords',
|
'seo_keywords',
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ class ProductCategory
|
|||||||
$categories = ProductCategoryModel::withoutField([
|
$categories = ProductCategoryModel::withoutField([
|
||||||
'language_id',
|
'language_id',
|
||||||
'unique_id',
|
'unique_id',
|
||||||
|
'icon',
|
||||||
|
'desc',
|
||||||
'related_tco_category',
|
'related_tco_category',
|
||||||
'created_at',
|
'created_at',
|
||||||
'updated_at'
|
'updated_at'
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use app\common\model\ProductPurchaseLinkBaseModel;
|
|||||||
class ProductPurchaseLinkModel extends ProductPurchaseLinkBaseModel
|
class ProductPurchaseLinkModel extends ProductPurchaseLinkBaseModel
|
||||||
{
|
{
|
||||||
// 关联购买平台
|
// 关联购买平台
|
||||||
public function platform()
|
public function platforms()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(ProductPurchasePlatformModel::class, 'platform_id', 'id')->bind(['platform']);
|
return $this->belongsTo(ProductPurchasePlatformModel::class, 'platform_id', 'id')->bind(['platform']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -29,15 +29,15 @@ return [
|
|||||||
// 驱动方式
|
// 驱动方式
|
||||||
'type' => 'redis',
|
'type' => 'redis',
|
||||||
// 服务器地址
|
// 服务器地址
|
||||||
'host' => '127.0.0.1',
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
// 端口
|
// 端口
|
||||||
'port' => 6379,
|
'port' => env('REDIS_PORT', 6379),
|
||||||
// 密码
|
// 密码
|
||||||
'password' => 'orico@f2b211',
|
'password' => env('REDIS_PASSWORD', 'orico@f2b211'),
|
||||||
// 缓存有效期 0表示永久缓存
|
// 缓存有效期 0表示永久缓存
|
||||||
'expire' => 0,
|
'expire' => 0,
|
||||||
// 缓存前缀
|
// 缓存前缀
|
||||||
'prefix' => 'ow:',
|
'prefix' => env('REDIS_PREFIX', 'ow:'),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -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,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -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],
|
||||||
@@ -105,18 +105,24 @@ class SysConfigInit extends Seeder
|
|||||||
["id" => 88, "group_id" => 6, "title" => "位置", "name" => "watermark_position", "value" => "top-left", "extra" => "top-left:左上角\ntop-right:右上角\ntop:上 - 水平居中\nleft:左 - 垂直居中\ncenter:水平垂直居中\nright:右 - 垂直居中\nbottom:下 - 水平居中\nbottom-left:左下角\nbottom-right:右下角", "type" => "radio", "sort" => 11, "remark" => null, "created_at" => "2025-06-10 16:02:17", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 88, "group_id" => 6, "title" => "位置", "name" => "watermark_position", "value" => "top-left", "extra" => "top-left:左上角\ntop-right:右上角\ntop:上 - 水平居中\nleft:左 - 垂直居中\ncenter:水平垂直居中\nright:右 - 垂直居中\nbottom:下 - 水平居中\nbottom-left:左下角\nbottom-right:右下角", "type" => "radio", "sort" => 11, "remark" => null, "created_at" => "2025-06-10 16:02:17", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 89, "group_id" => 6, "title" => "外边距 - X轴", "name" => "watermark_offset_x", "value" => "", "extra" => "", "type" => "text", "sort" => 12, "remark" => "在“位置”基础上的x轴偏移量", "created_at" => "2025-06-10 16:06:23", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 89, "group_id" => 6, "title" => "外边距 - X轴", "name" => "watermark_offset_x", "value" => "", "extra" => "", "type" => "text", "sort" => 12, "remark" => "在“位置”基础上的x轴偏移量", "created_at" => "2025-06-10 16:06:23", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 90, "group_id" => 6, "title" => "外边距 - Y轴", "name" => "watermark_offset_y", "value" => "", "extra" => null, "type" => "text", "sort" => 13, "remark" => "在“位置”基础上的y轴偏移量", "created_at" => "2025-06-10 16:09:23", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 90, "group_id" => 6, "title" => "外边距 - Y轴", "name" => "watermark_offset_y", "value" => "", "extra" => null, "type" => "text", "sort" => 13, "remark" => "在“位置”基础上的y轴偏移量", "created_at" => "2025-06-10 16:09:23", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 91, "group_id" => 14, "title" => "图片 - 保留原文件名", "name" => "upload_image.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 1, "remark" => "默认为否", "created_at" => "2025-06-12 11:08:59", "updated_at" => "2025-06-12 11:29:24", "deleted_at" => NULL],
|
["id" => 91, "group_id" => 14, "title" => "图片 - 格式转为", "name" => "upload_image.filetype_to", "value" => "original", "extra" => "original:原格式\nwebp:webp格式", "type" => "radio", "sort" => 1, "remark" => "webp格式图片质量为原图75%,可大幅压缩图片大小;选定webp格式时,所有上传图片均保存为webp格式。", "created_at" => "2025-06-12 11:28:22", "updated_at" => "2025-06-12 11:28:22", "deleted_at" => NULL],
|
||||||
["id" => 92, "group_id" => 14, "title" => "图片 - 唯一性保持", "name" => "upload_image.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 2, "remark" => "如果保持图片文件唯一,重复图片上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:16:46", "updated_at" => "2025-06-12 11:24:39", "deleted_at" => NULL],
|
["id" => 92, "group_id" => 14, "title" => "图片 - 保留原文件名", "name" => "upload_image.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 2, "remark" => "默认为否", "created_at" => "2025-06-12 11:08:59", "updated_at" => "2025-06-12 11:29:24", "deleted_at" => NULL],
|
||||||
["id" => 93, "group_id" => 14, "title" => "视频 - 保留原文件名", "name" => "upload_video.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 3, "remark" => "默认为否", "created_at" => "2025-06-12 11:22:27", "updated_at" => "2025-06-12 11:29:24", "deleted_at" => NULL],
|
["id" => 93, "group_id" => 14, "title" => "图片 - 唯一性保持", "name" => "upload_image.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 3, "remark" => "如果保持图片文件唯一,重复图片上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:16:46", "updated_at" => "2025-06-12 11:24:39", "deleted_at" => NULL],
|
||||||
["id" => 94, "group_id" => 14, "title" => "视频 - 唯一性保持", "name" => "upload_video.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 4, "remark" => "如果保持视频文件唯一,重复视频上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:24:24", "updated_at" => "2025-06-12 11:25:18", "deleted_at" => NULL],
|
["id" => 94, "group_id" => 14, "title" => "视频 - 保留原文件名", "name" => "upload_video.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 4, "remark" => "默认为否", "created_at" => "2025-06-12 11:22:27", "updated_at" => "2025-06-12 11:29:24", "deleted_at" => NULL],
|
||||||
["id" => 95, "group_id" => 14, "title" => "附件 - 保留原文件名", "name" => "upload_attachment.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 5, "remark" => "默认为否", "created_at" => "2025-06-12 11:27:08", "updated_at" => "2025-06-12 11:27:08", "deleted_at" => NULL],
|
["id" => 95, "group_id" => 14, "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" => 96, "group_id" => 14, "title" => "附件 - 唯一性保持", "name" => "upload_attachment.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 6, "remark" => "如果保持附件文件唯一,重复附件上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:28:22", "updated_at" => "2025-06-12 11:28:22", "deleted_at" => NULL],
|
["id" => 96, "group_id" => 14, "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" => 97, "group_id" => 13, "title" => "图片 - 保留原文件名", "name" => "upload_image.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 1, "remark" => "默认为否", "created_at" => "2025-06-12 11:08:59", "updated_at" => "2025-06-12 11:29:24", "deleted_at" => NULL],
|
["id" => 97, "group_id" => 14, "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" => 98, "group_id" => 13, "title" => "图片 - 唯一性保持", "name" => "upload_image.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 2, "remark" => "如果保持图片文件唯一,重复图片上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:16:46", "updated_at" => "2025-06-12 11:24:39", "deleted_at" => NULL],
|
["id" => 98, "group_id" => 13, "title" => "图片 - 格式转为", "name" => "upload_image.filetype_to", "value" => "original", "extra" => "original:原格式\nwebp:webp格式", "type" => "radio", "sort" => 1, "remark" => "webp格式图片质量为原图75%,可大幅压缩图片大小;选定webp格式时,所有上传图片均保存为webp格式。", "created_at" => "2025-06-12 11:28:22", "updated_at" => "2025-06-12 11:28:22", "deleted_at" => NULL],
|
||||||
["id" => 99, "group_id" => 13, "title" => "视频 - 保留原文件名", "name" => "upload_video.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 3, "remark" => "默认为否", "created_at" => "2025-06-12 11:22:27", "updated_at" => "2025-06-12 11:29:24", "deleted_at" => NULL],
|
["id" => 99, "group_id" => 13, "title" => "图片 - 保留原文件名", "name" => "upload_image.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 2, "remark" => "默认为否", "created_at" => "2025-06-12 11:08:59", "updated_at" => "2025-06-12 11:29:24", "deleted_at" => NULL],
|
||||||
["id" => 100, "group_id" => 13, "title" => "视频 - 唯一性保持", "name" => "upload_video.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 4, "remark" => "如果保持视频文件唯一,重复视频上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:24:24", "updated_at" => "2025-06-12 11:25:18", "deleted_at" => NULL],
|
["id" => 100, "group_id" => 13, "title" => "图片 - 唯一性保持", "name" => "upload_image.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 3, "remark" => "如果保持图片文件唯一,重复图片上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:16:46", "updated_at" => "2025-06-12 11:24:39", "deleted_at" => NULL],
|
||||||
["id" => 101, "group_id" => 13, "title" => "附件 - 保留原文件名", "name" => "upload_attachment.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 5, "remark" => "默认为否", "created_at" => "2025-06-12 11:27:08", "updated_at" => "2025-06-12 11:27:08", "deleted_at" => NULL],
|
["id" => 101, "group_id" => 13, "title" => "视频 - 保留原文件名", "name" => "upload_video.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 4, "remark" => "默认为否", "created_at" => "2025-06-12 11:22:27", "updated_at" => "2025-06-12 11:29:24", "deleted_at" => NULL],
|
||||||
["id" => 102, "group_id" => 13, "title" => "附件 - 唯一性保持", "name" => "upload_attachment.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 6, "remark" => "如果保持附件文件唯一,重复附件上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:28:22", "updated_at" => "2025-06-12 11:28:22", "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" => 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;
|
||||||
|
|||||||
@@ -84,13 +84,15 @@
|
|||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .send {
|
.oricoEGapp-Contact .send {
|
||||||
display: inline-block;
|
display: block;
|
||||||
background-color: #004bfa;
|
background-color: #004bfa;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "Montserrat-Bold";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
padding: 0.75rem 1.5rem;
|
padding: 0.75rem 1.5rem;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 1.25rem;
|
border-radius: 1.25rem;
|
||||||
|
width: fit-content;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .red {
|
.oricoEGapp-Contact .red {
|
||||||
color: #ee2f53;
|
color: #ee2f53;
|
||||||
@@ -198,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 {
|
||||||
|
|||||||
@@ -87,13 +87,15 @@
|
|||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .send {
|
.oricoEGapp-Contact .send {
|
||||||
display: inline-block;
|
display: block;
|
||||||
background-color: #004bfa;
|
background-color: #004bfa;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "Montserrat-Bold";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
padding: 0.75rem 1.5rem;
|
padding: 0.75rem 1.5rem;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 1.25rem;
|
border-radius: 1.25rem;
|
||||||
|
width: fit-content;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .red {
|
.oricoEGapp-Contact .red {
|
||||||
color: #ee2f53;
|
color: #ee2f53;
|
||||||
|
|||||||
@@ -30,7 +30,8 @@
|
|||||||
margin: 0 5%;
|
margin: 0 5%;
|
||||||
}
|
}
|
||||||
.oricoEGapp .oricoEGapp-index .oidx-cate .cateit {
|
.oricoEGapp .oricoEGapp-index .oidx-cate .cateit {
|
||||||
margin: 0 3.5%;
|
margin: 0 1%;
|
||||||
|
width: 50%;
|
||||||
}
|
}
|
||||||
.oricoEGapp .oricoEGapp-index .oidx-cate .cateit a{
|
.oricoEGapp .oricoEGapp-index .oidx-cate .cateit a{
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -45,8 +46,8 @@
|
|||||||
}
|
}
|
||||||
.oricoEGapp .oricoEGapp-index .oidx-cate .cateit span {
|
.oricoEGapp .oricoEGapp-index .oidx-cate .cateit span {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
white-space: nowrap;
|
word-break: break-word;
|
||||||
word-break: keep-all;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
.oricoEGapp .oricoEGapp-index .oidx-gg {
|
.oricoEGapp .oricoEGapp-index .oidx-gg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -34,4 +34,5 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|||||||
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;
|
||||||
@@ -1194,9 +1194,11 @@ video img {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
.faq-title h3 {
|
.faq-title h3 {
|
||||||
font-size: 1.685rem;
|
font-size: 1.685rem;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
.faq-title h5 {
|
.faq-title h5 {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
@@ -1209,6 +1211,7 @@ video img {
|
|||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'Montserrat-Medium';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
.faq-title p {
|
.faq-title p {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
@@ -1275,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;
|
||||||
@@ -1742,7 +1745,7 @@ video img {
|
|||||||
padding-left: 1.5rem;
|
padding-left: 1.5rem;
|
||||||
line-height: 0.64rem;
|
line-height: 0.64rem;
|
||||||
height: 0.54rem;
|
height: 0.54rem;
|
||||||
font-size: 1.2rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
.goods_details .cpa li:nth-child(2) {
|
.goods_details .cpa li:nth-child(2) {
|
||||||
border-left: 1px solid #009fdf;
|
border-left: 1px solid #009fdf;
|
||||||
@@ -2339,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;
|
||||||
@@ -216,3 +220,31 @@
|
|||||||
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;
|
||||||
|
}
|
||||||
2
public/static/index/mobile/js/jquery-3.6.0.min.js
vendored
Normal file
2
public/static/index/mobile/js/jquery-3.6.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
13
public/static/index/mobile/js/swiper-bundle8.4.7.min.css
vendored
Normal file
13
public/static/index/mobile/js/swiper-bundle8.4.7.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
14
public/static/index/mobile/js/swiper-bundle8.4.7.min.js
vendored
Normal file
14
public/static/index/mobile/js/swiper-bundle8.4.7.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
13
public/static/index/mobile/js/swiper-bundle9.4.1.min.css
vendored
Normal file
13
public/static/index/mobile/js/swiper-bundle9.4.1.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user