Compare commits
283 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8daf4d0696 | |||
| 322cfad5d9 | |||
| 2b2dc2021a | |||
| 9b732b19dc | |||
| 654caf58c2 | |||
| 1d62a64014 | |||
| 4447aa4a39 | |||
| 53a317c8cf | |||
| b269e18547 | |||
| 04efd7ef4a | |||
| dc74a1ee10 | |||
| 9b661405c9 | |||
| 1ed900d2b5 | |||
| d6ce8aa2be | |||
| 4b5dae8714 | |||
| cf670b24f8 | |||
| cf1c78c882 | |||
| adef3c1e2e | |||
| 180b5db570 | |||
| a18ff844a4 | |||
| 80d3aa8160 | |||
| d79b418310 | |||
| 816d85a744 | |||
| 2d078033fa | |||
| d430f04b41 | |||
| aaf73a0803 | |||
| 7baac33d0d | |||
| f2f59e9528 | |||
| a9abb16fcb | |||
| 7ff746267b | |||
| bc9f233cb2 | |||
| 2c4eb38495 | |||
| 347ebddb97 | |||
| 93a72c7826 | |||
| 9748a3008e | |||
| 2c20bd2649 | |||
| ff8e23766a | |||
| 81f01e1424 | |||
| b6b5ea5308 | |||
| 62db7e8cb2 | |||
| ba2b343d0a | |||
| 83be5a7c0b | |||
| ce38172cd6 | |||
| 5262ece276 | |||
| 86cc41b78c | |||
| f5a891e00e | |||
| 184e81737e | |||
| eb015c552f | |||
| 685cd53b1a | |||
| 2c3e309d2a | |||
| 853da3c948 | |||
| a68499255d | |||
| 23f9a8fc9a | |||
| 29abb5e230 | |||
| 8a9d66f5d3 | |||
| 90b4bccbcf | |||
| 4c592d9347 | |||
| ebe1c3015e | |||
| 9584b81729 | |||
| 8577877f83 | |||
| be26f2d75b | |||
| 863fdda9a5 | |||
| a1c7ae62ba | |||
| 49240893b5 | |||
| 61728434d3 | |||
| 5736d09dbe | |||
| f4646f1e3a | |||
| 5b3e505e9b | |||
| 624d7fde2f | |||
| a85f2c1b3a | |||
| 7ec97c39a7 | |||
| 67016c4e9a | |||
| 69c3634731 | |||
| 12bc6aeee7 | |||
| 2ca25e083e | |||
| df37a7c00d | |||
| 11e2c4f457 | |||
| edfc27b06a | |||
| fdc9064739 | |||
| 55a75b56b1 | |||
| 005457e13e | |||
| 3664861ef0 | |||
| b1b59a96f2 | |||
| 954ddbf8ba | |||
| 48f3c2b312 | |||
| 48e3d7f846 | |||
| 24e5554bc4 | |||
| 33929b8284 | |||
| c49c3b40d8 | |||
| 2eb7a41732 | |||
| 60177fe0b4 | |||
| c767c20641 | |||
| 64e5c4fe26 | |||
| 77e84f1086 | |||
| 128fb60bad | |||
| 3976ee745d | |||
| e5ccd8d031 | |||
| 991ca5b61c | |||
| d9000fbe1c | |||
| b7e09aeb04 | |||
| 91661b6bb4 | |||
| ded748ca87 | |||
| e4f509a9e5 | |||
| ae51682afe | |||
| be33b21b43 | |||
| db1ad0f88a | |||
| 4d34d76c4f | |||
| 276d901875 | |||
| c9bc2022e6 | |||
| 2c85df4a98 | |||
| 8311181967 | |||
| 99d49ee8a2 | |||
| 4035fe4751 | |||
| 634a758aff | |||
| 8ea03656d9 | |||
| 37023c6949 | |||
| 4fa32b56fe | |||
| 06078cf312 | |||
| 578ad475b7 | |||
| 8ced45364b | |||
| 88a91f3136 | |||
| 5fd603cbc6 | |||
| b92753c822 | |||
| ddd578eb08 | |||
| 9db66b7429 | |||
| c91895f57f | |||
| 42d9efdc02 | |||
| e16b8b6b41 | |||
| 8e4befc0ea | |||
| 1a43ad30fb | |||
| 1cdd0536b9 | |||
| c28b945858 | |||
| 9cc6dc3cd9 | |||
| 9845883d8e | |||
| 4d25f6fec8 | |||
| 5d44c45c13 | |||
| 2764ce3b86 | |||
| 7f472b0351 | |||
| 7cb270b313 | |||
| 14df140847 | |||
| 86ffcb99ac | |||
| 13e58c33a2 | |||
| c476193002 | |||
| 88e307a10e | |||
| 5643faad94 | |||
| 989f6c25a0 | |||
| 2e5103b19a | |||
| ca3c00f396 | |||
| c8d5661856 | |||
| 288c86ffbc | |||
| ccc551dcba | |||
| b6e8aa7880 | |||
| cc2bb999c0 | |||
| e7009c8a49 | |||
| 2a8f88637c | |||
| 1fc6f9067c | |||
| ffa6f29af8 | |||
| 476a238d27 | |||
| 18862c584f | |||
| ee9174e801 | |||
| 4c13d31cb9 | |||
| 3ed8e1f8fc | |||
| 1c998a4be1 | |||
| c3c67c9e59 | |||
| ef5d2c6ab9 | |||
| 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 |
14
.example.env
14
.example.env
@@ -26,6 +26,13 @@ TTL=3600
|
|||||||
REFRESH_TTL=20160
|
REFRESH_TTL=20160
|
||||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
||||||
|
|
||||||
|
# 七牛云存储配置
|
||||||
|
[QINIU_CLOUD]
|
||||||
|
BUCKET = orico-official-website
|
||||||
|
BASE_URL = //ow.static.f2b211.com
|
||||||
|
ACCESS_KEY = dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms
|
||||||
|
SECRET_KEY = KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q
|
||||||
|
|
||||||
# 后台不需要登录的接口
|
# 后台不需要登录的接口
|
||||||
[ADMIN_AUTH]
|
[ADMIN_AUTH]
|
||||||
WHITE_LIST[] = v1/user/login
|
WHITE_LIST[] = v1/user/login
|
||||||
@@ -47,6 +54,13 @@ REFRESH_TOKEN_LIFETIME = 1209600; # 刷新令牌有效期
|
|||||||
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
|
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
|
||||||
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
|
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
|
||||||
|
|
||||||
|
# 七牛云存储配置
|
||||||
|
[QINUI]
|
||||||
|
BUCKET = orico
|
||||||
|
BASE_URL = http://local.orico.com
|
||||||
|
ACCESS_KEY = 1234567890
|
||||||
|
SECRET_KEY = 1234567890
|
||||||
|
|
||||||
# 前台视图模板规则配置
|
# 前台视图模板规则配置
|
||||||
[INDEX_VIEW_TPL]
|
[INDEX_VIEW_TPL]
|
||||||
# 视图目录
|
# 视图目录
|
||||||
|
|||||||
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,12 +1,10 @@
|
|||||||
*.eot filter=lfs diff=lfs merge=lfs -text
|
*.eot filter=lfs diff=lfs merge=lfs -text
|
||||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.woff filter=lfs diff=lfs merge=lfs -text
|
*.woff filter=lfs diff=lfs merge=lfs -text
|
||||||
*.woff2 filter=lfs diff=lfs merge=lfs -text
|
*.woff2 filter=lfs diff=lfs merge=lfs -text
|
||||||
*.svg filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.tff filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||||
*.gzip filter=lfs diff=lfs merge=lfs -text
|
*.gzip filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||||
*.otf filter=lfs diff=lfs merge=lfs -text
|
*.otf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
26
.gitea/workflows/dev-ci.yaml
Normal file
26
.gitea/workflows/dev-ci.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: Gitea Actions Official-website
|
||||||
|
run-name: Deploy to ${{ inputs.deploy_target }} by @${{ gitea.actor }}
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-dev:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Setup SSH
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.SERVER_SSH_KEY }}" > ~/.ssh/id_rsa
|
||||||
|
chmod 600 ~/.ssh/id_rsa
|
||||||
|
ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts
|
||||||
|
- name: Deploy application
|
||||||
|
run: |
|
||||||
|
ssh ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} << 'EOF'
|
||||||
|
set -e
|
||||||
|
cd /www/wwwroot/dev.ow.f2b211.com
|
||||||
|
|
||||||
|
# 拉取最新代码
|
||||||
|
git pull --rebase
|
||||||
|
EOF
|
||||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -7,10 +7,22 @@ Thumbs.db
|
|||||||
.env.dev
|
.env.dev
|
||||||
.env.local
|
.env.local
|
||||||
.env.prod
|
.env.prod
|
||||||
|
.htaccess
|
||||||
|
.user.ini
|
||||||
|
/404.html
|
||||||
|
/index.html
|
||||||
|
|
||||||
|
public/dist*
|
||||||
|
public/opendoc
|
||||||
|
public/logo.png
|
||||||
|
public/.well-known
|
||||||
/.idea
|
/.idea
|
||||||
/.vscode
|
/.vscode
|
||||||
|
/.zed
|
||||||
/vendor
|
/vendor
|
||||||
/.settings
|
/.settings
|
||||||
/.buildpath
|
/.buildpath
|
||||||
/.project
|
/.project
|
||||||
|
|
||||||
|
CLAUDE.md
|
||||||
|
/skills
|
||||||
|
|||||||
24
.zed/settings.json
Normal file
24
.zed/settings.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Folder-specific settings
|
||||||
|
//
|
||||||
|
// For a full list of overridable settings, and general information on folder-specific settings,
|
||||||
|
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
|
||||||
|
{
|
||||||
|
"languages": {
|
||||||
|
"PHP": {
|
||||||
|
"language_servers": ["intelephense","!phpactor"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lsp": {
|
||||||
|
"intelephense": {
|
||||||
|
"initialization_options": {
|
||||||
|
"stubs": [
|
||||||
|
"wordpress",
|
||||||
|
"laravel",
|
||||||
|
"symfony",
|
||||||
|
"codeigniter",
|
||||||
|
"thinkphp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
208
LICENSE
Normal file
208
LICENSE
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
Apache License
|
||||||
|
|
||||||
|
Version 2.0, January 2004
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION,
|
||||||
|
AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, and distribution
|
||||||
|
as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||||
|
owner that is granting the License.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||||
|
that control, are controlled by, or are under common control with that entity.
|
||||||
|
For the purposes of this definition, "control" means (i) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity, whether
|
||||||
|
by contract or otherwise, or (ii) ownership of fifty percent (50%) or more
|
||||||
|
of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions
|
||||||
|
granted by this License.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, including
|
||||||
|
but not limited to software source code, documentation source, and configuration
|
||||||
|
files.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical transformation
|
||||||
|
or translation of a Source form, including but not limited to compiled object
|
||||||
|
code, generated documentation, and conversions to other media types.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or Object form,
|
||||||
|
made available under the License, as indicated by a copyright notice that
|
||||||
|
is included in or attached to the work (an example is provided in the Appendix
|
||||||
|
below).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object form,
|
||||||
|
that is based on (or derived from) the Work and for which the editorial revisions,
|
||||||
|
annotations, elaborations, or other modifications represent, as a whole, an
|
||||||
|
original work of authorship. For the purposes of this License, Derivative
|
||||||
|
Works shall not include works that remain separable from, or merely link (or
|
||||||
|
bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including the original version
|
||||||
|
of the Work and any modifications or additions to that Work or Derivative
|
||||||
|
Works thereof, that is intentionally submitted to Licensor for inclusion in
|
||||||
|
the Work by the copyright owner or by an individual or Legal Entity authorized
|
||||||
|
to submit on behalf of the copyright owner. For the purposes of this definition,
|
||||||
|
"submitted" means any form of electronic, verbal, or written communication
|
||||||
|
sent to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems, and
|
||||||
|
issue tracking systems that are managed by, or on behalf of, the Licensor
|
||||||
|
for the purpose of discussing and improving the Work, but excluding communication
|
||||||
|
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||||
|
owner as "Not a Contribution."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||||
|
of whom a Contribution has been received by Licensor and subsequently incorporated
|
||||||
|
within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of this
|
||||||
|
License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
|
||||||
|
Derivative Works of, publicly display, publicly perform, sublicense, and distribute
|
||||||
|
the Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of this License,
|
||||||
|
each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section) patent
|
||||||
|
license to make, have made, use, offer to sell, sell, import, and otherwise
|
||||||
|
transfer the Work, where such license applies only to those patent claims
|
||||||
|
licensable by such Contributor that are necessarily infringed by their Contribution(s)
|
||||||
|
alone or by combination of their Contribution(s) with the Work to which such
|
||||||
|
Contribution(s) was submitted. If You institute patent litigation against
|
||||||
|
any entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that the Work or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses granted to You
|
||||||
|
under this License for that Work shall terminate as of the date such litigation
|
||||||
|
is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the Work or
|
||||||
|
Derivative Works thereof in any medium, with or without modifications, and
|
||||||
|
in Source or Object form, provided that You meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or Derivative Works a copy
|
||||||
|
of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices stating that
|
||||||
|
You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works that You distribute,
|
||||||
|
all copyright, patent, trademark, and attribution notices from the Source
|
||||||
|
form of the Work, excluding those notices that do not pertain to any part
|
||||||
|
of the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its distribution,
|
||||||
|
then any Derivative Works that You distribute must include a readable copy
|
||||||
|
of the attribution notices contained within such NOTICE file, excluding those
|
||||||
|
notices that do not pertain to any part of the Derivative Works, in at least
|
||||||
|
one of the following places: within a NOTICE text file distributed as part
|
||||||
|
of the Derivative Works; within the Source form or documentation, if provided
|
||||||
|
along with the Derivative Works; or, within a display generated by the Derivative
|
||||||
|
Works, if and wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and do not modify the
|
||||||
|
License. You may add Your own attribution notices within Derivative Works
|
||||||
|
that You distribute, alongside or as an addendum to the NOTICE text from the
|
||||||
|
Work, provided that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and may provide
|
||||||
|
additional or different license terms and conditions for use, reproduction,
|
||||||
|
or distribution of Your modifications, or for any such Derivative Works as
|
||||||
|
a whole, provided Your use, reproduction, and distribution of the Work otherwise
|
||||||
|
complies with the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, any
|
||||||
|
Contribution intentionally submitted for inclusion in the Work by You to the
|
||||||
|
Licensor shall be under the terms and conditions of this License, without
|
||||||
|
any additional terms or conditions. Notwithstanding the above, nothing herein
|
||||||
|
shall supersede or modify the terms of any separate license agreement you
|
||||||
|
may have executed with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade names,
|
||||||
|
trademarks, service marks, or product names of the Licensor, except as required
|
||||||
|
for reasonable and customary use in describing the origin of the Work and
|
||||||
|
reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or agreed to
|
||||||
|
in writing, Licensor provides the Work (and each Contributor provides its
|
||||||
|
Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied, including, without limitation, any warranties
|
||||||
|
or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness
|
||||||
|
of using or redistributing the Work and assume any risks associated with Your
|
||||||
|
exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory, whether
|
||||||
|
in tort (including negligence), contract, or otherwise, unless required by
|
||||||
|
applicable law (such as deliberate and grossly negligent acts) or agreed to
|
||||||
|
in writing, shall any Contributor be liable to You for damages, including
|
||||||
|
any direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character arising as a result of this License or out of the use or inability
|
||||||
|
to use the Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all other commercial
|
||||||
|
damages or losses), even if such Contributor has been advised of the possibility
|
||||||
|
of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing the Work
|
||||||
|
or Derivative Works thereof, You may choose to offer, and charge a fee for,
|
||||||
|
acceptance of support, warranty, indemnity, or other liability obligations
|
||||||
|
and/or rights consistent with this License. However, in accepting such obligations,
|
||||||
|
You may act only on Your own behalf and on Your sole responsibility, not on
|
||||||
|
behalf of any other Contributor, and only if You agree to indemnify, defend,
|
||||||
|
and hold each Contributor harmless for any liability incurred by, or claims
|
||||||
|
asserted against, such Contributor by reason of your accepting any such warranty
|
||||||
|
or additional liability. END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following boilerplate
|
||||||
|
notice, with the fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
information. (Don't include the brackets!) The text should be enclosed in
|
||||||
|
the appropriate comment syntax for the file format. We also recommend that
|
||||||
|
a file or class name and description of purpose be included on the same "printed
|
||||||
|
page" as the copyright notice for easier identification within third-party
|
||||||
|
archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
|
||||||
|
limitations under the License.
|
||||||
@@ -99,18 +99,20 @@ class ReceiveProductSync
|
|||||||
}
|
}
|
||||||
|
|
||||||
$category = ProductCategoryModel::language($lang_id)->tcoId($tco_category['id'])->find();
|
$category = ProductCategoryModel::language($lang_id)->tcoId($tco_category['id'])->find();
|
||||||
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
|
if (!empty($category)) {
|
||||||
if (!empty($tco_parent)) {
|
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
|
||||||
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
|
if (!empty($tco_parent)) {
|
||||||
if ($parent->isEmpty()) {
|
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
|
||||||
throw new \Exception('产品分类父级不存在');
|
if ($parent->isEmpty()) {
|
||||||
|
throw new \Exception('产品分类父级不存在');
|
||||||
|
}
|
||||||
|
$category['pid'] = $parent['id'];
|
||||||
|
$category['path'] = $parent['path'] . $parent['pid'];
|
||||||
|
$category['level'] = $parent['level'] + 1;
|
||||||
|
}
|
||||||
|
if (!$category->save()) {
|
||||||
|
throw new \Exception('产品分类更新失败');
|
||||||
}
|
}
|
||||||
$category['pid'] = $parent['id'];
|
|
||||||
$category['path'] = $parent['path'] . $parent['pid'];
|
|
||||||
$category['level'] = $parent['level'] + 1;
|
|
||||||
}
|
|
||||||
if (!$category->save($category)) {
|
|
||||||
throw new \Exception('产品分类更新失败');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,15 +201,16 @@ class ReceiveProductSync
|
|||||||
throw new \Exception('产品创建失败');
|
throw new \Exception('产品创建失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strtotime($product['updated_at']) < strtotime($data['created_at'])) {
|
// 注释更新同步,防止tco同步修改官网手动调整数据
|
||||||
$product->spu = $data['spu'];
|
// else if (strtotime($product['updated_at']) < strtotime($data['created_at'])) {
|
||||||
$product->name = $data['name'];
|
// $product->spu = $data['spu'];
|
||||||
$product->category_id = $product_category['id'];
|
// $product->name = $data['name'];
|
||||||
$product->status = Operate_Of_ReceiveSync::Disable == $data['operate'] ? -1 : 1;
|
// $product->category_id = $product_category['id'];
|
||||||
if (!$product->save()) {
|
// $product->status = Operate_Of_ReceiveSync::Disable == $data['operate'] ? -1 : 1;
|
||||||
throw new \Exception('产品更新失败');
|
// if (!$product->save()) {
|
||||||
}
|
// throw new \Exception('产品更新失败');
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
return error(sprintf('%s %s:%d', $th->getMessage(), $th->getFile(), $th->getLine()));
|
return error(sprintf('%s %s:%d', $th->getMessage(), $th->getFile(), $th->getLine()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ class Banner
|
|||||||
|
|
||||||
$banner = SysBannerModel::withoutField([
|
$banner = SysBannerModel::withoutField([
|
||||||
'at_page',
|
'at_page',
|
||||||
'unique_label',
|
|
||||||
'language_id',
|
'language_id',
|
||||||
'created_at',
|
'created_at',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
@@ -142,6 +141,7 @@ class Banner
|
|||||||
'name',
|
'name',
|
||||||
'desc',
|
'desc',
|
||||||
'recommend',
|
'recommend',
|
||||||
|
'unique_label',
|
||||||
'at_platform' => 'pc',
|
'at_platform' => 'pc',
|
||||||
'status' => 1
|
'status' => 1
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ class BannerItem
|
|||||||
'rel_prod_cate_id',
|
'rel_prod_cate_id',
|
||||||
'title',
|
'title',
|
||||||
'title_txt_color',
|
'title_txt_color',
|
||||||
|
'short_title',
|
||||||
|
'short_title_txt_color',
|
||||||
'desc',
|
'desc',
|
||||||
'desc_txt_color',
|
'desc_txt_color',
|
||||||
'type',
|
'type',
|
||||||
@@ -156,6 +158,8 @@ class BannerItem
|
|||||||
'rel_prod_cate_id',
|
'rel_prod_cate_id',
|
||||||
'title',
|
'title',
|
||||||
'title_txt_color',
|
'title_txt_color',
|
||||||
|
'short_title',
|
||||||
|
'short_title_txt_color',
|
||||||
'desc',
|
'desc',
|
||||||
'desc_txt_color',
|
'desc_txt_color',
|
||||||
'type',
|
'type',
|
||||||
@@ -240,6 +244,7 @@ class BannerItem
|
|||||||
'banner_name' => '分类名称',
|
'banner_name' => '分类名称',
|
||||||
'title' => '横幅名称',
|
'title' => '横幅名称',
|
||||||
'title_txt_color' => '横幅名称字体颜色',
|
'title_txt_color' => '横幅名称字体颜色',
|
||||||
|
'short_title' => '横幅简称',
|
||||||
'desc' => '描述',
|
'desc' => '描述',
|
||||||
'desc_txt_color' => '描述字体颜色',
|
'desc_txt_color' => '描述字体颜色',
|
||||||
'type' => '前台显示类型',
|
'type' => '前台显示类型',
|
||||||
@@ -262,17 +267,16 @@ 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',
|
||||||
'banner.name' => 'banner_name',
|
'banner.name' => 'banner_name',
|
||||||
'item.title',
|
'item.title',
|
||||||
'item.title_txt_color',
|
'item.title_txt_color',
|
||||||
|
'item.short_title',
|
||||||
'item.desc',
|
'item.desc',
|
||||||
'item.desc_txt_color',
|
'item.desc_txt_color',
|
||||||
'item.type',
|
'item.type',
|
||||||
@@ -311,7 +315,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;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ class NavigationItem
|
|||||||
'id',
|
'id',
|
||||||
'pid',
|
'pid',
|
||||||
'name',
|
'name',
|
||||||
|
'desc',
|
||||||
|
'image',
|
||||||
'nav_id',
|
'nav_id',
|
||||||
'sort',
|
'sort',
|
||||||
'status',
|
'status',
|
||||||
@@ -93,7 +95,9 @@ class NavigationItem
|
|||||||
'pid',
|
'pid',
|
||||||
'nav_id',
|
'nav_id',
|
||||||
'name',
|
'name',
|
||||||
|
'desc',
|
||||||
'icon',
|
'icon',
|
||||||
|
'image',
|
||||||
'link_to' => 'custom',
|
'link_to' => 'custom',
|
||||||
'link',
|
'link',
|
||||||
'sort',
|
'sort',
|
||||||
@@ -121,7 +125,9 @@ class NavigationItem
|
|||||||
'pid',
|
'pid',
|
||||||
'nav_id',
|
'nav_id',
|
||||||
'name',
|
'name',
|
||||||
|
'desc',
|
||||||
'icon',
|
'icon',
|
||||||
|
'image',
|
||||||
'link_to',
|
'link_to',
|
||||||
'link',
|
'link',
|
||||||
'sort',
|
'sort',
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ class Product
|
|||||||
])
|
])
|
||||||
->bypk(request()->param('id'))
|
->bypk(request()->param('id'))
|
||||||
->find()
|
->find()
|
||||||
->bindAttr('category', ['category_name'])
|
?->bindAttr('category', ['category_name'])
|
||||||
->hidden(['category']);
|
->hidden(['category']);
|
||||||
if (empty($product)) {
|
if (empty($product)) {
|
||||||
return error('产品不存在');
|
return error('产品不存在');
|
||||||
@@ -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()) {
|
||||||
// 产品参数
|
// 产品参数
|
||||||
|
|||||||
203
app/admin/controller/v1/ProductCategoryRecommend.php
Normal file
203
app/admin/controller/v1/ProductCategoryRecommend.php
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\ProductCategoryRecommendModel;
|
||||||
|
use app\admin\validate\v1\ProductCategoryRecommendValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品分类推荐管理控制器
|
||||||
|
*/
|
||||||
|
class ProductCategoryRecommend
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 分页列表
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->get([
|
||||||
|
'keywords',
|
||||||
|
'category_name',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
$data = ProductCategoryRecommendModel::withJoin(['category' => function($query) use ($param) {
|
||||||
|
if (!empty($param['category_name'])) {
|
||||||
|
$query->where('category.name', 'like', '%' . $param['category_name'] . '%');
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
->withSearch(['keywords'], ['keywords' => $param['keywords']??null])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page'],
|
||||||
|
])
|
||||||
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
|
->hidden(['category', 'language_id', 'updated_at', 'deleted_at'])
|
||||||
|
?->each(function($item) {
|
||||||
|
// 列表页面图片输出缩略图
|
||||||
|
if (!empty($item['image'])) {
|
||||||
|
$item['image'] = thumb($item['image']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return success('获取成功', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出Excel
|
||||||
|
*/
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$schema = [
|
||||||
|
'id' => 'ID',
|
||||||
|
'image' => '图片',
|
||||||
|
'category_name' => '分类名称',
|
||||||
|
'desc' => '产品介绍',
|
||||||
|
'link' => '链接地址',
|
||||||
|
'sort' => '排序',
|
||||||
|
'disabled' => '状态',
|
||||||
|
'created_at' => '添加时间'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取导出数据
|
||||||
|
$data = $this->getProductCategoryRecommendData();
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
return xlsx_writer($data, $schema, '产品推荐列表' . date('YmdHis'));
|
||||||
|
}
|
||||||
|
// 获取要导出的推荐记录数据
|
||||||
|
private function getProductCategoryRecommendData()
|
||||||
|
{
|
||||||
|
$server = request()->server();
|
||||||
|
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . '/';
|
||||||
|
$param = request()->get(['keywords']);
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
return ProductCategoryRecommendModel::withJoin(['category' => function($query) use ($param) {
|
||||||
|
if (!empty($param['category_name'])) {
|
||||||
|
$query->where('category.name', 'like', '%' . $param['category_name'] . '%');
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
->withSearch(['keywords'], ['keywords' => $param['keywords']??null])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
|
->hidden(['category', 'language_id', 'updated_at', 'deleted_at'])
|
||||||
|
?->each(function($item) use($image_host) {
|
||||||
|
// 拼接完整图片URL
|
||||||
|
if (!empty($item['image'])) {
|
||||||
|
$item['image'] = url_join($image_host, $item['image']);
|
||||||
|
}
|
||||||
|
// 状态
|
||||||
|
$item['disabled'] = $item['disabled'] == 1 ? '禁用' : '启用';
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详细数据
|
||||||
|
*/
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id/d');
|
||||||
|
$record = ProductCategoryRecommendModel::bypk($id)
|
||||||
|
->withoutField(['language_id', 'created_at', 'updated_at', 'deleted_at'])
|
||||||
|
->find();
|
||||||
|
if (empty($record)) {
|
||||||
|
return error('推荐数据不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('success', $record);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增数据
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'category_id',
|
||||||
|
'title',
|
||||||
|
'image',
|
||||||
|
'desc',
|
||||||
|
'link',
|
||||||
|
'sort',
|
||||||
|
'disabled'
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
// 参数校验
|
||||||
|
$validate = new ProductCategoryRecommendValidate();
|
||||||
|
if (!$validate->scene('create')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存推荐数据
|
||||||
|
$recommend = ProductCategoryRecommendModel::create($data);
|
||||||
|
if ($recommend->isEmpty()) {
|
||||||
|
return error('保存失败');
|
||||||
|
}
|
||||||
|
return success('保存成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新数据
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id/d');
|
||||||
|
$post = request()->post([
|
||||||
|
'category_id',
|
||||||
|
'title',
|
||||||
|
'image',
|
||||||
|
'desc',
|
||||||
|
'link',
|
||||||
|
'sort',
|
||||||
|
'disabled'
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
// 参数校验
|
||||||
|
$validate = new ProductCategoryRecommendValidate();
|
||||||
|
$check_data = array_merge($data, ['id' => $id]);
|
||||||
|
if (!$validate->scene('update')->check($check_data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新推荐数据
|
||||||
|
$recommend = ProductCategoryRecommendModel::bypk($id)->find();
|
||||||
|
if (empty($recommend)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
if (!$recommend->save($data)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id/d');
|
||||||
|
|
||||||
|
// 删除推荐记录数据
|
||||||
|
$record = ProductCategoryRecommendModel::bypk($id)->find();
|
||||||
|
if (empty($record)) {
|
||||||
|
return error('请确认操作对象是否正确');
|
||||||
|
}
|
||||||
|
if (!$record->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
201
app/admin/controller/v1/SysMallStoreEntrance.php
Normal file
201
app/admin/controller/v1/SysMallStoreEntrance.php
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysMallStoreEntranceModel;
|
||||||
|
use app\admin\validate\v1\SysMallStoreEntranceValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统商城店铺入口管理控制器
|
||||||
|
*/
|
||||||
|
class SysMallStoreEntrance
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 分页列表
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->get([
|
||||||
|
'name',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
$data = SysMallStoreEntranceModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'hover_image',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], ['name' => $param['name']??null])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page'],
|
||||||
|
])
|
||||||
|
?->each(function($item) {
|
||||||
|
// 列表页面图片输出缩略图
|
||||||
|
if (!empty($item['image'])) {
|
||||||
|
$item['image'] = thumb($item['image']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return success('获取成功', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情
|
||||||
|
*/
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id/d');
|
||||||
|
$record = SysMallStoreEntranceModel::bypk($id)
|
||||||
|
->withoutField(['language_id', 'created_at', 'updated_at', 'deleted_at'])
|
||||||
|
->find();
|
||||||
|
if (empty($record)) {
|
||||||
|
return error('商城店铺入口数据不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('success', $record);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增数据
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'name',
|
||||||
|
'image',
|
||||||
|
'hover_image',
|
||||||
|
'link',
|
||||||
|
'sort',
|
||||||
|
'disabled'
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
// 参数校验
|
||||||
|
$validate = new SysMallStoreEntranceValidate();
|
||||||
|
if (!$validate->scene('create')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存数据
|
||||||
|
$entrance = SysMallStoreEntranceModel::create($data);
|
||||||
|
if ($entrance->isEmpty()) {
|
||||||
|
return error('保存失败');
|
||||||
|
}
|
||||||
|
return success('保存成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新数据
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id/d');
|
||||||
|
$post = request()->post([
|
||||||
|
'name',
|
||||||
|
'image',
|
||||||
|
'hover_image',
|
||||||
|
'link',
|
||||||
|
'sort',
|
||||||
|
'disabled'
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
// 参数校验
|
||||||
|
$validate = new SysMallStoreEntranceValidate();
|
||||||
|
$check_data = array_merge($data, ['id' => $id]);
|
||||||
|
if (!$validate->scene('update')->check($check_data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新数据
|
||||||
|
$entrance = SysMallStoreEntranceModel::bypk($id)->find();
|
||||||
|
if (empty($entrance)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
if (!$entrance->save($data)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id/d');
|
||||||
|
|
||||||
|
// 删除数据
|
||||||
|
$record = SysMallStoreEntranceModel::bypk($id)->find();
|
||||||
|
if (empty($record)) {
|
||||||
|
return error('请确认操作对象是否正确');
|
||||||
|
}
|
||||||
|
if (!$record->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出Excel
|
||||||
|
*/
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$schema = [
|
||||||
|
'id' => 'ID',
|
||||||
|
'image' => '图片',
|
||||||
|
'hover_image' => '悬浮图',
|
||||||
|
'name' => '名称',
|
||||||
|
'link' => '链接地址',
|
||||||
|
'sort' => '排序',
|
||||||
|
'disabled' => '状态',
|
||||||
|
'created_at' => '添加时间'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取导出数据
|
||||||
|
$data = $this->getExportData();
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
return xlsx_writer($data, $schema, '系统商城店铺入口列表' . date('YmdHis'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取要导出的数据
|
||||||
|
private function getExportData()
|
||||||
|
{
|
||||||
|
$server = request()->server();
|
||||||
|
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . '/';
|
||||||
|
$param = request()->get(['name']);
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
return SysMallStoreEntranceModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], ['name' => $param['name']??null])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
?->each(function($item) use($image_host) {
|
||||||
|
// 拼接完整图片URL
|
||||||
|
if (!empty($item['image'])) {
|
||||||
|
$item['image'] = url_join($image_host, $item['image']);
|
||||||
|
}
|
||||||
|
if (!empty($item['hover_image'])) {
|
||||||
|
$item['hover_image'] = url_join($image_host, $item['hover_image']);
|
||||||
|
}
|
||||||
|
// 状态转换
|
||||||
|
$item['disabled'] = $item['disabled'] == 1 ? '禁用' : '启用';
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -342,6 +342,30 @@ class System
|
|||||||
'url' => (string)url('/index/topic/nas/download')
|
'url' => (string)url('/index/topic/nas/download')
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 8,
|
||||||
|
'name' => '电力品线专题',
|
||||||
|
'url' => '',
|
||||||
|
'children' => [
|
||||||
|
[
|
||||||
|
'id' => 81,
|
||||||
|
'name' => '首页',
|
||||||
|
'url' => (string)url('/index/topic/power_prodline/index')
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 9,
|
||||||
|
'name' => '笔记本(AI PC)专题',
|
||||||
|
'url' => '',
|
||||||
|
'children' => [
|
||||||
|
[
|
||||||
|
'id' => 91,
|
||||||
|
'name' => '首页',
|
||||||
|
'url' => (string)url('/index/topic/laptop/index')
|
||||||
|
],
|
||||||
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件上传控制器
|
* 文件上传控制器
|
||||||
@@ -153,8 +154,8 @@ class Upload
|
|||||||
$image_model = new SysImageUploadRecordModel();
|
$image_model = new SysImageUploadRecordModel();
|
||||||
$image_model->language_id = request()->lang_id;
|
$image_model->language_id = request()->lang_id;
|
||||||
$image_model->module = $param['module'];
|
$image_model->module = $param['module'];
|
||||||
$image_model->image_path = $filename;
|
$image_model->image_path = $storage . '/' . $filename;
|
||||||
$image_model->image_thumb = $thumb_filename;
|
$image_model->image_thumb = $storage . '/' . $thumb_filename;
|
||||||
$image_model->file_size = $file_size;
|
$image_model->file_size = $file_size;
|
||||||
$image_model->file_type = $mime_type;
|
$image_model->file_type = $mime_type;
|
||||||
$image_model->file_md5 = $filemd5;
|
$image_model->file_md5 = $filemd5;
|
||||||
@@ -165,8 +166,8 @@ class Upload
|
|||||||
}
|
}
|
||||||
|
|
||||||
return success('操作成功', [
|
return success('操作成功', [
|
||||||
'path' => $storage . '/' . $image_model->image_path,
|
'path' => $image_model->image_path,
|
||||||
'thumb_path' => $storage . '/' . $image_model->image_thumb,
|
'thumb_path' => $image_model->image_thumb,
|
||||||
'filemd5' => $image_model->file_md5,
|
'filemd5' => $image_model->file_md5,
|
||||||
'filesha1' => $image_model->file_sha1
|
'filesha1' => $image_model->file_sha1
|
||||||
]);
|
]);
|
||||||
@@ -226,6 +227,7 @@ class Upload
|
|||||||
'filename_keep' => (int)data_get($options, 'filename_keep.value', 0) == 1,
|
'filename_keep' => (int)data_get($options, 'filename_keep.value', 0) == 1,
|
||||||
'filemd5_unique' => (int)data_get($options, 'filemd5_unique.value', 0) == 1,
|
'filemd5_unique' => (int)data_get($options, 'filemd5_unique.value', 0) == 1,
|
||||||
'filetype_to' => data_get($options, 'filetype_to.value', 'original'),
|
'filetype_to' => data_get($options, 'filetype_to.value', 'original'),
|
||||||
|
'save_to' => data_get($options, 'save_to.value', 'local'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -345,20 +347,35 @@ class Upload
|
|||||||
// 获取视频上传配置
|
// 获取视频上传配置
|
||||||
list(
|
list(
|
||||||
'filename_keep' => $filename_keep,
|
'filename_keep' => $filename_keep,
|
||||||
'filemd5_unique' => $filemd5_unique
|
'filemd5_unique' => $filemd5_unique,
|
||||||
|
'save_to' => $save_to,
|
||||||
) = $this->getUploadOptions('upload_video');
|
) = $this->getUploadOptions('upload_video');
|
||||||
// 是否需要根据文件MD5值检查文件是否已存在
|
// 是否需要根据文件MD5值检查文件是否已存在
|
||||||
$video = $filemd5_unique ? SysVideoUploadRecordModel::md5($filemd5)->find() : null;
|
$video = $filemd5_unique ? SysVideoUploadRecordModel::md5($filemd5)->find() : null;
|
||||||
if (is_null($video)) {
|
if (is_null($video)) {
|
||||||
|
// 保存位置配置 key
|
||||||
|
$disk = 'video';
|
||||||
// 检查是否需要保留原文件名
|
// 检查是否需要保留原文件名
|
||||||
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
||||||
$filename = Filesystem::disk('video')->putFile($param['module'], $file, $name_rule());
|
|
||||||
|
// 保存到七牛云
|
||||||
|
if ($save_to == 'qiniu_cloud') {
|
||||||
|
$disk = 'video_qiniu';
|
||||||
|
$storage = config('filesystem.disks.video_qiniu.path_prefix');
|
||||||
|
}
|
||||||
|
$filename = Filesystem::disk($disk)->putFile($param['module'], $file, $name_rule());
|
||||||
|
|
||||||
|
// 组装视频路径
|
||||||
|
$video_path = $storage . '/' . $filename;
|
||||||
|
if ($save_to == 'qiniu_cloud') {
|
||||||
|
$video_path = Filesystem::disk($disk)->url($filename);
|
||||||
|
}
|
||||||
|
|
||||||
// 保存视频
|
// 保存视频
|
||||||
$video = new SysVideoUploadRecordModel();
|
$video = new SysVideoUploadRecordModel();
|
||||||
$video->language_id = request()->lang_id;
|
$video->language_id = request()->lang_id;
|
||||||
$video->module = $param['module'];
|
$video->module = $param['module'];
|
||||||
$video->video_path = $filename;
|
$video->video_path = $video_path;
|
||||||
$video->file_size = $file->getSize();
|
$video->file_size = $file->getSize();
|
||||||
$video->file_type = $file->getOriginalMime();
|
$video->file_type = $file->getOriginalMime();
|
||||||
$video->file_md5 = $filemd5;
|
$video->file_md5 = $filemd5;
|
||||||
@@ -369,7 +386,7 @@ class Upload
|
|||||||
}
|
}
|
||||||
|
|
||||||
return success('上传成功', [
|
return success('上传成功', [
|
||||||
'path' => $storage . '/' . $video->video_path,
|
'path' => $video->video_path,
|
||||||
'file_md5' => $video->file_md5,
|
'file_md5' => $video->file_md5,
|
||||||
'file_sha1' => $video->file_sha1
|
'file_sha1' => $video->file_sha1
|
||||||
]);
|
]);
|
||||||
@@ -399,25 +416,42 @@ class Upload
|
|||||||
return error($validate->getError());
|
return error($validate->getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$storage = config('filesystem.disks.public.url');
|
||||||
|
|
||||||
$filemd5 = $file->md5();
|
$filemd5 = $file->md5();
|
||||||
$filesha1 = $file->sha1();
|
$filesha1 = $file->sha1();
|
||||||
|
|
||||||
// 获取附件上传配置
|
// 获取附件上传配置
|
||||||
list(
|
list(
|
||||||
'filename_keep' => $filename_keep,
|
'filename_keep' => $filename_keep,
|
||||||
'filemd5_unique' => $filemd5_unique
|
'filemd5_unique' => $filemd5_unique,
|
||||||
|
'save_to' => $save_to
|
||||||
) = $this->getUploadOptions('upload_attachment');
|
) = $this->getUploadOptions('upload_attachment');
|
||||||
// 是否需要根据文件MD5值检查文件是否已存在
|
// 是否需要根据文件MD5值检查文件是否已存在
|
||||||
$attachment = $filemd5_unique ? SysAttachmentUploadRecordModel::md5($filemd5)->find() : null;
|
$attachment = $filemd5_unique ? SysAttachmentUploadRecordModel::md5($filemd5)->find() : null;
|
||||||
if (is_null($attachment)) {
|
if (is_null($attachment)) {
|
||||||
|
// 保存位置配置 key
|
||||||
|
$disk = 'public';
|
||||||
// 检查是否需要保留原文件名
|
// 检查是否需要保留原文件名
|
||||||
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
||||||
$filename = Filesystem::disk('public')->putFile('attachments', $file, $name_rule());
|
|
||||||
|
|
||||||
// 保存视频
|
// 保存到七牛云
|
||||||
|
if ($save_to == 'qiniu_cloud') {
|
||||||
|
$disk = 'public_qiniu';
|
||||||
|
$storage = config('filesystem.disks.public_qiniu.path_prefix');
|
||||||
|
}
|
||||||
|
$filename = Filesystem::disk($disk)->putFile('attachments', $file, $name_rule());
|
||||||
|
|
||||||
|
// 组装附件路径
|
||||||
|
$attachment_path = $storage . '/' . $filename;
|
||||||
|
if ($save_to == 'qiniu_cloud') {
|
||||||
|
$attachment_path = Filesystem::disk($disk)->url($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存附件
|
||||||
$attachment = new SysAttachmentUploadRecordModel();
|
$attachment = new SysAttachmentUploadRecordModel();
|
||||||
$attachment->language_id = request()->lang_id;
|
$attachment->language_id = request()->lang_id;
|
||||||
$attachment->attachment_path = $filename;
|
$attachment->attachment_path = $attachment_path;
|
||||||
$attachment->file_size = $file->getSize();
|
$attachment->file_size = $file->getSize();
|
||||||
$attachment->file_type = $file->getOriginalMime();
|
$attachment->file_type = $file->getOriginalMime();
|
||||||
$attachment->file_md5 = $filemd5;
|
$attachment->file_md5 = $filemd5;
|
||||||
@@ -427,9 +461,8 @@ class Upload
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$storage = config('filesystem.disks.public.url');
|
|
||||||
return success('上传成功', [
|
return success('上传成功', [
|
||||||
'path' => $storage . '/' . $attachment->attachment_path,
|
'path' => $attachment->attachment_path,
|
||||||
'file_md5' => $attachment->file_md5,
|
'file_md5' => $attachment->file_md5,
|
||||||
'file_sha1' => $attachment->file_sha1
|
'file_sha1' => $attachment->file_sha1
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -209,9 +209,6 @@ class Video
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$domain = request()->domain();
|
$domain = request()->domain();
|
||||||
$image_path = Config::get('filesystem.disks.image.url');
|
|
||||||
$video_path = Config::get('filesystem.disks.video.url');
|
|
||||||
|
|
||||||
return VideoModel::withoutField([
|
return VideoModel::withoutField([
|
||||||
'language_id',
|
'language_id',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
@@ -230,13 +227,9 @@ class Video
|
|||||||
->select()
|
->select()
|
||||||
->bindAttr('category', ['category_name' => 'name'])
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
->hidden(['category_id', 'category'])
|
->hidden(['category_id', 'category'])
|
||||||
->each(function ($item) use($domain, $image_path, $video_path) {
|
->each(function ($item) use($domain) {
|
||||||
if (!empty($item->image)) {
|
$item->image = !empty($item->image) ? url_join($domain, $item->image) : '';
|
||||||
$item->image = $domain . $image_path . '/' . $item->image;
|
$item->video = !empty($item->video) ? url_join($domain, $item->video) : '';
|
||||||
}
|
|
||||||
if (!empty($item->video)) {
|
|
||||||
$item->video = $domain . $video_path . '/' . $item->video;
|
|
||||||
}
|
|
||||||
$item->recommend = $item->recommend == 1 ? '是' : '否';
|
$item->recommend = $item->recommend == 1 ? '是' : '否';
|
||||||
$item->status = $item->status == 1 ? '启用' : '禁用';
|
$item->status = $item->status == 1 ? '启用' : '禁用';
|
||||||
return $item;
|
return $item;
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ class ProductCategoryModel extends ProductCategoryBaseModel
|
|||||||
// 所属产品目录分类id查询
|
// 所属产品目录分类id查询
|
||||||
public function scopeTcoId($query, $value)
|
public function scopeTcoId($query, $value)
|
||||||
{
|
{
|
||||||
$query->where('related_tco_category', '=', $value);
|
// $query->where('related_tco_category', '=', $value);
|
||||||
|
$query->whereRaw('FIND_IN_SET(:ref_id, related_tco_category)', ['ref_id' => $value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
47
app/admin/model/v1/ProductCategoryRecommendModel.php
Normal file
47
app/admin/model/v1/ProductCategoryRecommendModel.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\ProductCategoryRecommendBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品分类推荐模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ProductCategoryRecommendModel extends ProductCategoryRecommendBaseModel
|
||||||
|
{
|
||||||
|
// 启用软件删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软件删除时间字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联语言
|
||||||
|
public function language()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(\app\index\model\LanguageModel::class, 'language_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关联产品分类
|
||||||
|
public function category()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(\app\index\model\ProductCategoryModel::class, 'category_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所属语言范围查询
|
||||||
|
public function scopeLanguage($query, $language)
|
||||||
|
{
|
||||||
|
$query->where($this->getTable() . '.language_id', '=', $language);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关键词搜索
|
||||||
|
public function searchKeywordsAttr($query, string|null $keywords)
|
||||||
|
{
|
||||||
|
if (is_null($keywords)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where($this->getTable() . '.title', 'like', "%{$keywords}%")
|
||||||
|
->whereOr($this->getTable() . '.desc', 'like', "%{$keywords}%");
|
||||||
|
}
|
||||||
|
}
|
||||||
61
app/admin/model/v1/SysMallStoreEntranceModel.php
Normal file
61
app/admin/model/v1/SysMallStoreEntranceModel.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysMallStoreEntranceBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统商城店铺入口模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysMallStoreEntranceModel extends SysMallStoreEntranceBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联语言
|
||||||
|
public function language()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(\app\index\model\LanguageModel::class, 'language_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所属语言范围查询
|
||||||
|
public function scopeLanguage($query, $language)
|
||||||
|
{
|
||||||
|
$query->where($this->getTable() . '.language_id', '=', $language);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询启用状态
|
||||||
|
public function scopeEnabled($query)
|
||||||
|
{
|
||||||
|
$query->where('disabled', '=', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询禁用状态
|
||||||
|
public function scopeDisabled($query)
|
||||||
|
{
|
||||||
|
$query->where('disabled', '=', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按名称搜索
|
||||||
|
public function searchNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('name', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按链接地址搜索
|
||||||
|
public function searchLinkAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('link_url', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -311,6 +311,27 @@ Route::group('v1', function () {
|
|||||||
|
|
||||||
// 分类删除
|
// 分类删除
|
||||||
Route::delete('delete/:id', 'ProductCategory/delete');
|
Route::delete('delete/:id', 'ProductCategory/delete');
|
||||||
|
|
||||||
|
// 产品分类推荐数据
|
||||||
|
Route::group('recommend', function () {
|
||||||
|
// 推荐数据分页列表
|
||||||
|
Route::get('index', 'ProductCategoryRecommend/index');
|
||||||
|
|
||||||
|
// 推荐数据导出
|
||||||
|
Route::get('export', 'ProductCategoryRecommend/export');
|
||||||
|
|
||||||
|
// 推荐数据详情
|
||||||
|
Route::get('read/:id', 'ProductCategoryRecommend/read');
|
||||||
|
|
||||||
|
// 推荐数据新增
|
||||||
|
Route::post('save', 'ProductCategoryRecommend/save');
|
||||||
|
|
||||||
|
// 推荐数据更新
|
||||||
|
Route::put('update/:id', 'ProductCategoryRecommend/update');
|
||||||
|
|
||||||
|
// 推荐数据删除
|
||||||
|
Route::delete('delete/:id', 'ProductCategoryRecommend/delete');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 产品购买链接
|
// 产品购买链接
|
||||||
@@ -574,6 +595,29 @@ Route::group('v1', function () {
|
|||||||
// 反馈管理 - 产品询盘列表
|
// 反馈管理 - 产品询盘列表
|
||||||
Route::get('product/inquiry/index', 'ProductInquiry/index');
|
Route::get('product/inquiry/index', 'ProductInquiry/index');
|
||||||
|
|
||||||
|
// 系统商城店铺入口
|
||||||
|
Route::group('mall', function() {
|
||||||
|
Route::group('store', function() {
|
||||||
|
// 店铺入口列表分页
|
||||||
|
Route::get('index', 'SysMallStoreEntrance/index');
|
||||||
|
|
||||||
|
// 店铺入口导出
|
||||||
|
Route::get('export', 'SysMallStoreEntrance/export');
|
||||||
|
|
||||||
|
// 店铺入口详情
|
||||||
|
Route::get('read/:id', 'SysMallStoreEntrance/read');
|
||||||
|
|
||||||
|
// 店铺入口新增
|
||||||
|
Route::post('save', 'SysMallStoreEntrance/save');
|
||||||
|
|
||||||
|
// 店铺入口更新
|
||||||
|
Route::put('update/:id', 'SysMallStoreEntrance/update');
|
||||||
|
|
||||||
|
// 店铺入口删除
|
||||||
|
Route::delete('delete/:id', 'SysMallStoreEntrance/delete');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// 配置项列表
|
// 配置项列表
|
||||||
Route::group('config', function() {
|
Route::group('config', function() {
|
||||||
// 配置分组
|
// 配置分组
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ class NavigationItemValidate extends Validate
|
|||||||
'nav_id' => 'require|integer',
|
'nav_id' => 'require|integer',
|
||||||
'pid' => 'integer|different:id|checkPidNotBeChildren',
|
'pid' => 'integer|different:id|checkPidNotBeChildren',
|
||||||
'name' => 'require|max:64',
|
'name' => 'require|max:64',
|
||||||
|
'desc' => 'max:255',
|
||||||
'icon' => 'max:64',
|
'icon' => 'max:64',
|
||||||
|
'image' => 'max:255',
|
||||||
'link_to' => 'require|max:64|in:article,article_category,product,product_category,system_page,custom',
|
'link_to' => 'require|max:64|in:article,article_category,product,product_category,system_page,custom',
|
||||||
'link' => 'max:255',
|
'link' => 'max:255',
|
||||||
'sort' => 'integer',
|
'sort' => 'integer',
|
||||||
@@ -44,7 +46,9 @@ class NavigationItemValidate extends Validate
|
|||||||
'pid.checkPidNotBeChildren' => '父级ID不能为自身的子导航',
|
'pid.checkPidNotBeChildren' => '父级ID不能为自身的子导航',
|
||||||
'name.require' => '导航名称不能为空',
|
'name.require' => '导航名称不能为空',
|
||||||
'name.max' => '导航名称最多不能超过64个字符',
|
'name.max' => '导航名称最多不能超过64个字符',
|
||||||
|
'desc.max' => '导航名称最多不能超过:rule个字符',
|
||||||
'icon.max' => '图标最多不能超过64个字符',
|
'icon.max' => '图标最多不能超过64个字符',
|
||||||
|
'image.max' => '图标最多不能超过:rule个字符',
|
||||||
'link_to.require' => '链接类型不能为空',
|
'link_to.require' => '链接类型不能为空',
|
||||||
'link_to.max' => '链接类型最多不能超过64个字符',
|
'link_to.max' => '链接类型最多不能超过64个字符',
|
||||||
'link_to.in' => '链接类型必须是article,article_category,product_category,product,system_page,custom中之一',
|
'link_to.in' => '链接类型必须是article,article_category,product_category,product,system_page,custom中之一',
|
||||||
|
|||||||
63
app/admin/validate/v1/ProductCategoryRecommendValidate.php
Normal file
63
app/admin/validate/v1/ProductCategoryRecommendValidate.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\validate\v1;
|
||||||
|
|
||||||
|
use think\Validate;
|
||||||
|
|
||||||
|
class ProductCategoryRecommendValidate extends Validate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 定义验证规则
|
||||||
|
* 格式:'字段名' => ['规则1','规则2'...]
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $rule = [
|
||||||
|
'language_id' => 'require|integer',
|
||||||
|
'category_id' => 'require|integer',
|
||||||
|
'title' => 'require|max:255',
|
||||||
|
'image' => 'require|max:255',
|
||||||
|
'desc' => 'require|max:255',
|
||||||
|
'link' => 'max:500',
|
||||||
|
'sort' => 'require|integer',
|
||||||
|
'disabled' => 'in:0,1'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义错误信息
|
||||||
|
* 格式:'字段名.规则名' => '错误信息'
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $message = [
|
||||||
|
'id.require' => 'ID不能为空',
|
||||||
|
'id.integer' => 'ID必须是整数',
|
||||||
|
'language_id.require' => '语言ID不能为空',
|
||||||
|
'language_id.integer' => '语言ID必须是整数',
|
||||||
|
'category_id.require' => '分类ID不能为空',
|
||||||
|
'category_id.integer' => '分类ID必须是整数',
|
||||||
|
'title.require' => '标题不能为空',
|
||||||
|
'title.max' => '标题长度不能超过:rule个字符',
|
||||||
|
'image.require' => '图片不能为空',
|
||||||
|
'image.max' => '图片长度不能超过:rule个字符',
|
||||||
|
'desc.require' => '描述不能为空',
|
||||||
|
'desc.max' => '描述长度不能超过:rule个字符',
|
||||||
|
'link.max' => '链接长度不能超过:rule个字符',
|
||||||
|
'sort.require' => '排序不能为空',
|
||||||
|
'sort.integer' => '排序必须是整数',
|
||||||
|
'disabled.in' => '禁用状态只能是0或1',
|
||||||
|
];
|
||||||
|
|
||||||
|
// 新增场景
|
||||||
|
protected function sceneCreate()
|
||||||
|
{
|
||||||
|
return $this->remove('id', 'require|integer');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新场景
|
||||||
|
protected function sceneUpdate()
|
||||||
|
{
|
||||||
|
return $this->append('id', 'require|integer');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ class ProductCategoryValidate extends Validate
|
|||||||
'name' => 'require|max:64',
|
'name' => 'require|max:64',
|
||||||
'icon' => 'max:125',
|
'icon' => 'max:125',
|
||||||
'desc' => 'max:255',
|
'desc' => 'max:255',
|
||||||
'related_tco_category' => 'integer',
|
'related_tco_category' => 'string|checkRelatedTcoCategory',
|
||||||
'sort' => 'integer',
|
'sort' => 'integer',
|
||||||
'level' => 'integer',
|
'level' => 'integer',
|
||||||
'is_show' => 'in:0,1',
|
'is_show' => 'in:0,1',
|
||||||
@@ -39,25 +39,26 @@ class ProductCategoryValidate extends Validate
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $message = [
|
protected $message = [
|
||||||
'id.require' => 'ID不能为空',
|
'id.require' => 'ID不能为空',
|
||||||
'id.integer' => 'ID必须为整数',
|
'id.integer' => 'ID必须为整数',
|
||||||
'language_id.require' => '语言ID不能为空',
|
'language_id.require' => '语言ID不能为空',
|
||||||
'language_id.integer' => '语言ID必须为整数',
|
'language_id.integer' => '语言ID必须为整数',
|
||||||
'unique_id.require' => '唯一标识不能为空',
|
'unique_id.require' => '唯一标识不能为空',
|
||||||
'pid.different' => '父级ID不能为自身',
|
'pid.different' => '父级ID不能为自身',
|
||||||
'pid.checkPidNotBeChildren' => '父级ID不能为自身的子分类',
|
'pid.checkPidNotBeChildren' => '父级ID不能为自身的子分类',
|
||||||
'pid.integer' => '父级ID必须为整数',
|
'pid.integer' => '父级ID必须为整数',
|
||||||
'name.require' => '名称不能为空',
|
'name.require' => '名称不能为空',
|
||||||
'name.max' => '名称最多不能超过64个字符',
|
'name.max' => '名称最多不能超过64个字符',
|
||||||
'icon.max' => '图标最多不能超过125个字符',
|
'icon.max' => '图标最多不能超过125个字符',
|
||||||
'desc.max' => '描述最多不能超过255个字符',
|
'desc.max' => '描述最多不能超过255个字符',
|
||||||
'related_tco_category.integer' => '关联TCO分类格式错误',
|
'related_tco_category.string' => '关联TCO分类格式错误',
|
||||||
'sort.integer' => '排序格式错误',
|
'related_tco_category.checkRelatedTcoCategory' => '该TCO分类已绑定',
|
||||||
'level.integer' => '级别格式错误',
|
'sort.integer' => '排序格式错误',
|
||||||
'is_show.in' => '是否显示格式错误',
|
'level.integer' => '级别格式错误',
|
||||||
'seo_title.max' => 'SEO标题最多不能超过255个字符',
|
'is_show.in' => '是否显示格式错误',
|
||||||
'seo_keywords.max' => 'SEO关键字最多不能超过255个字符',
|
'seo_title.max' => 'SEO标题最多不能超过255个字符',
|
||||||
'seo_desc.max' => 'SEO描述最多不能超过255个字符',
|
'seo_keywords.max' => 'SEO关键字最多不能超过255个字符',
|
||||||
|
'seo_desc.max' => 'SEO描述最多不能超过255个字符',
|
||||||
];
|
];
|
||||||
|
|
||||||
// 验证pid
|
// 验证pid
|
||||||
@@ -84,4 +85,32 @@ class ProductCategoryValidate extends Validate
|
|||||||
{
|
{
|
||||||
return $this->remove('id', 'require|integer')->remove('pid', 'different|checkPidNotBeChildren');
|
return $this->remove('id', 'require|integer')->remove('pid', 'different|checkPidNotBeChildren');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证related_tco_category
|
||||||
|
protected function checkRelatedTcoCategory($value, $rule, $data = [])
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$val = ProductCategoryModel::where(function($query) use($value) {
|
||||||
|
$arr = explode(",", $value);
|
||||||
|
foreach ($arr as $v) {
|
||||||
|
$query->whereFindInSet('related_tco_category', $v, 'OR');
|
||||||
|
}
|
||||||
|
})->column('id');
|
||||||
|
if (!empty($val)) {
|
||||||
|
$size = count($val);
|
||||||
|
// 如果存在超过一个,直接验证失败
|
||||||
|
if ($size > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 如果存在一个,并存在的id不为自身,验证失败(考虑更新场景查到自身情况)
|
||||||
|
if ($size == 1 && $val[0] != $data['id']) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ namespace app\admin\validate\v1;
|
|||||||
|
|
||||||
use think\Validate;
|
use think\Validate;
|
||||||
|
|
||||||
use function PHPSTORM_META\type;
|
|
||||||
|
|
||||||
class ProductValidate extends Validate
|
class ProductValidate extends Validate
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ class SysBannerItemValidate extends Validate
|
|||||||
'banner_id' => 'require|integer|gt:0',
|
'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:2048',
|
||||||
'desc_txt_color' => 'max:7',
|
'desc_txt_color' => 'max:7',
|
||||||
'type' => 'in:image,video',
|
'type' => 'in:image,video',
|
||||||
'image' => 'max:255',
|
'image' => 'max:255',
|
||||||
'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'
|
||||||
];
|
];
|
||||||
@@ -45,7 +45,7 @@ class SysBannerItemValidate extends Validate
|
|||||||
'title.require' => '名称不能为空',
|
'title.require' => '名称不能为空',
|
||||||
'title.max' => '名称最多不能超过256个字符',
|
'title.max' => '名称最多不能超过256个字符',
|
||||||
'title_txt_color.max' => '名称字体颜色最多不能超过7个字符',
|
'title_txt_color.max' => '名称字体颜色最多不能超过7个字符',
|
||||||
'desc.max' => '描述最多不能超过1024个字符',
|
'desc.max' => '描述最多不能超过2048个字符',
|
||||||
'desc_txt_color.max' => '描述字体颜色最多不能超过7个字符',
|
'desc_txt_color.max' => '描述字体颜色最多不能超过7个字符',
|
||||||
'type.in' => '显示类型必须是image或video',
|
'type.in' => '显示类型必须是image或video',
|
||||||
'image.max' => '图片地址最多不能超过255个字符',
|
'image.max' => '图片地址最多不能超过255个字符',
|
||||||
@@ -54,7 +54,7 @@ class SysBannerItemValidate extends Validate
|
|||||||
'link_to.requireIf' => '链接类型不能为空',
|
'link_to.requireIf' => '链接类型不能为空',
|
||||||
'link_to.max' => '链接类型最多不能超过64个字符',
|
'link_to.max' => '链接类型最多不能超过64个字符',
|
||||||
'link_to.in' => '链接类型必须是article,article_category,product,product_category,system_page,custom中之一',
|
'link_to.in' => '链接类型必须是article,article_category,product,product_category,system_page,custom中之一',
|
||||||
'link.max' => '链接最多不能超过255个字符',
|
'link.max' => '链接最多不能超过512个字符',
|
||||||
'sort.integer' => '排序值必须是整数',
|
'sort.integer' => '排序值必须是整数',
|
||||||
'status.in' => '状态必须是-1或1'
|
'status.in' => '状态必须是-1或1'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ class SysBannerValidate extends BaseValidate
|
|||||||
'at_platform.in' => '显示端口只能是pc或mobile',
|
'at_platform.in' => '显示端口只能是pc或mobile',
|
||||||
'at_page.max' => '页面位置最多255个字符',
|
'at_page.max' => '页面位置最多255个字符',
|
||||||
'unique_label.max' => '唯一标识最多64个字符',
|
'unique_label.max' => '唯一标识最多64个字符',
|
||||||
'unique_label.mustOmit' => '更新时不能有unique_label字段',
|
|
||||||
'name.require' => '名称不能为空',
|
'name.require' => '名称不能为空',
|
||||||
'name.max' => '名称最多64个字符',
|
'name.max' => '名称最多64个字符',
|
||||||
'desc.max' => '描述最多255个字符',
|
'desc.max' => '描述最多255个字符',
|
||||||
@@ -61,6 +60,6 @@ class SysBannerValidate extends BaseValidate
|
|||||||
// 编辑场景
|
// 编辑场景
|
||||||
public function sceneEdit()
|
public function sceneEdit()
|
||||||
{
|
{
|
||||||
return $this->remove('language_id', 'require|integer')->append('unique_label', 'mustOmit');
|
return $this->remove('language_id', 'require|integer');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
61
app/admin/validate/v1/SysMallStoreEntranceValidate.php
Normal file
61
app/admin/validate/v1/SysMallStoreEntranceValidate.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\validate\v1;
|
||||||
|
|
||||||
|
use think\Validate;
|
||||||
|
|
||||||
|
class SysMallStoreEntranceValidate extends Validate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 定义验证规则
|
||||||
|
* 格式:'字段名' => ['规则1','规则2'...]
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $rule = [
|
||||||
|
'id' => 'require|integer',
|
||||||
|
'language_id' => 'require|integer',
|
||||||
|
'name' => 'require|max:255',
|
||||||
|
'image' => 'require|max:255',
|
||||||
|
'hover_image' => 'max:255',
|
||||||
|
'link' => 'url|max:500',
|
||||||
|
'sort' => 'require|integer',
|
||||||
|
'disabled' => 'in:0,1',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义错误信息
|
||||||
|
* 格式:'字段名.规则名' => '错误信息'
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $message = [
|
||||||
|
'id.require' => 'ID不能为空',
|
||||||
|
'id.integer' => 'ID必须是整数',
|
||||||
|
'language_id.require' => '语言ID不能为空',
|
||||||
|
'language_id.integer' => '语言ID必须是整数',
|
||||||
|
'name.require' => '商城名称不能为空',
|
||||||
|
'name.max' => '商城名称长度不能超过:rule个字符',
|
||||||
|
'image.require' => '图片不能为空',
|
||||||
|
'image.max' => '图片长度不能超过:rule个字符',
|
||||||
|
'hover_image.max' => '悬浮图长度不能超过:rule个字符',
|
||||||
|
'link.url' => '链接地址必须是有效的URL',
|
||||||
|
'link.max' => '链接地址长度不能超过:rule个字符',
|
||||||
|
'sort.require' => '排序不能为空',
|
||||||
|
'sort.integer' => '排序必须是整数',
|
||||||
|
'disabled.in' => '禁用状态只能是0或1',
|
||||||
|
];
|
||||||
|
|
||||||
|
// 新增场景
|
||||||
|
protected function sceneCreate()
|
||||||
|
{
|
||||||
|
return $this->remove('id', 'require|integer');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新场景
|
||||||
|
protected function sceneUpdate()
|
||||||
|
{
|
||||||
|
return $this->append('id', 'require|integer');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ class VideoValidate extends Validate
|
|||||||
'id' => 'require|integer',
|
'id' => 'require|integer',
|
||||||
'language_id' => 'require|integer',
|
'language_id' => 'require|integer',
|
||||||
'category_id' => 'require|integer',
|
'category_id' => 'require|integer',
|
||||||
'name' => 'require|max:64',
|
'name' => 'require|max:128',
|
||||||
'desc' => 'max:512',
|
'desc' => 'max:512',
|
||||||
'image' => 'max:125',
|
'image' => 'max:125',
|
||||||
'video' => 'max:125',
|
'video' => 'max:125',
|
||||||
@@ -43,7 +43,7 @@ class VideoValidate extends Validate
|
|||||||
'category_id.require' => '分类不能为空',
|
'category_id.require' => '分类不能为空',
|
||||||
'category_id.integer' => '分类参数类型错误',
|
'category_id.integer' => '分类参数类型错误',
|
||||||
'name.require' => '名称不能为空',
|
'name.require' => '名称不能为空',
|
||||||
'name.max' => '名称不能超过64个字符',
|
'name.max' => '名称不能超过128个字符',
|
||||||
'desc.max' => '描述不能超过512个字符',
|
'desc.max' => '描述不能超过512个字符',
|
||||||
'image.max' => '图片不能超过125个字符',
|
'image.max' => '图片不能超过125个字符',
|
||||||
'video.max' => '视频不能超过125个字符',
|
'video.max' => '视频不能超过125个字符',
|
||||||
|
|||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
app/common/model/ProductCategoryRecommendBaseModel.php
Normal file
33
app/common/model/ProductCategoryRecommendBaseModel.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\common\model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品分类推荐模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ProductCategoryRecommendBaseModel extends BaseModel
|
||||||
|
{
|
||||||
|
// 表名
|
||||||
|
protected $name = 'product_category_recommend';
|
||||||
|
|
||||||
|
// 主键
|
||||||
|
protected $pk = 'id';
|
||||||
|
|
||||||
|
// 字段信息
|
||||||
|
protected $schema = [
|
||||||
|
'id' => 'int',
|
||||||
|
'language_id' => 'int',
|
||||||
|
'category_id' => 'int',
|
||||||
|
'title' => 'string',
|
||||||
|
'image' => 'string',
|
||||||
|
'desc' => 'string',
|
||||||
|
'link' => 'string',
|
||||||
|
'sort' => 'int',
|
||||||
|
'disabled' => 'int',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime',
|
||||||
|
'deleted_at' => 'datetime'
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -17,22 +17,24 @@ class SysBannerItemBaseModel extends BaseModel
|
|||||||
|
|
||||||
// 字段信息
|
// 字段信息
|
||||||
protected $schema = [
|
protected $schema = [
|
||||||
'id' => 'int',
|
'id' => 'int',
|
||||||
'banner_id' => 'int',
|
'banner_id' => 'int',
|
||||||
'title' => 'string',
|
'title' => 'string',
|
||||||
'title_txt_color' => 'string',
|
'title_txt_color' => 'string',
|
||||||
'desc' => 'string',
|
'short_title' => 'string',
|
||||||
'desc_txt_color' => 'string',
|
'short_title_txt_color' => 'string',
|
||||||
'type' => 'string',
|
'desc' => 'string',
|
||||||
'image' => 'string',
|
'desc_txt_color' => 'string',
|
||||||
'extra_image' => 'string',
|
'type' => 'string',
|
||||||
'video' => 'string',
|
'image' => 'string',
|
||||||
'link_to' => 'string',
|
'extra_image' => 'string',
|
||||||
'link' => 'string',
|
'video' => 'string',
|
||||||
'sort' => 'int',
|
'link_to' => 'string',
|
||||||
'status' => 'int',
|
'link' => 'string',
|
||||||
'created_at' => 'datetime',
|
'sort' => 'int',
|
||||||
'updated_at' => 'datetime',
|
'status' => 'int',
|
||||||
'deleted_at' => 'datetime'
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime',
|
||||||
|
'deleted_at' => 'datetime'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
32
app/common/model/SysMallStoreEntranceBaseModel.php
Normal file
32
app/common/model/SysMallStoreEntranceBaseModel.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\common\model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统商城店铺入口模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysMallStoreEntranceBaseModel extends BaseModel
|
||||||
|
{
|
||||||
|
// 表名
|
||||||
|
protected $name = 'sys_mall_store_entrance';
|
||||||
|
|
||||||
|
// 主键
|
||||||
|
protected $pk = 'id';
|
||||||
|
|
||||||
|
// 字段信息
|
||||||
|
protected $schema = [
|
||||||
|
'id' => 'int',
|
||||||
|
'language_id' => 'int',
|
||||||
|
'name' => 'string',
|
||||||
|
'image' => 'string',
|
||||||
|
'hover_image' => 'string',
|
||||||
|
'link' => 'string',
|
||||||
|
'sort' => 'int',
|
||||||
|
'disabled' => 'int',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime',
|
||||||
|
'deleted_at' => 'datetime',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -21,7 +21,9 @@ class SysNavigationItemBaseModel extends BaseModel
|
|||||||
'nav_id' => 'int',
|
'nav_id' => 'int',
|
||||||
'pid' => 'int',
|
'pid' => 'int',
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
|
'desc' => 'string',
|
||||||
'icon' => 'string',
|
'icon' => 'string',
|
||||||
|
'image' => 'string',
|
||||||
'link_to' => 'string',
|
'link_to' => 'string',
|
||||||
'link' => 'string',
|
'link' => 'string',
|
||||||
'sort' => 'int',
|
'sort' => 'int',
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ class Attachment extends Common
|
|||||||
'size/d' => 12,
|
'size/d' => 12,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 获取附件分类
|
// 获取附件分类
|
||||||
$categorys = AttachmentCategoryModel::field([
|
$categorys = AttachmentCategoryModel::field([
|
||||||
'id',
|
'id',
|
||||||
@@ -61,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());
|
||||||
|
|
||||||
@@ -124,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);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use app\index\model\LanguageModel;
|
|||||||
use app\index\model\ProductCategoryModel;
|
use app\index\model\ProductCategoryModel;
|
||||||
use app\index\model\ProductModel;
|
use app\index\model\ProductModel;
|
||||||
use app\index\model\SysConfigModel;
|
use app\index\model\SysConfigModel;
|
||||||
|
use app\index\model\SysMallStoreEntranceModel;
|
||||||
use app\index\model\SysNavigationItemModel;
|
use app\index\model\SysNavigationItemModel;
|
||||||
use think\facade\Lang;
|
use think\facade\Lang;
|
||||||
use think\facade\View;
|
use think\facade\View;
|
||||||
@@ -38,7 +39,7 @@ abstract class Common extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取产品分类
|
// 获取产品分类
|
||||||
$categorys = $this->getProductCategory($this->lang_id);
|
$categorys = $this->getProductCategory($this->lang_id, true);
|
||||||
// 输出产品分类
|
// 输出产品分类
|
||||||
View::assign('header_categorys', $categorys);
|
View::assign('header_categorys', $categorys);
|
||||||
|
|
||||||
@@ -47,6 +48,9 @@ abstract class Common extends BaseController
|
|||||||
// 输出热销产品
|
// 输出热销产品
|
||||||
View::assign('header_hot_products', $hot_products);
|
View::assign('header_hot_products', $hot_products);
|
||||||
|
|
||||||
|
// 获取商品购买入口
|
||||||
|
View::assign("header_mall_entrance", $this->getMallStoreEntrance($this->lang_id));
|
||||||
|
|
||||||
// 输出顶部导航
|
// 输出顶部导航
|
||||||
View::assign('header_navigation', $this->getNavigation('NAV_67f3701f3e831', $this->lang_id));
|
View::assign('header_navigation', $this->getNavigation('NAV_67f3701f3e831', $this->lang_id));
|
||||||
|
|
||||||
@@ -78,7 +82,7 @@ abstract class Common extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取产品分类
|
// 获取产品分类
|
||||||
protected function getProductCategory($language = 1)
|
protected function getProductCategory($language = 1, $with_recommends = false)
|
||||||
{
|
{
|
||||||
$categorys = ProductCategoryModel::field([
|
$categorys = ProductCategoryModel::field([
|
||||||
'id',
|
'id',
|
||||||
@@ -87,15 +91,48 @@ abstract class Common extends BaseController
|
|||||||
'icon',
|
'icon',
|
||||||
'level'
|
'level'
|
||||||
])
|
])
|
||||||
|
->when($with_recommends, function($query) {
|
||||||
|
$query->with(['recommends' => function($query) {
|
||||||
|
$query->field(['id', 'category_id', 'title', 'image', 'desc', 'link'])->disabled(false)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc']);
|
||||||
|
}]);
|
||||||
|
})
|
||||||
->language($language)
|
->language($language)
|
||||||
->displayed()
|
->displayed()
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
->select();
|
->select()
|
||||||
|
->hidden(["recommends.category_id"]);
|
||||||
if ($categorys->isEmpty()) {
|
if ($categorys->isEmpty()) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_to_tree($categorys->toArray(), 0, 'pid', 1, false);
|
return $this->toTreeAndChunk($categorys->toArray(), 0, 1);
|
||||||
|
}
|
||||||
|
private function toTreeAndChunk(array $categorys, int $pid, int|bool $level): array
|
||||||
|
{
|
||||||
|
$ret = [];
|
||||||
|
foreach ($categorys as $item) {
|
||||||
|
if ($item['pid'] == $pid) {
|
||||||
|
$lv = $level;
|
||||||
|
if ($level !== false) {
|
||||||
|
$item['level'] = $level;
|
||||||
|
$lv = $level + 1;
|
||||||
|
}
|
||||||
|
$children = $this->toTreeAndChunk($categorys, $item['id'], $lv);
|
||||||
|
if (!empty($children)) {
|
||||||
|
if ($lv == 1) {
|
||||||
|
$item['children'] = array_chunk($children, 2);
|
||||||
|
} else if ($lv == 2) {
|
||||||
|
$item['children'] = array_chunk($children, 3);
|
||||||
|
} else {
|
||||||
|
$item['children'] = $children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$ret[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取顶部导航
|
// 获取顶部导航
|
||||||
@@ -164,6 +201,26 @@ abstract class Common extends BaseController
|
|||||||
return $languages;
|
return $languages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取商品购买入口
|
||||||
|
private function getMallStoreEntrance($language = 1)
|
||||||
|
{
|
||||||
|
return SysMallStoreEntranceModel::field([
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'image',
|
||||||
|
'hover_image',
|
||||||
|
'link'
|
||||||
|
])
|
||||||
|
->language($language)
|
||||||
|
->enabled()
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
?->each(function($item) {
|
||||||
|
$item->image = thumb($item->image);
|
||||||
|
return $item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 获取系统联系方式配置
|
// 获取系统联系方式配置
|
||||||
protected function getSysConfig($language, $group = [])
|
protected function getSysConfig($language, $group = [])
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -267,6 +267,59 @@ class Product extends Common
|
|||||||
return View::fetch('subcategory');
|
return View::fetch('subcategory');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单纯分类页
|
||||||
|
*/
|
||||||
|
public function classify()
|
||||||
|
{
|
||||||
|
$pid = request()->param('id/d', 0);
|
||||||
|
|
||||||
|
// 获取当前选中的父分类
|
||||||
|
$parent = ProductCategoryModel::field(['id', 'name'])->find($pid);
|
||||||
|
View::assign('parent', $parent);
|
||||||
|
|
||||||
|
// 获取分类及产品信息
|
||||||
|
$categorys = ProductCategoryModel::field(['id', 'pid', 'name', 'path', 'level'])
|
||||||
|
->language($this->lang_id)
|
||||||
|
->displayed(true)
|
||||||
|
->children($pid)
|
||||||
|
->order(['pid' => 'asc', 'sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// 组装第三级分类所属产品数据
|
||||||
|
$lv3_id_arr = array_column(array_filter($categorys, fn($item)=> $item['level'] === 3), 'id');
|
||||||
|
$products = ProductModel::field([
|
||||||
|
'id',
|
||||||
|
'category_id',
|
||||||
|
'name',
|
||||||
|
'short_name',
|
||||||
|
'cover_image',
|
||||||
|
'spu'
|
||||||
|
])
|
||||||
|
->byCategory($lv3_id_arr)
|
||||||
|
->language($this->lang_id)
|
||||||
|
->enabled(true)
|
||||||
|
->onSale(true)
|
||||||
|
->onShelves(true)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
$product_groups = [];
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$product_groups[$product['category_id']][] = $product;
|
||||||
|
}
|
||||||
|
foreach ($categorys as $key => $category) {
|
||||||
|
if ($category['level'] < 3) continue;
|
||||||
|
$categorys[$key]['products'] = $product_groups[$category['id']] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$tree = array_to_tree($categorys, $pid);
|
||||||
|
View::assign('categorys', $tree);
|
||||||
|
|
||||||
|
return View::fetch('classify');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 产品搜索
|
* 产品搜索
|
||||||
*/
|
*/
|
||||||
|
|||||||
104
app/index/controller/TopicLaptop.php
Normal file
104
app/index/controller/TopicLaptop.php
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\index\controller;
|
||||||
|
|
||||||
|
use app\index\model\SysBannerModel;
|
||||||
|
use think\facade\View;
|
||||||
|
|
||||||
|
class TopicLaptop extends Common
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 专题 - 笔记本电脑首页
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
|
||||||
|
$banners = SysBannerModel::with([
|
||||||
|
'items' => function ($query) {
|
||||||
|
$query->withoutField(['sort', 'created_at', 'updated_at', 'deleted_at'])
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->enabled(true);
|
||||||
|
}
|
||||||
|
])
|
||||||
|
->atPlatform(request()->from)
|
||||||
|
->uniqueLabel([
|
||||||
|
'BANNER_693a268c8aa5f', // 专题 - 笔记本首页 - 焦点图
|
||||||
|
'BANNER_693a26b1ad252', // 专题 - 笔记本首页 - 性能介绍
|
||||||
|
'BANNER_693a27b767c8c', // 专题 - 笔记本首页 - CPU介绍
|
||||||
|
'BANNER_693a28740b8a7', // 专题 - 笔记本首页 - 显卡介绍
|
||||||
|
'BANNER_693a28aa8412d', // 专题 - 笔记本首页 - 运行内存介绍
|
||||||
|
'BANNER_693a29009fa72', // 专题 - 笔记本首页 - 硬盘介绍
|
||||||
|
'BANNER_693a29263c609', // 专题 - 笔记本首页 - 散热系统介绍
|
||||||
|
'BANNER_693a2959958bc', // 专题 - 笔记本首页 - 行业App运行介绍
|
||||||
|
'BANNER_693a298342b38', // 专题 - 笔记本首页 - 柔光屏介绍
|
||||||
|
'BANNER_693a2ad31fbe8', // 专题 - 笔记本首页 - 色域介绍
|
||||||
|
'BANNER_693a2b0327ac3', // 专题 - 笔记本首页 - 防眩光介绍
|
||||||
|
'BANNER_693a2cc70c762', // 专题 - 笔记本首页 - 外形质感介绍
|
||||||
|
'BANNER_693a2d3113d14', // 专题 - 笔记本首页 - 网卡介绍
|
||||||
|
'BANNER_693a2d53ac247', // 专题 - 笔记本首页 - 电池续航介绍
|
||||||
|
'BANNER_693a2d7f5fa21', // 专题 - 笔记本首页 - 接口介绍
|
||||||
|
'BANNER_693a2f2114eb3', // 专题 - 笔记本首页 - 使用场景焦点图
|
||||||
|
'BANNER_693a2f92baaa3', // 专题 - 笔记本首页 - 摄像头/麦克风/安全介绍
|
||||||
|
'BANNER_693a2fad26f55', // 专题 - 笔记本首页 - 系统预装介绍
|
||||||
|
'BANNER_693a2ff4629bd', // 专题 - 笔记本首页 - 产品检测介绍
|
||||||
|
'BANNER_693a30e9e4572', // 专题 - 笔记本首页 - 网页脚注
|
||||||
|
])
|
||||||
|
->language($this->lang_id)
|
||||||
|
->enabled(true)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
if (!$banners->isEmpty()) {
|
||||||
|
$banners_map = [];
|
||||||
|
foreach ($banners as $banner) {
|
||||||
|
$banners_map[$banner->unique_label] = $banner;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 焦点图轮播图
|
||||||
|
$data['top_focus_images'] = data_get($banners_map, 'BANNER_693a268c8aa5f')?->items->toArray();
|
||||||
|
// 性能介绍
|
||||||
|
$data['perf'] = data_get($banners_map, 'BANNER_693a26b1ad252')?->items->toArray();
|
||||||
|
// CPU介绍
|
||||||
|
$data['cpu'] = data_get($banners_map, 'BANNER_693a27b767c8c')?->items->toArray();
|
||||||
|
// 显卡介绍
|
||||||
|
$data['gpu'] = data_get($banners_map, 'BANNER_693a28740b8a7')?->items->toArray();
|
||||||
|
// 运行内存介绍
|
||||||
|
$data['ram'] = data_get($banners_map, 'BANNER_693a28aa8412d')?->items->first()?->toArray();
|
||||||
|
// 硬盘介绍
|
||||||
|
$data['hard_drive'] = data_get($banners_map, 'BANNER_693a29009fa72')?->items->toArray();
|
||||||
|
// 散热系统介绍
|
||||||
|
$data['cooling_system'] = data_get($banners_map, 'BANNER_693a29263c609')?->items->toArray();
|
||||||
|
// 行业App运行介绍
|
||||||
|
$data['apps'] = data_get($banners_map, 'BANNER_693a2959958bc')?->items->first()?->toArray();
|
||||||
|
// 柔光屏介绍
|
||||||
|
$data['screen_soft_light'] = data_get($banners_map, 'BANNER_693a298342b38')?->items->toArray();
|
||||||
|
// 色域介绍
|
||||||
|
$data['screen_color_gamut'] = data_get($banners_map, 'BANNER_693a2ad31fbe8')?->items->toArray();
|
||||||
|
// 防眩光介绍
|
||||||
|
$data['screen_anti_glare'] = data_get($banners_map, 'BANNER_693a2b0327ac3')?->items->toArray();
|
||||||
|
// 外形质感介绍
|
||||||
|
$data['exterior_texture'] = data_get($banners_map, 'BANNER_693a2cc70c762')?->items->toArray();
|
||||||
|
// 网卡介绍
|
||||||
|
$data['network_card'] = data_get($banners_map, 'BANNER_693a2d3113d14')?->items->toArray();
|
||||||
|
// 电池续航介绍
|
||||||
|
$data['battery_life'] = data_get($banners_map, 'BANNER_693a2d53ac247')?->items->toArray();
|
||||||
|
// 接口介绍
|
||||||
|
$data['interface'] = data_get($banners_map, 'BANNER_693a2d7f5fa21')?->items->toArray();
|
||||||
|
// 使用场景焦点图
|
||||||
|
$data['scene_focus_images'] = data_get($banners_map, 'BANNER_693a2f2114eb3')?->items->toArray();
|
||||||
|
// 摄像头/麦克风/安全介绍
|
||||||
|
$data['camare_microphone_security'] = data_get($banners_map, 'BANNER_693a2f92baaa3')?->items->toArray();
|
||||||
|
// 系统预装介绍
|
||||||
|
$data['unified_preinstall'] = data_get($banners_map, 'BANNER_693a2fad26f55')?->items->first()?->toArray();
|
||||||
|
// 产品检测介绍
|
||||||
|
$data['product_testing'] = data_get($banners_map, 'BANNER_693a2ff4629bd')?->items->toArray();
|
||||||
|
// 网页脚注
|
||||||
|
$data['webpage_footnotes'] = data_get($banners_map, 'BANNER_693a30e9e4572')?->items->first()?->toArray();
|
||||||
|
}
|
||||||
|
View::assign('data', $data);
|
||||||
|
|
||||||
|
return View::fetch('index');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -192,6 +192,8 @@ class TopicNas extends Common
|
|||||||
{
|
{
|
||||||
// 获取文章分类及文章数据
|
// 获取文章分类及文章数据
|
||||||
$parent = ArticleCategoryModel::uniqueLabel('CATEGORY_681182e0a4529')->language($this->lang_id)->value('id');
|
$parent = ArticleCategoryModel::uniqueLabel('CATEGORY_681182e0a4529')->language($this->lang_id)->value('id');
|
||||||
|
$parent_two = ArticleCategoryModel::parent($parent)->language($this->lang_id)->column('id');//二级分类id
|
||||||
|
array_push($parent_two,$parent);
|
||||||
$article_categorys = ArticleCategoryModel::with(['article' => function($query) {
|
$article_categorys = ArticleCategoryModel::with(['article' => function($query) {
|
||||||
$query->field(['id', 'title', 'category_id'])
|
$query->field(['id', 'title', 'category_id'])
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
@@ -199,15 +201,48 @@ class TopicNas extends Common
|
|||||||
}])
|
}])
|
||||||
->field([
|
->field([
|
||||||
'id',
|
'id',
|
||||||
|
'pid',
|
||||||
'name',
|
'name',
|
||||||
'icon'
|
'icon'
|
||||||
])
|
])
|
||||||
->language($this->lang_id)
|
->language($this->lang_id)
|
||||||
->parent($parent)
|
// ->parent($parent)
|
||||||
|
->parentChild($parent_two)
|
||||||
->isShow(true)
|
->isShow(true)
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
->select();
|
->select();
|
||||||
View::assign('article_categorys', $article_categorys);
|
//查询三级分类
|
||||||
|
$article_categorys_new = [];
|
||||||
|
$article_categorys_two = [];
|
||||||
|
// dump($article_categorys->toArray());exit;
|
||||||
|
if (!$article_categorys->isEmpty()) {
|
||||||
|
foreach ($article_categorys->toArray() as $kk=>$vv) {
|
||||||
|
if ( $parent == $vv['pid'] ) {
|
||||||
|
array_push($article_categorys_new,$vv);
|
||||||
|
} else {
|
||||||
|
$article_categorys_two[$vv['pid']][] = $vv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !empty($article_categorys_two) ) {
|
||||||
|
foreach ($article_categorys_new as &$vvv) {
|
||||||
|
$articles = $vvv['article'];
|
||||||
|
if ( isset($article_categorys_two[$vvv['id']]) ) {
|
||||||
|
foreach ($article_categorys_two[$vvv['id']] as $v) {
|
||||||
|
foreach ($v['article'] as $av) {
|
||||||
|
if ( count($articles) < 3 ) {
|
||||||
|
array_push($articles,$av);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$vvv['article'] = $articles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
View::assign('article_categorys', $article_categorys_new);
|
||||||
|
// View::assign('article_categorys', $article_categorys);
|
||||||
|
|
||||||
$contacts = [];
|
$contacts = [];
|
||||||
// 获取banner数据
|
// 获取banner数据
|
||||||
@@ -246,20 +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'])
|
->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');
|
||||||
}
|
}
|
||||||
@@ -317,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
90
app/index/controller/TopicPowerProdline.php
Normal file
90
app/index/controller/TopicPowerProdline.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\index\controller;
|
||||||
|
|
||||||
|
use app\index\model\SysBannerModel;
|
||||||
|
use think\facade\View;
|
||||||
|
use think\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 专题 - 电力品线控制器
|
||||||
|
*/
|
||||||
|
class TopicPowerProdline extends Common
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 专题 - 电力品线首页
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$banners = SysBannerModel::with([
|
||||||
|
'items' => function ($query) {
|
||||||
|
$query->withoutField(['sort', 'created_at', 'updated_at', 'deleted_at'])
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->enabled(true);
|
||||||
|
}
|
||||||
|
])
|
||||||
|
->atPlatform(request()->from)
|
||||||
|
->uniqueLabel([
|
||||||
|
'BANNER_691e729f2428d',
|
||||||
|
'BANNER_691e732e4ad69',
|
||||||
|
'BANNER_691e752d2bbe2',
|
||||||
|
'BANNER_691e75561c4d3',
|
||||||
|
'BANNER_691e75ec9391c',
|
||||||
|
'BANNER_691e7616545bf',
|
||||||
|
'BANNER_691e763fc08f4',
|
||||||
|
'BANNER_691e765a27eba',
|
||||||
|
'BANNER_691e76b6af393',
|
||||||
|
])
|
||||||
|
->language($this->lang_id)
|
||||||
|
->enabled(true)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
if (!$banners->isEmpty()) {
|
||||||
|
$banners_map = [];
|
||||||
|
foreach ($banners as $banner) {
|
||||||
|
$banners_map[$banner->unique_label] = $banner;
|
||||||
|
}
|
||||||
|
// 焦点轮播图
|
||||||
|
$focus_image = data_get($banners_map, 'BANNER_691e729f2428d')?->items->toArray();
|
||||||
|
if (!empty($focus_image)) $data['focus_image'] = $focus_image;
|
||||||
|
|
||||||
|
// 分类
|
||||||
|
$category = data_get($banners_map, 'BANNER_691e732e4ad69')?->items->toArray();
|
||||||
|
if (!empty($category)) $data['category'] = $category;
|
||||||
|
|
||||||
|
// 为什么选择奥睿科相关数据
|
||||||
|
$why_choose = data_get($banners_map, 'BANNER_691e752d2bbe2')?->items->toArray();
|
||||||
|
if (!empty($why_choose)) $data['why_choose'] = $why_choose;
|
||||||
|
|
||||||
|
// 差旅充
|
||||||
|
$travel_charger = data_get($banners_map, 'BANNER_691e75561c4d3')?->items->toArray();
|
||||||
|
if (!empty($travel_charger)) $data['travel_charger'] = $travel_charger;
|
||||||
|
|
||||||
|
// 家居充
|
||||||
|
$home_charger = data_get($banners_map, 'BANNER_691e75ec9391c')?->items->toArray();
|
||||||
|
if (!empty($home_charger)) $data['home_charger'] = $home_charger;
|
||||||
|
|
||||||
|
// 桌面充
|
||||||
|
$desktop_charger = data_get($banners_map, 'BANNER_691e7616545bf')?->items->toArray();
|
||||||
|
if (!empty($desktop_charger)) $data['desktop_charger'] = $desktop_charger;
|
||||||
|
|
||||||
|
// 墙充
|
||||||
|
$wall_charger = data_get($banners_map, 'BANNER_691e763fc08f4')?->items->toArray();
|
||||||
|
if (!empty($wall_charger)) $data['wall_charger'] = $wall_charger;
|
||||||
|
|
||||||
|
// 转换器
|
||||||
|
$converter = data_get($banners_map, 'BANNER_691e765a27eba')?->items->toArray();
|
||||||
|
if (!empty($converter)) $data['converter'] = $converter;
|
||||||
|
|
||||||
|
// 底部介绍
|
||||||
|
$footer_info = data_get($banners_map, 'BANNER_691e76b6af393')?->items->toArray();
|
||||||
|
if (!empty($footer_info)) $data['footer_info'] = $footer_info;
|
||||||
|
}
|
||||||
|
View::assign('data', $data);
|
||||||
|
|
||||||
|
return View::fetch('index');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,9 @@ return [
|
|||||||
'产品列表' => 'Products',
|
'产品列表' => 'Products',
|
||||||
'搜索' => 'Search',
|
'搜索' => 'Search',
|
||||||
'搜索历史' => 'Search History',
|
'搜索历史' => 'Search History',
|
||||||
|
'请输入搜索关键词' => 'Please enter a search keyword',
|
||||||
|
'搜索记录' => 'Search History',
|
||||||
|
'清空' => 'Clear',
|
||||||
'请择地区' => 'SELECT A REGION',
|
'请择地区' => 'SELECT A REGION',
|
||||||
'产品' => 'Product',
|
'产品' => 'Product',
|
||||||
'联系方式' => 'Contact',
|
'联系方式' => 'Contact',
|
||||||
@@ -219,4 +222,21 @@ return [
|
|||||||
'联系我们' => 'Contact US',
|
'联系我们' => 'Contact US',
|
||||||
'目录' => 'Content'
|
'目录' => 'Content'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// 笔记本专题 - 首页
|
||||||
|
'topiclaptop/index' => [
|
||||||
|
'CineBench R23 多核跑分' => 'Outperforms Ryzen 5 & Intel i5',
|
||||||
|
'*此跑分为ORICO实验室测定所得,请以实际使用为准' => '*Data measured by ORICO Lab. Actual performance may vary.',
|
||||||
|
'3DMARK Time Spy显卡得分' => 'Handles Office & Gaming with Ease',
|
||||||
|
'肯辛通锁孔' => 'Kensington <br/> Lock Slot',
|
||||||
|
'千兆网口' => 'Gigabit <br/> Ethernet',
|
||||||
|
'USB-A<br/>(5Gbps)' => 'USB-A <br/> (5Gbps)',
|
||||||
|
'3.5mm<br/>耳麦合一' => '3.5mm <br/> Combo Audio',
|
||||||
|
'TF口3.0' => 'TF 3.0 <br/> Card Slot',
|
||||||
|
'全功能<br/>USB-C' => 'All-in-One <br/> USB-C',
|
||||||
|
"接口大满贯" => "Full-Featured Ports",
|
||||||
|
"酷睿i5-12450H" => "Core i5-12450H",
|
||||||
|
"锐龙9 6900HX" => "Ryzen9 6900HX",
|
||||||
|
"标配多种接口,会议室连接电脑、</br>U盘传输文件、TF卡读取等,全都轻松搞定" => "Versatile Ports for Easy Connectivity. Effortlessly</br> link to projectors, U disks, TF cards, and more.",
|
||||||
|
],
|
||||||
];
|
];
|
||||||
@@ -5,10 +5,17 @@ return [
|
|||||||
'产品列表' => 'Products',
|
'产品列表' => 'Products',
|
||||||
'店铺' => 'Store',
|
'店铺' => 'Store',
|
||||||
'搜索记录' => 'Search History',
|
'搜索记录' => 'Search History',
|
||||||
'热销产品' => 'Popular Products',
|
|
||||||
'产品' => 'Product',
|
'产品' => 'Product',
|
||||||
'联系我们' => 'Contact',
|
'联系我们' => 'Contact',
|
||||||
|
|
||||||
|
// 新导航栏 - 2023-03-31
|
||||||
|
'搜索' => 'Search',
|
||||||
|
'搜索产品、分类...' => 'Search products and categories...',
|
||||||
|
'最近搜索' => 'Recent Searches',
|
||||||
|
'清空' => 'Clear',
|
||||||
|
'热销产品' => 'Popular Products',
|
||||||
|
'购买' => 'Buy',
|
||||||
|
|
||||||
// 返回文本
|
// 返回文本
|
||||||
'提交成功' => 'success',
|
'提交成功' => 'success',
|
||||||
'提交失败' => 'fail',
|
'提交失败' => 'fail',
|
||||||
@@ -224,4 +231,21 @@ return [
|
|||||||
'联系我们' => 'Contact US',
|
'联系我们' => 'Contact US',
|
||||||
'目录' => 'Content'
|
'目录' => 'Content'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// 笔记本专题 - 首页
|
||||||
|
'topiclaptop/index' => [
|
||||||
|
'CineBench R23 多核跑分' => 'Outperforms Ryzen 5 & Intel i5',
|
||||||
|
'*此跑分为ORICO实验室测定所得,请以实际使用为准' => '*Data measured by ORICO Lab. Actual performance may vary.',
|
||||||
|
'3DMARK Time Spy显卡得分' => 'Handles Office & Gaming with Ease',
|
||||||
|
'肯辛通锁孔' => 'Kensington <br/> Lock Slot',
|
||||||
|
'千兆网口' => 'Gigabit <br/> Ethernet',
|
||||||
|
'USB-A<br/>(5Gbps)' => 'USB-A <br/> (5Gbps)',
|
||||||
|
'3.5mm<br/>耳麦合一' => '3.5mm <br/> Combo Audio',
|
||||||
|
'TF口3.0' => 'TF 3.0 <br/> Card Slot',
|
||||||
|
'全功能<br/>USB-C' => 'All-in-One <br/> USB-C',
|
||||||
|
"接口大满贯" => "Full-Featured Ports",
|
||||||
|
"酷睿i5-12450H" => "Core i5-12450H",
|
||||||
|
"锐龙9 6900HX" => "Ryzen9 6900HX",
|
||||||
|
"标配多种接口,会议室连接电脑、U盘传输文件、TF卡读取等,全都轻松搞定" => "Versatile Ports for Easy Connectivity. Effortlessly link to pro",
|
||||||
|
],
|
||||||
];
|
];
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ class ProductCategoryModel extends ProductCategoryBaseModel
|
|||||||
// 软件删除时间字段
|
// 软件删除时间字段
|
||||||
protected $deleteTime = 'deleted_at';
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联产品推荐
|
||||||
|
public function recommends()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ProductCategoryRecommendModel::class, 'category_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
// 所属语言范围查询
|
// 所属语言范围查询
|
||||||
public function scopeLanguage($query, $language)
|
public function scopeLanguage($query, $language)
|
||||||
{
|
{
|
||||||
|
|||||||
30
app/index/model/ProductCategoryRecommendModel.php
Normal file
30
app/index/model/ProductCategoryRecommendModel.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\index\model;
|
||||||
|
|
||||||
|
use app\common\model\ProductCategoryRecommendBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品分类推荐模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ProductCategoryRecommendModel extends ProductCategoryRecommendBaseModel
|
||||||
|
{
|
||||||
|
// 启用软件删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软件删除时间字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 所属语言范围查询
|
||||||
|
public function scopeLanguage($query, $language)
|
||||||
|
{
|
||||||
|
$query->where($this->getTable() . '.language_id', '=', $language);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeDisabled($query, $disabled = true)
|
||||||
|
{
|
||||||
|
$query->where($this->getTable() . '.disabled', '=', (int)$disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
43
app/index/model/SysMallStoreEntranceModel.php
Normal file
43
app/index/model/SysMallStoreEntranceModel.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\index\model;
|
||||||
|
|
||||||
|
use app\common\model\SysMallStoreEntranceBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统商城店铺入口模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysMallStoreEntranceModel extends SysMallStoreEntranceBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联语言
|
||||||
|
public function language()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(\app\index\model\LanguageModel::class, 'language_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所属语言范围查询
|
||||||
|
public function scopeLanguage($query, $language)
|
||||||
|
{
|
||||||
|
$query->where($this->getTable() . '.language_id', '=', $language);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询启用状态
|
||||||
|
public function scopeEnabled($query)
|
||||||
|
{
|
||||||
|
$query->where('disabled', '=', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询禁用状态
|
||||||
|
public function scopeDisabled($query)
|
||||||
|
{
|
||||||
|
$query->where('disabled', '=', 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,8 @@ Route::group('product', function () {
|
|||||||
Route::get('category/:id', 'Product/category');
|
Route::get('category/:id', 'Product/category');
|
||||||
// 产品分类 - 查看子类
|
// 产品分类 - 查看子类
|
||||||
Route::get('subcategory/:id', 'Product/subcategory');
|
Route::get('subcategory/:id', 'Product/subcategory');
|
||||||
|
// 单纯分类页
|
||||||
|
Route::get('classify/:id', 'Product/classify');
|
||||||
// 产品详情页
|
// 产品详情页
|
||||||
Route::get('detail/:id', 'Product/detail');
|
Route::get('detail/:id', 'Product/detail');
|
||||||
// 产品询盘
|
// 产品询盘
|
||||||
@@ -105,6 +107,18 @@ Route::group('topic', function () {
|
|||||||
// 专题-Nas软件下载页
|
// 专题-Nas软件下载页
|
||||||
Route::get('download', 'TopicNas/download');
|
Route::get('download', 'TopicNas/download');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 专题 - 电力品线
|
||||||
|
Route::group('power_prodline', function() {
|
||||||
|
// 专题 - 电力品线首页
|
||||||
|
Route::get('index', 'TopicPowerProdline/index');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 专题 - 笔记本电脑
|
||||||
|
Route::group('laptop', function() {
|
||||||
|
// 专题 - 笔记本电脑首页
|
||||||
|
Route::get('index', 'TopicLaptop/index');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 数据迁移
|
// 数据迁移
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<!-- banner-->
|
<!-- banner-->
|
||||||
<div class="oidx-banner">
|
<div class="oidx-banner">
|
||||||
{notempty name="focus_images"}
|
{notempty name="focus_images"}
|
||||||
<div class="swiper-container bannerswiper">
|
<div class="swiper-container bannerswiper" style="background: #fff;">
|
||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper">
|
||||||
{volist name="focus_images" id="fi"}
|
{volist name="focus_images" id="fi"}
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
|
|||||||
225
app/index/view/mobile/product/classify.html
Normal file
225
app/index/view/mobile/product/classify.html
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
{extend name="public/base" /}
|
||||||
|
|
||||||
|
{block name="style"}
|
||||||
|
<link rel="stylesheet" href="__CSS__/category.css">
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function (doc, win) {
|
||||||
|
var docEl = doc.documentElement;
|
||||||
|
var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
|
||||||
|
|
||||||
|
function setRootFontSize() {
|
||||||
|
var clientWidth = docEl.clientWidth;
|
||||||
|
if (!clientWidth) return;
|
||||||
|
var fontSize = clientWidth / 8.04; // 750px/7.5=100px,375px/7.5=50px
|
||||||
|
// 直接修改内联样式,优先级最高
|
||||||
|
docEl.setAttribute('style', 'font-size: ' + fontSize + 'px !important;');
|
||||||
|
}
|
||||||
|
|
||||||
|
setRootFontSize();
|
||||||
|
win.addEventListener(resizeEvt, setRootFontSize);
|
||||||
|
doc.addEventListener('DOMContentLoaded', setRootFontSize);
|
||||||
|
})(document, window);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block name="main"}
|
||||||
|
<!-- 顶部返回栏(已完全按图纸修改) -->
|
||||||
|
<div class="top-box">
|
||||||
|
<div class="top-bar">
|
||||||
|
<div class="back">
|
||||||
|
<image src="__IMAGES__/left.png"></image>
|
||||||
|
</div>
|
||||||
|
<div class="title">{$parent.name|default=''}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="main">
|
||||||
|
<!-- 左侧导航 -->
|
||||||
|
{if condition="!empty($categorys)"}
|
||||||
|
<ul class="sidebar">
|
||||||
|
{volist name="categorys" id="category"}
|
||||||
|
<li class="nav-item {eq name='$key' value='0'}active{/eq}" data-tab="tab{$category.id}">{$category.name}</li>
|
||||||
|
{/volist}
|
||||||
|
<li style="background: #fff;" class="li-bottom"></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- 右侧分区内容 -->
|
||||||
|
<div class="right-content">
|
||||||
|
{volist name="categorys" id="category"}
|
||||||
|
<div class="tab-pane {eq name='$key' value='0'}active{/eq}" id="tab{$category.id}">
|
||||||
|
{if condition="!empty($category.children)"}
|
||||||
|
{volist name="$category.children" id="child"}
|
||||||
|
<section class="sec-box">
|
||||||
|
<div class="sec-header">
|
||||||
|
<div class="sec-title">{$child.name}</div>
|
||||||
|
<a class="sec-arrow" href="{:url('product/subcategory', ['id' => $child.id])}" target="_self">
|
||||||
|
<img src="__IMAGES__/y.png" alt="">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{if condition="!empty($child.products)"}
|
||||||
|
<div class="scroll-box">
|
||||||
|
{volist name="$child.products" id="pro"}
|
||||||
|
<a class="card" href="{:url('product/detail', ['id' => $pro.id])}" style="background: #fff;">
|
||||||
|
<div class="card-img">
|
||||||
|
<img src="{$pro.cover_image}" alt="">
|
||||||
|
</div>
|
||||||
|
<div class="card-info">
|
||||||
|
<div class="card-name">{$pro.name}</div>
|
||||||
|
<div class="card-model">{$pro.spu}</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</section>
|
||||||
|
{/volist}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block name="script"}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 点击右侧箭头滚动
|
||||||
|
function scrollNext (el)
|
||||||
|
{
|
||||||
|
const box = el.closest('section')?.querySelector('.scroll-box')
|
||||||
|
|| el.parentElement.nextElementSibling
|
||||||
|
if (box) box.scrollBy({ left: 150, behavior: 'smooth' })
|
||||||
|
}
|
||||||
|
const back = document.querySelector('.back')
|
||||||
|
// 左侧Tab切换
|
||||||
|
const navItems = document.querySelectorAll('.nav-item')
|
||||||
|
const tabPanes = document.querySelectorAll('.tab-pane')
|
||||||
|
|
||||||
|
navItems.forEach(item =>
|
||||||
|
{
|
||||||
|
item.addEventListener('click', () =>
|
||||||
|
{
|
||||||
|
// 切换左侧激活状态
|
||||||
|
navItems.forEach(i => i.classList.remove('active'))
|
||||||
|
item.classList.add('active')
|
||||||
|
// 切换右侧内容
|
||||||
|
const target = item.dataset.tab
|
||||||
|
tabPanes.forEach(p => p.classList.remove('active'))
|
||||||
|
document.getElementById(target)?.classList.add('active')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
back.addEventListener('click',()=>{
|
||||||
|
window.location.href = document.referrer;
|
||||||
|
})
|
||||||
|
// 更新侧边栏相邻元素的圆角
|
||||||
|
function updateSidebarAdjacentRadius() {
|
||||||
|
const sidebarItems = document.querySelectorAll('.sidebar li');
|
||||||
|
|
||||||
|
// 先移除所有相邻类名
|
||||||
|
sidebarItems.forEach(item => {
|
||||||
|
item.classList.remove('active-prev', 'active-next');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 找到当前激活的项
|
||||||
|
let activeIndex = -1;
|
||||||
|
sidebarItems.forEach((item, index) => {
|
||||||
|
if (item.classList.contains('active')) {
|
||||||
|
activeIndex = index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加上一个和下一个的类名(使用requestAnimationFrame确保DOM更新)
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (activeIndex > 0) {
|
||||||
|
sidebarItems[activeIndex - 1].classList.add('active-prev');
|
||||||
|
}
|
||||||
|
if (activeIndex < sidebarItems.length - 1) {
|
||||||
|
sidebarItems[activeIndex + 1].classList.add('active-next');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定点击事件
|
||||||
|
document.querySelectorAll('.sidebar li').forEach(item => {
|
||||||
|
item.addEventListener('click', function() {
|
||||||
|
// 移除所有active
|
||||||
|
document.querySelectorAll('.sidebar li').forEach(li => {
|
||||||
|
li.classList.remove('active');
|
||||||
|
});
|
||||||
|
// 添加active
|
||||||
|
this.classList.add('active');
|
||||||
|
// 更新相邻圆角
|
||||||
|
updateSidebarAdjacentRadius();
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面初始化时调用
|
||||||
|
if (document.querySelector('.sidebar li.active')) {
|
||||||
|
updateSidebarAdjacentRadius();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 动态计算 li-bottom 的高度
|
||||||
|
function setLiBottomHeight() {
|
||||||
|
const sidebar = document.querySelector('.sidebar');
|
||||||
|
const liBottom = document.querySelector('.sidebar .li-bottom');
|
||||||
|
const sidebarItems = document.querySelectorAll('.sidebar li:not(.li-bottom)');
|
||||||
|
|
||||||
|
if (!sidebar || !liBottom || sidebarItems.length === 0) return;
|
||||||
|
|
||||||
|
// 计算所有正常li的总高度
|
||||||
|
let totalHeight = 0;
|
||||||
|
sidebarItems.forEach(item => {
|
||||||
|
totalHeight += item.offsetHeight;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取sidebar的高度
|
||||||
|
const sidebarHeight = sidebar.offsetHeight;
|
||||||
|
|
||||||
|
// 计算剩余高度
|
||||||
|
const remainingHeight = sidebarHeight - totalHeight;
|
||||||
|
|
||||||
|
// 赋值给 li-bottom
|
||||||
|
if (remainingHeight > 0) {
|
||||||
|
liBottom.style.height = remainingHeight + 'px';
|
||||||
|
} else {
|
||||||
|
liBottom.style.height = '0px';
|
||||||
|
liBottom.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面加载时执行
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
setLiBottomHeight();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 窗口大小改变时重新计算
|
||||||
|
window.addEventListener('resize', function() {
|
||||||
|
console.log('切换了吗')
|
||||||
|
setLiBottomHeight();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果侧边栏内容有动态变化,使用 MutationObserver 监听
|
||||||
|
const observer = new MutationObserver(function() {
|
||||||
|
setLiBottomHeight();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听侧边栏变化
|
||||||
|
const sidebar = document.querySelector('.sidebar');
|
||||||
|
if (sidebar) {
|
||||||
|
observer.observe(sidebar, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
attributes: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{/block}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -1,161 +1,662 @@
|
|||||||
<header class="oircoEgapp-head">
|
<link rel="stylesheet" href="__CSS__/new_header.css">
|
||||||
<div class="headtop">
|
<header>
|
||||||
<a href="/"><img src="__IMAGES__/logo.png" class="headerlogimg" /></a>
|
<div class="mobile-header-box">
|
||||||
<div class="action-r">
|
<div class="mobile-header-left">
|
||||||
<div class="right img-responsive cursor_p">
|
<img src="__IMAGES__/header/nav.png" class="nav-img">
|
||||||
<span class="icon-category cursor_p top-menu-toggle"><i class="icon-menu-svg"></i></span>
|
<img src="__IMAGES__/header/x.png" class="nav-img1">
|
||||||
<span class="icon-keyword cursor_p top-search-toggle"><i class="icon-search-svg"></i></span>
|
<a href="/" target="_self" style="display: flex; justify-content: center;">
|
||||||
<span class="mask-up cursor_p top-country-toggle"><i class="icon-lag-svg"></i></span>
|
<img src="__IMAGES__/logo.png" class="nav-log">
|
||||||
</div>
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="mobile-header-right">
|
||||||
|
<img src="__IMAGES__/header/search.png" class="nav-search">
|
||||||
|
<img src="__IMAGES__/header/lang.png" class="nav-lang">
|
||||||
|
<img src="__IMAGES__/header/card.png" class="nav-card">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 顶部菜单-->
|
|
||||||
<div class="top-menu">
|
<div class="nav-dropdown-menu" style="height: 100vh; overflow-y: scroll;-webkit-overflow-scrolling: touch;padding-bottom:9rem;">
|
||||||
<div class="it-ct">
|
<!-- 产品列表 - 有子菜单 -->
|
||||||
<div class="it-1"><a href="/">{:lang_i18n('首页')}</a></div>
|
<div class="menu-item has-child">
|
||||||
</div>
|
<div class="menu-item-box">
|
||||||
<div class="it-ct">
|
<span>{:lang_i18n('产品列表')}</span>
|
||||||
<div class="it-1">
|
<img src="__IMAGES__/header/b.png" class="menu-item-img">
|
||||||
<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>
|
||||||
|
{if condition="!empty($header_categorys)"}
|
||||||
|
<div class="sub-menu" style="overflow-y: auto;">
|
||||||
|
{volist name="header_categorys" id="vo" key="idx"}
|
||||||
|
<div class="sub-item"><a href="{:url('product/classify', ['id' => $vo.id])}" target="_self">{$vo.name}</a></div>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{notempty name="header_navigation"}
|
|
||||||
|
{if condition="!empty($header_navigation)"}
|
||||||
{volist name="header_navigation" id="nav"}
|
{volist name="header_navigation" id="nav"}
|
||||||
<div class="it-ct">
|
{empty name='nav.children'}
|
||||||
<div class="it-1">
|
<div class="menu-item no-child" data-link="{$nav.link}">
|
||||||
{empty name="nav.children"}
|
{else/}
|
||||||
<a href="{$nav.link}">{$nav.name}</a>
|
<div class="menu-item has-child" data-link="{$nav.link}">
|
||||||
{else/}
|
{/empty}
|
||||||
<div class="it-1-more">{$nav.name}<i class="icon-arrow"></i></div>
|
<div class="menu-item-box">
|
||||||
{volist name="nav.children" id="ch"}
|
<span>{$nav.name}</span>
|
||||||
<div class="it-1-2"><a href="{$ch.link}">{$ch.name}</a></div>
|
<img src="__IMAGES__/header/b.png" class="menu-item-img">
|
||||||
{/volist}
|
|
||||||
{/empty}
|
|
||||||
</div>
|
</div>
|
||||||
|
{if condition="!empty($nav.children)"}
|
||||||
|
<div class="sub-menu" style="border: none;" >
|
||||||
|
{volist name="nav.children" id="child"}
|
||||||
|
<div class="sub-item no-padding ">
|
||||||
|
<a href="{$child.link}" target="{$child.blank==1?'_blank':'_self'}" class="sub-item-card">
|
||||||
|
<img src="{$child.image}" alt="" class="sub-item-card-img">
|
||||||
|
<div class="sub-item-card-title">{$child.name}</div>
|
||||||
|
<div class="sub-item-card-name">{$child.desc}</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/volist}
|
{/volist}
|
||||||
{/notempty}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<!-- 顶部搜索-->
|
|
||||||
<div class="top-search">
|
<!-- ====================== 购物车弹窗 ====================== -->
|
||||||
<div class="marsk-container">
|
<div class="modal-overlay" id="cartModal">
|
||||||
<div class="popup-quick">
|
<div class="modal-content">
|
||||||
<div class="ac-close float_r "><img src="__IMAGES__/close.png"></div>
|
<img src="__IMAGES__/header/x.png" class="modal-close">
|
||||||
<div class="search-in">
|
{if condition="!empty($header_mall_entrance)"}
|
||||||
<form action="{:url('product/search')}" method="get">
|
<div class="modal-items-list">
|
||||||
<input type="text" name="keywords" placeholder="{:lang_i18n('产品')} USB 2.0...">
|
{volist name="header_mall_entrance" id="ma"}
|
||||||
<button type="submit" id="search-btnput" class="search-button">{:lang_i18n('搜索')}</button>
|
{if condition="!empty($ma.link)"}
|
||||||
</form>
|
<a class="modal-item" href="{$ma.link}" target="_self">
|
||||||
<div class="title-text">
|
<img src="{$ma.image}" alt="" class="modal-item-img">
|
||||||
<p><a href="#">{:lang_i18n('搜索历史')}</a></p>
|
<div class="modal-item-title">{$ma.name}</div>
|
||||||
<div id="history"></div>
|
</a>
|
||||||
</div>
|
{else/}
|
||||||
|
<!--悬浮图-->
|
||||||
|
<div class="modal-item" data-link="{$ma.link}" style="cursor: pointer;">
|
||||||
|
<img src="{$ma.image}" alt="" class="modal-item-img">
|
||||||
|
<div class="modal-item-title">{$ma.name}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal-item" style="display:none">
|
||||||
|
<img src="{$ma.hover_image}" alt="" class="modal-item-img">
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ====================== 语言弹窗 ====================== -->
|
||||||
|
<div class="modal-overlay" id="langModal">
|
||||||
|
<div class="lang-modal-content">
|
||||||
|
<img src="__IMAGES__/header/x.png" class="modal-close">
|
||||||
|
<div class="lang-items-list">
|
||||||
|
{volist name="header_languages" id="la"}
|
||||||
|
<a class="lang-item" href="{$la.lang_url}" target="_self">
|
||||||
|
<img src="{$la.lang_icon}" />
|
||||||
|
<div>{$la.country_en_name} - {$la.lang_en_name}</div>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 顶部国家选择-->
|
|
||||||
<div class="top-country">
|
<!-- ====================== 搜索弹窗 ====================== -->
|
||||||
<div class="mask"></div>
|
<div class="modal-overlay" id="searchModal">
|
||||||
<div class="action-sheet">
|
<div class="search-modal-content">
|
||||||
<div class="menu-title">
|
<img src="__IMAGES__/header/x.png" class="modal-close">
|
||||||
<div class="menu-name">{:lang_i18n('请择地区')}</div>
|
<div class="search-input-box">
|
||||||
<div class="close-icon">
|
<input type="text" placeholder="{:lang_i18n('请输入搜索关键词')}" id="searchInput">
|
||||||
<img src="__IMAGES__/close.png">
|
|
||||||
|
<div class="search-clear-box">
|
||||||
|
<img src="__IMAGES__/header/x.png" alt="{:lang_i18n('清除')}" class="search-clear-btn" id="searchClearBtn" style="display: none;">
|
||||||
|
</div>
|
||||||
|
<!-- <span style="width: 1px; color:#d9d9d9;margin: 0 10px;">|</span> -->
|
||||||
|
<div class="search-submit-box">
|
||||||
|
<img src="__IMAGES__/header/search.png" alt="{:lang_i18n('搜索')}" class="search-submit-icon" id="searchSubmit">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="search-history">
|
||||||
|
<div class="search-history-header">
|
||||||
|
<div class="search-history-title">{:lang_i18n('搜索记录')}</div>
|
||||||
|
<div class="search-history-clear" id="clearAllHistory">{:lang_i18n('清空')}</div>
|
||||||
|
</div>
|
||||||
|
<div class="search-history-list" id="searchHistoryList">
|
||||||
|
<!-- 搜索记录会动态显示在这里 -->
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
</header>
|
</header>
|
||||||
<script type="text/javascript">
|
<script>
|
||||||
$(function() {
|
|
||||||
// 点击顶部菜单
|
|
||||||
$(".top-menu-toggle").click(function() {
|
|
||||||
$(".top-menu").slideToggle(800);
|
|
||||||
})
|
|
||||||
// 点击一级菜单显示二级菜单
|
|
||||||
$(".it-1-more").on("click", function() {
|
|
||||||
$('.it-1-2').hide();
|
|
||||||
$('.icon-arrow').removeClass('rotate');
|
|
||||||
$(this).siblings('.it-1-2').slideToggle(800);
|
|
||||||
$(this).find('.icon-arrow').addClass('rotate');
|
|
||||||
});
|
|
||||||
//点击搜索
|
|
||||||
$('.top-search-toggle').click(function() {
|
|
||||||
$(".marsk-container").show();
|
|
||||||
})
|
|
||||||
$('.ac-close').click(function() {
|
|
||||||
$(".marsk-container").hide();
|
|
||||||
})
|
|
||||||
// 顶部国家选择
|
|
||||||
$('.top-country-toggle').click(function(){
|
|
||||||
$(".mask,.action-sheet").show();
|
|
||||||
})
|
|
||||||
$('.top-country .close-icon').click(function(){
|
|
||||||
$(".mask,.action-sheet").hide();
|
|
||||||
})
|
|
||||||
|
|
||||||
// 移动端顶部宽度设置和主体内容宽度一致
|
document.addEventListener('DOMContentLoaded', function ()
|
||||||
var pageWidth = $('.oricoEGapp').outerWidth();
|
{
|
||||||
// 设置.header-PC元素的宽度
|
const navBtn = document.querySelector('.nav-img');
|
||||||
$('.oircoEgapp-head').css('width', pageWidth + 'px');
|
const navBtn1 = document.querySelector('.nav-img1');
|
||||||
// 可选:监听窗口大小变化,实时更新宽度
|
const dropdownMenu = document.querySelector('.nav-dropdown-menu');
|
||||||
$(window).resize(function() {
|
|
||||||
var newWidth = $('.oricoEGapp').outerWidth();
|
|
||||||
$('.oircoEgapp-head').css('width', newWidth + 'px');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 回显搜索历史记录
|
// 禁止body滚动
|
||||||
history();
|
function disableBodyScroll() {
|
||||||
})
|
document.body.style.overflow = 'hidden';
|
||||||
|
document.body.style.position = 'fixed';
|
||||||
function history() {
|
document.body.style.top = `-${window.scrollY}px`;
|
||||||
var keywords = new URL(window.location.href).searchParams.get('keywords')
|
document.body.style.width = '100%';
|
||||||
var history_keywords = localStorage.getItem('header_search_keywords');
|
|
||||||
if (!history_keywords) {
|
|
||||||
history_keywords = [];
|
|
||||||
} else {
|
|
||||||
history_keywords = JSON.parse(history_keywords);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 记录搜索关键词
|
// 恢复body滚动
|
||||||
if (keywords) {
|
function enableBodyScroll() {
|
||||||
if (history_keywords.includes(keywords)) {
|
const scrollY = document.body.style.top;
|
||||||
history_keywords.splice(history_keywords.indexOf(keywords), 1);
|
document.body.style.overflow = '';
|
||||||
|
document.body.style.position = '';
|
||||||
|
document.body.style.top = '';
|
||||||
|
document.body.style.width = '';
|
||||||
|
if (scrollY) {
|
||||||
|
window.scrollTo(0, parseInt(scrollY || '0') * -1);
|
||||||
}
|
}
|
||||||
history_keywords.unshift(keywords);
|
|
||||||
if (history_keywords.length > 3) {
|
|
||||||
history_keywords.pop();
|
|
||||||
}
|
|
||||||
localStorage.setItem('header_search_keywords', JSON.stringify(history_keywords));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回显搜索历史
|
// 复位所有子菜单(关闭并重置滚动位置)
|
||||||
history_keywords.forEach(function(item) {
|
function resetAllSubMenus() {
|
||||||
$('#history').append(
|
let hasOpenMenu = false;
|
||||||
$('<a>')
|
document.querySelectorAll('.has-child .sub-menu').forEach(function(subMenu) {
|
||||||
.css({
|
if (subMenu.classList.contains('show')) {
|
||||||
'margin-right': '10px'
|
hasOpenMenu = true;
|
||||||
})
|
}
|
||||||
.attr('href', '{:url("product/search")}?keywords=' + item)
|
subMenu.classList.remove('show');
|
||||||
.text(item)
|
// 重置滚动位置到顶部
|
||||||
);
|
subMenu.scrollTop = 0;
|
||||||
|
});
|
||||||
|
document.querySelectorAll('.has-child').forEach(function(item) {
|
||||||
|
item.classList.remove('open');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果没有打开的菜单,恢复body滚动
|
||||||
|
if (!hasOpenMenu) {
|
||||||
|
enableBodyScroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭单个子菜单并重置滚动位置
|
||||||
|
function closeSubMenu(subMenu, menuItem) {
|
||||||
|
if (subMenu) {
|
||||||
|
subMenu.classList.remove('show');
|
||||||
|
subMenu.scrollTop = 0; // 重置滚动位置
|
||||||
|
}
|
||||||
|
if (menuItem) {
|
||||||
|
menuItem.classList.remove('open');
|
||||||
|
}
|
||||||
|
// 检查是否还有其他打开的菜单
|
||||||
|
const anyOpen = document.querySelector('.has-child .sub-menu.show');
|
||||||
|
if (!anyOpen) {
|
||||||
|
enableBodyScroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开子菜单
|
||||||
|
function openSubMenu(subMenu, menuItem) {
|
||||||
|
// 禁止body滚动
|
||||||
|
disableBodyScroll();
|
||||||
|
|
||||||
|
subMenu.classList.add('show');
|
||||||
|
menuItem.classList.add('open');
|
||||||
|
// 确保新打开的菜单滚动位置在顶部
|
||||||
|
subMenu.scrollTop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开菜单
|
||||||
|
navBtn.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
// 禁止body滚动
|
||||||
|
disableBodyScroll();
|
||||||
|
// 关闭所有弹窗
|
||||||
|
closeAllModals();
|
||||||
|
dropdownMenu.classList.add('show');
|
||||||
|
navBtn.style.display = 'none';
|
||||||
|
navBtn1.style.display = 'block';
|
||||||
});
|
});
|
||||||
|
|
||||||
return history_keywords;
|
// 关闭菜单 - 复位所有子菜单
|
||||||
}
|
navBtn1.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
dropdownMenu.classList.remove('show');
|
||||||
|
navBtn.style.display = 'block';
|
||||||
|
navBtn1.style.display = 'none';
|
||||||
|
|
||||||
|
// 复位所有子菜单到初始状态
|
||||||
|
resetAllSubMenus();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ====================== 处理所有菜单项(同一时间只展开一个) ======================
|
||||||
|
document.querySelectorAll('.menu-item').forEach(function (item)
|
||||||
|
{
|
||||||
|
const isHasChild = item.classList.contains('has-child');
|
||||||
|
const subMenu = item.querySelector('.sub-menu');
|
||||||
|
const box = item.querySelector('.menu-item-box');
|
||||||
|
|
||||||
|
if (isHasChild && subMenu) {
|
||||||
|
// 移除原有事件,重新绑定(确保只有一个展开)
|
||||||
|
const newBox = box.cloneNode(true);
|
||||||
|
box.parentNode.replaceChild(newBox, box);
|
||||||
|
|
||||||
|
newBox.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
// 检查当前是否已展开
|
||||||
|
const isOpen = subMenu.classList.contains('show');
|
||||||
|
|
||||||
|
// 关闭所有其他子菜单并重置滚动位置
|
||||||
|
document.querySelectorAll('.has-child').forEach(function (otherItem) {
|
||||||
|
const otherSubMenu = otherItem.querySelector('.sub-menu');
|
||||||
|
if (otherSubMenu && otherSubMenu !== subMenu) {
|
||||||
|
otherSubMenu.classList.remove('show');
|
||||||
|
otherSubMenu.scrollTop = 0; // 重置滚动位置
|
||||||
|
otherItem.classList.remove('open');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 切换当前菜单
|
||||||
|
if (!isOpen) {
|
||||||
|
openSubMenu(subMenu, item);
|
||||||
|
} else {
|
||||||
|
closeSubMenu(subMenu, item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const link = item.getAttribute('data-link');
|
||||||
|
if (link) {
|
||||||
|
item.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
window.location.href = link;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 阻止子菜单链接冒泡
|
||||||
|
document.querySelectorAll('.sub-item').forEach(function (sub)
|
||||||
|
{
|
||||||
|
sub.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dropdownMenu.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
navBtn1.style.display = 'none';
|
||||||
|
navBtn.style.display = 'block';
|
||||||
|
|
||||||
|
// 关闭所有弹窗的公共函数
|
||||||
|
function closeAllModals ()
|
||||||
|
{
|
||||||
|
cartModal.classList.remove('show');
|
||||||
|
langModal.classList.remove('show');
|
||||||
|
searchModal.classList.remove('show');
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.value = '';
|
||||||
|
if (searchClearBtn) searchClearBtn.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 购物车弹窗交互 ======================
|
||||||
|
const cardBtn = document.querySelector('.nav-card');
|
||||||
|
const cartModal = document.getElementById('cartModal');
|
||||||
|
const cartModalClose = cartModal.querySelector('.modal-close');
|
||||||
|
|
||||||
|
cardBtn.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
// 关闭下拉菜单和其他弹窗
|
||||||
|
dropdownMenu.classList.remove('show');
|
||||||
|
navBtn.style.display = 'block';
|
||||||
|
navBtn1.style.display = 'none';
|
||||||
|
closeAllModals();
|
||||||
|
// 复位所有子菜单
|
||||||
|
resetAllSubMenus();
|
||||||
|
cartModal.classList.add('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
cartModalClose.addEventListener('click', function ()
|
||||||
|
{
|
||||||
|
cartModal.classList.remove('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
cartModal.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
if (e.target === cartModal) {
|
||||||
|
cartModal.classList.remove('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ====================== 语言弹窗交互 ======================
|
||||||
|
const langBtn = document.querySelector('.nav-lang');
|
||||||
|
const langModal = document.getElementById('langModal');
|
||||||
|
const langModalClose = langModal.querySelector('.modal-close');
|
||||||
|
|
||||||
|
langBtn.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
// 关闭下拉菜单和其他弹窗
|
||||||
|
dropdownMenu.classList.remove('show');
|
||||||
|
navBtn.style.display = 'block';
|
||||||
|
navBtn1.style.display = 'none';
|
||||||
|
closeAllModals();
|
||||||
|
// 复位所有子菜单
|
||||||
|
resetAllSubMenus();
|
||||||
|
langModal.classList.add('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
langModalClose.addEventListener('click', function ()
|
||||||
|
{
|
||||||
|
langModal.classList.remove('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
langModal.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
if (e.target === langModal) {
|
||||||
|
langModal.classList.remove('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.lang-item').forEach(function (item)
|
||||||
|
{
|
||||||
|
item.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
console.log('选择了语言:', this.innerText);
|
||||||
|
langModal.classList.remove('show');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ====================== 搜索记录功能 ======================
|
||||||
|
// 获取搜索记录
|
||||||
|
function getSearchHistory ()
|
||||||
|
{
|
||||||
|
const history = localStorage.getItem('searchHistory');
|
||||||
|
return history ? JSON.parse(history) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存搜索记录
|
||||||
|
function saveSearchHistory (history)
|
||||||
|
{
|
||||||
|
localStorage.setItem('searchHistory', JSON.stringify(history));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加搜索记录
|
||||||
|
function addSearchHistory (keyword)
|
||||||
|
{
|
||||||
|
if (!keyword || !keyword.trim()) return;
|
||||||
|
keyword = keyword.trim();
|
||||||
|
let history = getSearchHistory();
|
||||||
|
history = history.filter(item => item !== keyword);
|
||||||
|
history.unshift(keyword);
|
||||||
|
if (history.length > 10) {
|
||||||
|
history = history.slice(0, 10);
|
||||||
|
}
|
||||||
|
saveSearchHistory(history);
|
||||||
|
renderSearchHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除单条搜索记录
|
||||||
|
function deleteSearchHistoryItem (keyword)
|
||||||
|
{
|
||||||
|
let history = getSearchHistory();
|
||||||
|
history = history.filter(item => item !== keyword);
|
||||||
|
saveSearchHistory(history);
|
||||||
|
renderSearchHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空所有搜索记录
|
||||||
|
function clearAllSearchHistory ()
|
||||||
|
{
|
||||||
|
saveSearchHistory([]);
|
||||||
|
renderSearchHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染搜索记录列表
|
||||||
|
function renderSearchHistory ()
|
||||||
|
{
|
||||||
|
const historyList = document.getElementById('searchHistoryList');
|
||||||
|
const history = getSearchHistory();
|
||||||
|
|
||||||
|
if (!historyList) return;
|
||||||
|
|
||||||
|
if (history.length === 0) {
|
||||||
|
historyList.innerHTML = '<div class="empty-history">暂无搜索记录</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
historyList.innerHTML = '';
|
||||||
|
history.forEach(function (keyword)
|
||||||
|
{
|
||||||
|
const itemDiv = document.createElement('div');
|
||||||
|
itemDiv.className = 'search-history-item';
|
||||||
|
itemDiv.innerHTML = `
|
||||||
|
<span>${escapeHtml(keyword)}</span>
|
||||||
|
<img src="__IMAGES__/header/x.png" class="delete-icon" data-keyword="${escapeHtml(keyword)}">
|
||||||
|
`;
|
||||||
|
itemDiv.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
if (e.target.classList && e.target.classList.contains('delete-icon')) {
|
||||||
|
e.stopPropagation();
|
||||||
|
deleteSearchHistoryItem(keyword);
|
||||||
|
} else {
|
||||||
|
e.stopPropagation();
|
||||||
|
searchInput.value = keyword;
|
||||||
|
doSearch(keyword);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
historyList.appendChild(itemDiv);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 简单的防XSS
|
||||||
|
function escapeHtml (str)
|
||||||
|
{
|
||||||
|
return str.replace(/[&<>]/g, function (m)
|
||||||
|
{
|
||||||
|
if (m === '&') return '&';
|
||||||
|
if (m === '<') return '<';
|
||||||
|
if (m === '>') return '>';
|
||||||
|
return m;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 搜索弹窗交互 ======================
|
||||||
|
const searchBtn = document.querySelector('.nav-search');
|
||||||
|
const searchModal = document.getElementById('searchModal');
|
||||||
|
const searchModalClose = searchModal.querySelector('.modal-close');
|
||||||
|
const searchInput = document.getElementById('searchInput');
|
||||||
|
const searchSubmit = document.getElementById('searchSubmit');
|
||||||
|
const searchClearBtn = document.getElementById('searchClearBtn');
|
||||||
|
const clearAllHistoryBtn = document.getElementById('clearAllHistory');
|
||||||
|
|
||||||
|
searchInput.addEventListener('input', function (e)
|
||||||
|
{
|
||||||
|
if (searchInput.value.length > 0) {
|
||||||
|
searchClearBtn.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
searchClearBtn.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
searchClearBtn.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
searchInput.value = '';
|
||||||
|
searchClearBtn.style.display = 'none';
|
||||||
|
searchInput.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (clearAllHistoryBtn) {
|
||||||
|
clearAllHistoryBtn.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
clearAllSearchHistory();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
searchBtn.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
// 关闭下拉菜单和其他弹窗
|
||||||
|
dropdownMenu.classList.remove('show');
|
||||||
|
navBtn.style.display = 'block';
|
||||||
|
navBtn1.style.display = 'none';
|
||||||
|
closeAllModals();
|
||||||
|
// 复位所有子菜单
|
||||||
|
resetAllSubMenus();
|
||||||
|
renderSearchHistory();
|
||||||
|
searchModal.classList.add('show');
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
searchInput.focus();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
searchModalClose.addEventListener('click', function ()
|
||||||
|
{
|
||||||
|
searchModal.classList.remove('show');
|
||||||
|
searchInput.value = '';
|
||||||
|
searchClearBtn.style.display = 'none';
|
||||||
|
});
|
||||||
|
|
||||||
|
searchModal.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
if (e.target === searchModal) {
|
||||||
|
searchModal.classList.remove('show');
|
||||||
|
searchInput.value = '';
|
||||||
|
searchClearBtn.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 执行搜索
|
||||||
|
function doSearch (keyword)
|
||||||
|
{
|
||||||
|
if (keyword && keyword.trim()) {
|
||||||
|
const searchKeyword = keyword.trim();
|
||||||
|
console.log('搜索关键词:', searchKeyword);
|
||||||
|
if (searchKeyword) {
|
||||||
|
addSearchHistory(searchKeyword);
|
||||||
|
window.location.href = "{:url('product/search')}?keywords=" + encodeURIComponent(searchKeyword);
|
||||||
|
searchModal.classList.remove('show');
|
||||||
|
searchInput.value = '';
|
||||||
|
searchClearBtn.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchSubmit.addEventListener('click', function (e)
|
||||||
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
doSearch(searchInput.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
searchInput.addEventListener('keypress', function (e)
|
||||||
|
{
|
||||||
|
console.log(e,'========e=============')
|
||||||
|
if (e.key === 'Enter' || e.key === 'enter' || e.keyCode === 13) {
|
||||||
|
e.preventDefault();
|
||||||
|
doSearch(searchInput.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ====================== 添加:点击空白区域关闭所有子菜单 ======================
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
// 如果点击的不是菜单项内部,关闭所有子菜单
|
||||||
|
if (!e.target.closest('.menu-item')) {
|
||||||
|
resetAllSubMenus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ====================== 购物车弹窗悬浮图功能 ======================
|
||||||
|
// 处理购物车弹窗中的图片悬浮效果
|
||||||
|
function initCartModalHover() {
|
||||||
|
const modalItems = document.querySelectorAll('#cartModal .modal-item');
|
||||||
|
|
||||||
|
modalItems.forEach(function(item) {
|
||||||
|
// 查找当前item中是否有悬浮图(隐藏的那个)
|
||||||
|
const defaultImg = item.querySelector('.modal-item-img');
|
||||||
|
const hiddenItem = item.nextElementSibling;
|
||||||
|
let hoverImg = null;
|
||||||
|
|
||||||
|
// 检查下一个元素是否是隐藏的悬浮图容器
|
||||||
|
if (hiddenItem && hiddenItem.classList && hiddenItem.classList.contains('modal-item') && hiddenItem.style.display === 'none') {
|
||||||
|
hoverImg = hiddenItem.querySelector('.modal-item-img');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有悬浮图
|
||||||
|
if (hoverImg && defaultImg) {
|
||||||
|
const originalSrc = defaultImg.src;
|
||||||
|
const hoverSrc = hoverImg.src;
|
||||||
|
const link = item.getAttribute('data-link');
|
||||||
|
|
||||||
|
// 移除原有的href,因为需要悬浮图效果
|
||||||
|
item.style.cursor = 'pointer';
|
||||||
|
|
||||||
|
// 鼠标移入:显示悬浮图
|
||||||
|
item.addEventListener('mouseenter', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
defaultImg.src = hoverSrc;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标移出:恢复普通图
|
||||||
|
item.addEventListener('mouseleave', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
defaultImg.src = originalSrc;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 点击事件:如果有链接就跳转
|
||||||
|
item.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (link && link !== '#') {
|
||||||
|
window.location.href = link;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 没有悬浮图,保持原有链接
|
||||||
|
const link = item.getAttribute('href') || item.getAttribute('data-link');
|
||||||
|
if (link && link !== '#') {
|
||||||
|
item.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
window.location.href = link;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在购物车弹窗打开时初始化悬浮图功能
|
||||||
|
const cartModalObserver = new MutationObserver(function(mutations) {
|
||||||
|
mutations.forEach(function(mutation) {
|
||||||
|
if (mutation.attributeName === 'class') {
|
||||||
|
if (cartModal.classList.contains('show')) {
|
||||||
|
setTimeout(function() {
|
||||||
|
initCartModalHover();
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (cartModal) {
|
||||||
|
cartModalObserver.observe(cartModal, { attributes: true });
|
||||||
|
// 如果弹窗默认是打开的,也初始化一次
|
||||||
|
if (cartModal.classList.contains('show')) {
|
||||||
|
initCartModalHover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
1270
app/index/view/mobile/topic_laptop/index.html
Normal file
1270
app/index/view/mobile/topic_laptop/index.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -57,6 +57,8 @@
|
|||||||
<div class="nars-hlpdt-ml">
|
<div class="nars-hlpdt-ml">
|
||||||
{notempty name="article_categorys"}
|
{notempty name="article_categorys"}
|
||||||
<div class="nav-tree">
|
<div class="nav-tree">
|
||||||
|
|
||||||
|
|
||||||
{volist name="article_categorys" id="ac" key="idx"}
|
{volist name="article_categorys" id="ac" key="idx"}
|
||||||
<div class="categoryhelp">
|
<div class="categoryhelp">
|
||||||
<div class="categoryhelp-title">
|
<div class="categoryhelp-title">
|
||||||
@@ -67,6 +69,24 @@
|
|||||||
<span>{$ac.name}</span>
|
<span>{$ac.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<ul class="sub-list" {if condition='$ac.id == $Request.get.cid' }style="display: block;" {/if}>
|
<ul class="sub-list" {if condition='$ac.id == $Request.get.cid' }style="display: block;" {/if}>
|
||||||
|
{volist name="ac.child" id="ad"}
|
||||||
|
<li class="two-mues">
|
||||||
|
<a href="#" class="two-a">
|
||||||
|
<div><img src="__IMAGES__/nars-jt.png"
|
||||||
|
class="arrow {if condition='$ad.id == $Request.get.pid'}rotate{/if}">
|
||||||
|
</div>
|
||||||
|
<span>{$ad.name}</span>
|
||||||
|
</a>
|
||||||
|
<ul class="thress-mues" {if condition='$ad.id == $Request.get.pid' }style="display: block;" {/if}>
|
||||||
|
{volist name="ad.article" id="ae"}
|
||||||
|
<li>
|
||||||
|
<a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id ,'pid' => $ad.id, 'id' => $ae.id])}"
|
||||||
|
style="margin-left:18%;padding: 0.4rem;">{$ae.title}</a>
|
||||||
|
</li>
|
||||||
|
{/volist}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{/volist}
|
||||||
{volist name="ac.article" id="ar"}
|
{volist name="ac.article" id="ar"}
|
||||||
<li>
|
<li>
|
||||||
<a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id , 'id' => $ar.id])}"
|
<a href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id , 'id' => $ar.id])}"
|
||||||
@@ -78,6 +98,9 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{/volist}
|
{/volist}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
@@ -128,6 +151,17 @@
|
|||||||
$(this).next('.sub-list').slideToggle();
|
$(this).next('.sub-list').slideToggle();
|
||||||
$(this).find('.arrow').toggleClass('rotate');
|
$(this).find('.arrow').toggleClass('rotate');
|
||||||
});
|
});
|
||||||
|
//分类二三级交互
|
||||||
|
$('.two-a').click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation(); // 阻止事件冒泡
|
||||||
|
|
||||||
|
// 切换当前二级菜单的箭头方向
|
||||||
|
$(this).find('.arrow').toggleClass('rotate');
|
||||||
|
|
||||||
|
// 切换对应的三级菜单显示/隐藏
|
||||||
|
$(this).siblings('.thress-mues').slideToggle();
|
||||||
|
});
|
||||||
// 点击顶部搜索图标-点击取消关闭
|
// 点击顶部搜索图标-点击取消关闭
|
||||||
$('#ssico').click(function () {
|
$('#ssico').click(function () {
|
||||||
$('.nhlpapp-pagescate').hide();
|
$('.nhlpapp-pagescate').hide();
|
||||||
|
|||||||
763
app/index/view/mobile/topic_power_prodline/index.html
Normal file
763
app/index/view/mobile/topic_power_prodline/index.html
Normal file
@@ -0,0 +1,763 @@
|
|||||||
|
{extend name="public/base" /}
|
||||||
|
{block name="style"}
|
||||||
|
<!-- 将rem适配JS移到这里,确保优先执行 -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function (doc, win) {
|
||||||
|
var docEl = doc.documentElement;
|
||||||
|
var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
|
||||||
|
|
||||||
|
function setRootFontSize() {
|
||||||
|
var clientWidth = docEl.clientWidth;
|
||||||
|
if (!clientWidth) return;
|
||||||
|
var fontSize = clientWidth / 7.5; // 750px/7.5=100px,375px/7.5=50px
|
||||||
|
// 直接修改内联样式,优先级最高
|
||||||
|
docEl.setAttribute('style', 'font-size: ' + fontSize + 'px !important;');
|
||||||
|
}
|
||||||
|
|
||||||
|
setRootFontSize();
|
||||||
|
win.addEventListener(resizeEvt, setRootFontSize);
|
||||||
|
doc.addEventListener('DOMContentLoaded', setRootFontSize);
|
||||||
|
})(document, window);
|
||||||
|
</script>
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/index.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/swiper.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/nav.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/advantage.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/moren.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/mask.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/product.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/product_list.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/product_card.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/footer.css">
|
||||||
|
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block name="main"}
|
||||||
|
<!-- <a class="header" href="/">
|
||||||
|
<div class="header-img">
|
||||||
|
<img src="__IMAGES__/logo.png" alt="">
|
||||||
|
</div>
|
||||||
|
</a> -->
|
||||||
|
<!-- 轮播核心容器 -->
|
||||||
|
<div class="swiper-container auto-swiper-container" >
|
||||||
|
{notempty name="data.focus_image"}
|
||||||
|
<div class="swiper-wrapper">
|
||||||
|
{volist name="data.focus_image" id="fo"}
|
||||||
|
<a class="swiper-slide auto-swiper-slide" href="{$fo.link}">
|
||||||
|
<img src="{$fo.image}" alt="{$fo.title}" />
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
<div class="swiper-pagination"></div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
<!-- 分类 -->
|
||||||
|
{notempty name="data.category"}
|
||||||
|
<div class="nav-box">
|
||||||
|
{volist name="data.category" id="ca"}
|
||||||
|
<a class="nav-item" href="{$ca.link}">
|
||||||
|
<img src="{$ca.image}" alt="{$ca.title}">
|
||||||
|
<p {:style(['color'=>$ca.title_txt_color])}>{$ca.title}</p>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 500万 -->
|
||||||
|
{notempty name="data.why_choose"}
|
||||||
|
<div class="advantage-section">
|
||||||
|
{assign name="why_choose_title" value=":array_shift($data.why_choose)" /}
|
||||||
|
<h2 class="advantage-section__title">{$why_choose_title.title|default=''|raw}</h2>
|
||||||
|
<div class="advantage-section__list">
|
||||||
|
{volist name="data.why_choose" id="ch"}
|
||||||
|
<div class="advantage-card-wrap">
|
||||||
|
<div class="advantage-card" data-target="design">
|
||||||
|
<img src="{$ch.image}" alt="{$ch.title}:{$ch.short_title}" class="advantage-card__img">
|
||||||
|
<div class="advantage-card__content">
|
||||||
|
<!-- 标题+箭头容器:水平+垂直双居中,内部文字左、箭头右 -->
|
||||||
|
<div class="advantage-card__heading-wrap">
|
||||||
|
<div class="advantage-card__heading" {:style(['color'=>$ch.title_txt_color])}>{$ch.title}</div>
|
||||||
|
<img src="__IMAGES__/jiant.png" alt="" class="card-arrow">
|
||||||
|
</div>
|
||||||
|
<div class="advantage-card__description" {:style(['color'=>$ch.short_title_txt_color])}>{$ch.short_title}</div>
|
||||||
|
<div style="display:none;" class="mack-conten-text">{$ch.desc|raw}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 产品差旅充 -->
|
||||||
|
{notempty name="data.travel_charger"}
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="tc_title" value=":array_shift($data.travel_charger)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$tc_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$tc_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
<div class="product-container" >
|
||||||
|
{assign name="tc_first_section_lf" value=":array_shift($data.travel_charger)" /}
|
||||||
|
{notempty name="tc_first_section_lf"}
|
||||||
|
<a class="product-left" href="{$tc_first_section_lf.link}">
|
||||||
|
<img src="{$tc_first_section_lf.image}" alt="{$tc_first_section_lf.title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸统一,定位不同 -->
|
||||||
|
<div class="product-img-hover top55">
|
||||||
|
<img src="{$tc_first_section_lf.extra_image}" alt="{$tc_first_section_lf.short_title}" class="img1">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="tc_first_section_lr" value=":array_shift($data.travel_charger)" /}
|
||||||
|
{notempty name="tc_first_section_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$tc_first_section_lr.image}" alt="{$tc_first_section_lr.title}" class="right-content right-img">
|
||||||
|
<video src="{$tc_first_section_lr.video}" class="right-content right-video" muted loop playsinline>
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
<button class="video-play-btn">
|
||||||
|
<span class="play-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<path d="M9 7L16 12L9 17V7Z" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<!-- 暂停图标(默认隐藏) -->
|
||||||
|
<span class="pause-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<rect x="8" y="7" width="3" height="10" fill="white" />
|
||||||
|
<rect x="13" y="7" width="3" height="10" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{assign name="tc_second_section" value=":array_splice($data.travel_charger, 0, 4)" /}
|
||||||
|
{notempty name="tc_second_section"}
|
||||||
|
<div class="product-card-box">
|
||||||
|
<div class="product-card-container">
|
||||||
|
{volist name="tc_second_section" id="tss"}
|
||||||
|
<a class="product-card-wrap" href="{$tss.link}">
|
||||||
|
<div class="product-card" >
|
||||||
|
<div class="product-card-img">
|
||||||
|
<img src="{$tss.image}" alt="{$tss.title}">
|
||||||
|
</div>
|
||||||
|
<div class="product-card-text">
|
||||||
|
<div class="product-card-title" {:style(['color'=>$tss.title_txt_color])}>{$tss.title}</div>
|
||||||
|
<div class="product-card-desc" {:style(['color'=>$tss.short_title_txt_color])}>{$tss.short_title}</div>
|
||||||
|
</div>
|
||||||
|
<div class="product-card-link">
|
||||||
|
<img src="__IMAGES__/ljgd.png" alt="查看更多">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{assign name="tc_three_section" value=":array_shift($data.travel_charger)" /}
|
||||||
|
{notempty name="tc_three_section"}
|
||||||
|
<a href="{$tc_three_section.link}" class="more">
|
||||||
|
<div class="more-img">
|
||||||
|
{$tc_three_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 产品 家居充-->
|
||||||
|
{notempty name="data.home_charger"}
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="hc_title" value=":array_shift($data.home_charger)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$hc_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$hc_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
<div class="product-container">
|
||||||
|
{assign name="hc_first_section_lf" value=":array_shift($data.home_charger)" /}
|
||||||
|
{notempty name="hc_first_section_lf"}
|
||||||
|
<a class="product-left" href="{$hc_first_section_lf.link}">
|
||||||
|
<img src="{$hc_first_section_lf.image}" alt="{$hc_first_section_lf.title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸统一,定位不同 -->
|
||||||
|
<div class="product-img-hover">
|
||||||
|
<img src="{$hc_first_section_lf.extra_image}" alt="{$hc_first_section_lf.short_title}" class="img2">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="hc_first_section_lr" value=":array_shift($data.home_charger)" /}
|
||||||
|
{notempty name="hc_first_section_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$hc_first_section_lr.image}" alt="{$hc_first_section_lr.title}" class="right-content right-img">
|
||||||
|
<video src="{$hc_first_section_lr.video}" class="right-content right-video" muted loop playsinline >
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
<button class="video-play-btn">
|
||||||
|
<span class="play-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<path d="M9 7L16 12L9 17V7Z" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<!-- 暂停图标(默认隐藏) -->
|
||||||
|
<span class="pause-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<rect x="8" y="7" width="3" height="10" fill="white" />
|
||||||
|
<rect x="13" y="7" width="3" height="10" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{assign name="hc_second_section" value=":array_splice($data.home_charger, 0, 4)" /}
|
||||||
|
{notempty name="hc_second_section"}
|
||||||
|
<div class="product-card-box">
|
||||||
|
<div class="product-card-container">
|
||||||
|
{volist name="hc_second_section" id="hcs"}
|
||||||
|
<a class="product-card-wrap" href="{$hcs.link}">
|
||||||
|
<div class="product-card" href="#">
|
||||||
|
<div class="product-card-img">
|
||||||
|
<img src="{$hcs.image}" alt="{$hcs.short_title}">
|
||||||
|
</div>
|
||||||
|
<div class="product-card-text">
|
||||||
|
<div class="product-card-title">{$hcs.title}</div>
|
||||||
|
<div class="product-card-desc">{$hcs.short_title}</div>
|
||||||
|
</div>
|
||||||
|
<div class="product-card-link">
|
||||||
|
<img src="__IMAGES__/ljgd.png" alt="查看更多">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="hc_three_section" value=":array_shift($data.home_charger)" /}
|
||||||
|
{notempty name="hc_three_section"}
|
||||||
|
<a href="{$hc_three_section.link}" class="more">
|
||||||
|
<div class="more-img">
|
||||||
|
{$hc_three_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 产品 桌面充(悬浮图上右超出)底部列表样式不一样(左文右图) -->
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="dc_title" value=":array_shift($data.desktop_charger)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$dc_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$dc_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
<div class="product-container">
|
||||||
|
{assign name="dc_first_section_lf" value=":array_shift($data.desktop_charger)" /}
|
||||||
|
{notempty name="dc_first_section_lf"}
|
||||||
|
<a class="product-left" href="{$dc_first_section_lf.link}">
|
||||||
|
<img src="{$dc_first_section_lf.image}" alt="{$dc_first_section_lf.short_title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸和第一个完全一致,仅定位不同 -->
|
||||||
|
<div class="product-img-hover right" >
|
||||||
|
<img src="{$dc_first_section_lf.extra_image}" alt="{$dc_first_section_lf.short_title}" class="img3">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="dc_first_section_lr" value=":array_shift($data.desktop_charger)" /}
|
||||||
|
{notempty name="dc_first_section_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$dc_first_section_lr.image}"
|
||||||
|
alt="使用场景" class="right-content right-img">
|
||||||
|
<!--muted loop playsinline controls-->
|
||||||
|
<video
|
||||||
|
src="{$dc_first_section_lr.video}"
|
||||||
|
class="right-content right-video" muted loop playsinline >
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
<button class="video-play-btn">
|
||||||
|
<span class="play-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<path d="M9 7L16 12L9 17V7Z" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<!-- 暂停图标(默认隐藏) -->
|
||||||
|
<span class="pause-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<rect x="8" y="7" width="3" height="10" fill="white" />
|
||||||
|
<rect x="13" y="7" width="3" height="10" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{assign name="dc_second_section" value=":array_splice($data.desktop_charger, 0, 2)" /}
|
||||||
|
{notempty name="dc_second_section"}
|
||||||
|
<div class="product-card-box">
|
||||||
|
<div class="product-card-container">
|
||||||
|
{volist name="dc_second_section" id="dcs"}
|
||||||
|
<a class="product-card-wrap" href="{$dcs.link}">
|
||||||
|
<div class="product-card" href="#">
|
||||||
|
<div class="product-card-img">
|
||||||
|
<img src="{$dcs.image}" alt="{$dcs.short_title}">
|
||||||
|
</div>
|
||||||
|
<div class="product-card-text">
|
||||||
|
<div class="product-card-title">{$dcs.title}</div>
|
||||||
|
<div class="product-card-desc">{$dcs.short_title}</div>
|
||||||
|
</div>
|
||||||
|
<div class="product-card-link">
|
||||||
|
<img src="__IMAGES__/ljgd.png" alt="查看更多">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/notempty}
|
||||||
|
{assign name="dc_three_section" value=":array_shift($data.desktop_charger)" /}
|
||||||
|
{notempty name="dc_three_section"}
|
||||||
|
<a href="{$dc_three_section.link}" class="more">
|
||||||
|
<div class="more-img">
|
||||||
|
{$dc_three_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
<!-- 墙插 -->
|
||||||
|
{notempty name="data.wall_charger"}
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="wc_title" value=":array_shift($data.wall_charger)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$wc_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$wc_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
<div class="product-container">
|
||||||
|
{assign name="wc_first_section_lf" value=":array_shift($data.wall_charger)" /}
|
||||||
|
{notempty name="wc_first_section_lf"}
|
||||||
|
<a class="product-left" href="{$wc_first_section_lf.link}">
|
||||||
|
<img src="{$wc_first_section_lf.image}" alt="{$wc_first_section_lf.title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸统一,定位不同 -->
|
||||||
|
<div class="product-img-hover top70">
|
||||||
|
<img src="{$wc_first_section_lf.extra_image}" alt="{$wc_first_section_lf.title}" class="img4">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="wc_first_section_lr" value=":array_shift($data.wall_charger)" /}
|
||||||
|
{notempty name="wc_first_section_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$wc_first_section_lr.image}" alt="{$wc_first_section_lr.title}" class="right-content right-img">
|
||||||
|
<video src="{$wc_first_section_lr.video}" class="right-content right-video" muted loop playsinline>
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
<button class="video-play-btn">
|
||||||
|
<span class="play-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<path d="M9 7L16 12L9 17V7Z" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<!-- 暂停图标(默认隐藏) -->
|
||||||
|
<span class="pause-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<rect x="8" y="7" width="3" height="10" fill="white" />
|
||||||
|
<rect x="13" y="7" width="3" height="10" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{assign name="wc_more_section" value=":array_shift($data.wall_charger)" /}
|
||||||
|
{notempty name="wc_more_section"}
|
||||||
|
<a href="{$wc_more_section.link}" class="more">
|
||||||
|
<div class="more-img">
|
||||||
|
{$wc_more_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
{notempty name="data.converter"}
|
||||||
|
<!-- 转换器 -->
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="ct_title" value=":array_shift($data.converter)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$ct_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$ct_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
{assign name="ct_more_section" value=":array_pop($data.converter)" /}
|
||||||
|
{assign name="ct_chunk_section" value=":array_chunk($data.converter, 2)" /}
|
||||||
|
{assign name="ct_chunk_section_len" value=":count($ct_chunk_section)" /}
|
||||||
|
{volist name="ct_chunk_section" id="cts" key="k"}
|
||||||
|
<div class="product-container">
|
||||||
|
{assign name="cts_lf" value=":array_shift($cts)" /}
|
||||||
|
{notempty name="cts_lf"}
|
||||||
|
<a class="product-left" href="{$cts_lf.link}">
|
||||||
|
<img src="{$cts_lf.image}" alt="{$cts_lf.title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸统一,定位不同 -->
|
||||||
|
<!--style="display:flex;justify-content: center;"-->
|
||||||
|
<div class="product-img-hover top40" >
|
||||||
|
<!-- style="width:70%"-->
|
||||||
|
<img src="{$cts_lf.extra_image}" alt="{$cts_lf.title}" class="img5">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="cts_lr" value=":array_shift($cts)" /}
|
||||||
|
{notempty name="cts_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$cts_lr.image}" alt="{$cts_lr.title}" class="right-content right-img">
|
||||||
|
<video src="{$cts_lr.video}" class="right-content right-video" muted loop playsinline>
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
<!-- 播放图标 -->
|
||||||
|
<button class="video-play-btn">
|
||||||
|
<span class="play-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<path d="M9 7L16 12L9 17V7Z" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<!-- 暂停图标(默认隐藏) -->
|
||||||
|
<span class="pause-icon">
|
||||||
|
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" fill="rgba(0,0,0,0.5)" />
|
||||||
|
<rect x="8" y="7" width="3" height="10" fill="white" />
|
||||||
|
<rect x="13" y="7" width="3" height="10" fill="white" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{neq name="k" value="$ct_chunk_section_len"}
|
||||||
|
<div class="line"></div>
|
||||||
|
{/neq}
|
||||||
|
{/volist}
|
||||||
|
{notempty name="ct_more_section"}
|
||||||
|
<a href="{$ct_more_section.link}" class="more">
|
||||||
|
<div class="more-img">
|
||||||
|
{$ct_more_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
{notempty name="data.footer_info"}
|
||||||
|
<!-- 底部 -->
|
||||||
|
<div class="prodline-footer-box">
|
||||||
|
<div class="prodline-footer-box-img">
|
||||||
|
<img src="{$data.footer_info.0.image}" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 蒙版 -->
|
||||||
|
<div class="mask" id="mask">
|
||||||
|
<div class="mask-content" >
|
||||||
|
<span class="close-btn">×</span>
|
||||||
|
<div class="mask-scroll-content"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{/block}
|
||||||
|
{block name="script"}
|
||||||
|
<script type="text/javascript">
|
||||||
|
let swiper=null;
|
||||||
|
const advantageItems = document.querySelectorAll('.advantage-card');
|
||||||
|
let scrollTop = 0; // 保存页面滚动位置
|
||||||
|
let closeBtnHtml = null; // 关闭按钮元素(全局变量,避免重复创建)
|
||||||
|
const mask = document.getElementById('mask');
|
||||||
|
const maskContent = document.querySelector('.mask-content');
|
||||||
|
const maskScrollContent = document.querySelector('.mask-scroll-content'); // 滚动容器(关键!)
|
||||||
|
const closeBtn = document.querySelector('.close-btn')
|
||||||
|
// 初始化:确保 maskScrollContent 存在于 maskContent 中(避免被清空)
|
||||||
|
if (!maskScrollContent) {
|
||||||
|
// 如果页面没有 mask-scroll-content,动态创建(确保结构稳定)
|
||||||
|
const scrollContent = document.createElement('div');
|
||||||
|
scrollContent.className = 'mask-scroll-content';
|
||||||
|
maskContent.appendChild(scrollContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCloseBtn() {
|
||||||
|
if (closeBtnHtml) {
|
||||||
|
closeBtnHtml.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
closeBtnHtml = document.createElement('span');
|
||||||
|
closeBtnHtml.className = 'close-btn';
|
||||||
|
closeBtnHtml.innerHTML = '×';
|
||||||
|
|
||||||
|
closeBtnHtml.addEventListener('click', hideMask);
|
||||||
|
|
||||||
|
// 挂载到 maskContent(而非 scrollContent),避免被滚动影响位置
|
||||||
|
maskContent.prepend(closeBtnHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMask(contentHtml) {
|
||||||
|
// 保存页面滚动位置
|
||||||
|
scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
|
||||||
|
|
||||||
|
// 关键:将内容填充到 scrollContent 中(而非直接替换 maskContent)
|
||||||
|
maskScrollContent.innerHTML = contentHtml;
|
||||||
|
createCloseBtn();
|
||||||
|
|
||||||
|
// 显示蒙版
|
||||||
|
mask.style.display = 'flex';
|
||||||
|
|
||||||
|
// 禁止滚动(复用你的逻辑)
|
||||||
|
document.documentElement.classList.add('no-scroll');
|
||||||
|
document.body.classList.add('no-scroll');
|
||||||
|
document.body.style.top = `-${scrollTop}px`;
|
||||||
|
|
||||||
|
// 额外:打开蒙版时就重置滚动位置(避免残留上次滚动状态)
|
||||||
|
maskScrollContent.scrollTop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideMask() {
|
||||||
|
// 关键步骤 1:先重置 scrollContent 的滚动位置(此时元素还未被销毁)
|
||||||
|
maskScrollContent.scrollTop = 0;
|
||||||
|
|
||||||
|
// 关键步骤 2:清空 scrollContent 的内容(而非 maskContent)
|
||||||
|
maskScrollContent.innerHTML = "";
|
||||||
|
|
||||||
|
// 隐藏蒙版
|
||||||
|
mask.style.display = 'none';
|
||||||
|
|
||||||
|
// 恢复滚动(复用你的逻辑)
|
||||||
|
document.documentElement.classList.remove('no-scroll');
|
||||||
|
document.body.classList.remove('no-scroll');
|
||||||
|
document.body.style.top = '';
|
||||||
|
|
||||||
|
// 还原页面滚动位置
|
||||||
|
window.scrollTo(0, scrollTop);
|
||||||
|
|
||||||
|
// 移除关闭按钮(可选,避免残留)
|
||||||
|
if (closeBtnHtml) {
|
||||||
|
closeBtnHtml.remove();
|
||||||
|
closeBtnHtml = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 点击卡片显示详情
|
||||||
|
advantageItems.forEach((item) => {
|
||||||
|
item.addEventListener('click', (e) => {
|
||||||
|
// 获取当前点击卡片内的.mack-conten-text元素
|
||||||
|
const currentMackContent = e.currentTarget.querySelector('.mack-conten-text');
|
||||||
|
if (currentMackContent) {
|
||||||
|
// 关键修改:获取该元素的子内容(innerHTML 本身就是内部HTML,不含当前元素标签)
|
||||||
|
// 若想更彻底,可遍历子节点拼接内容(兼容特殊场景)
|
||||||
|
let contentHtml = '';
|
||||||
|
Array.from(currentMackContent.childNodes).forEach(child => {
|
||||||
|
// 只保留元素节点和文本节点(过滤空节点)
|
||||||
|
if (child.nodeType === 1 || child.nodeType === 3) {
|
||||||
|
contentHtml += child.outerHTML || child.textContent;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 显示蒙版并传入纯净的子内容
|
||||||
|
showMask(contentHtml);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 关闭按钮事件
|
||||||
|
closeBtn.addEventListener('click', hideMask);
|
||||||
|
// 点击蒙版背景关闭(可选)
|
||||||
|
mask.addEventListener('click', (e) => {
|
||||||
|
if (e.target === mask) hideMask();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ESC 键关闭(可选)
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape' && mask.style.display === 'flex') hideMask();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 关键:拦截蒙版的 touchmove 事件,阻止滚动穿透(移动端核心)
|
||||||
|
mask.addEventListener(
|
||||||
|
'touchmove',
|
||||||
|
(e) => {
|
||||||
|
// 只有点击蒙版背景(不是内容区域)才阻止滚动
|
||||||
|
if (e.target === mask) {
|
||||||
|
e.preventDefault(); // 阻止默认触摸滚动行为
|
||||||
|
e.stopPropagation(); // 阻止事件冒泡
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ passive: false }
|
||||||
|
); // passive: false 必须,否则 preventDefault 无效
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// 初始化所有视频容器
|
||||||
|
function initVideoContainers() {
|
||||||
|
const productRights = document.querySelectorAll('.product-right');
|
||||||
|
// 支持的视频格式
|
||||||
|
const supportedVideoFormats = ['.mp4', '.webm', '.ogg', '.mov', '.avi', '.mkv', '.flv', '.wmv'];
|
||||||
|
productRights.forEach((container, index) => {
|
||||||
|
const video = container.querySelector('.right-video');
|
||||||
|
const btn = container.querySelector('.video-play-btn');
|
||||||
|
const img = container.querySelector('.right-img');
|
||||||
|
if (!video || !btn || !img) return;
|
||||||
|
const videoSrc = video.src.trim()
|
||||||
|
console.log(videoSrc,'=videoSrc=')
|
||||||
|
// 修复:正确检测有效视频地址
|
||||||
|
// 排除空字符串、null、undefined
|
||||||
|
const hasValidVideo = !!videoSrc && videoSrc.trim() !== '' && videoSrc !== 'undefined' && videoSrc !== 'null';
|
||||||
|
|
||||||
|
// 验证视频格式是否有效
|
||||||
|
const isValidFormat = supportedVideoFormats.some(format =>
|
||||||
|
videoSrc.toLowerCase().endsWith(format) ||
|
||||||
|
(videoSrc.includes('?') && videoSrc.toLowerCase().split('?')[0].endsWith(format))
|
||||||
|
);
|
||||||
|
|
||||||
|
// 初始化状态:无视频或格式无效则保持图片显示,永不切换
|
||||||
|
if (!hasValidVideo || !isValidFormat) {
|
||||||
|
img.style.display = 'block';
|
||||||
|
video.style.display = 'none';
|
||||||
|
btn.style.display = 'none';
|
||||||
|
// 绑定空方法,防止调用报错
|
||||||
|
video.switchMedia = function() {};
|
||||||
|
console.log(`容器${index}:无有效视频(src="${videoSrc}"),保持图片显示`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 有有效视频的情况
|
||||||
|
console.log(`容器${index}:有有效视频(src="${videoSrc}"),初始化播放逻辑`);
|
||||||
|
|
||||||
|
// 初始状态
|
||||||
|
video.style.display = 'none';
|
||||||
|
video.pause();
|
||||||
|
img.style.display = 'block';
|
||||||
|
btn.style.display = 'none';
|
||||||
|
btn.style.opacity = '0';
|
||||||
|
|
||||||
|
// 同步状态函数
|
||||||
|
function syncMediaState() {
|
||||||
|
if (img.style.display === 'block') {
|
||||||
|
btn.style.display = 'none';
|
||||||
|
btn.style.opacity = '0';
|
||||||
|
} else {
|
||||||
|
btn.style.display = 'block';
|
||||||
|
btn.style.opacity = '1';
|
||||||
|
btn.classList.toggle('paused', !video.paused && !video.ended);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按钮点击事件
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
if (video.paused) {
|
||||||
|
video.play().catch(() => syncMediaState());
|
||||||
|
} else {
|
||||||
|
video.pause();
|
||||||
|
}
|
||||||
|
syncMediaState();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 视频事件监听
|
||||||
|
['play', 'pause', 'ended', 'playing', 'waiting'].forEach(event => {
|
||||||
|
video.addEventListener(event, syncMediaState);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 滚动切换函数
|
||||||
|
video.switchMedia = function(showVideo) {
|
||||||
|
// 只处理有有效视频的情况
|
||||||
|
if (showVideo) {
|
||||||
|
img.style.display = 'none';
|
||||||
|
video.style.display = 'block';
|
||||||
|
video.play().catch(() => {
|
||||||
|
console.log(`容器${index}:自动播放失败,需要用户交互`);
|
||||||
|
syncMediaState();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
video.pause();
|
||||||
|
img.style.display = 'block';
|
||||||
|
video.style.display = 'none';
|
||||||
|
}
|
||||||
|
syncMediaState();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始同步
|
||||||
|
syncMediaState();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动监听 - 优化版
|
||||||
|
function setupScrollWatcher() {
|
||||||
|
let ticking = false;
|
||||||
|
|
||||||
|
function updateVideoVisibility() {
|
||||||
|
const productRights = document.querySelectorAll('.product-right');
|
||||||
|
|
||||||
|
productRights.forEach(container => {
|
||||||
|
const video = container.querySelector('.right-video');
|
||||||
|
if (!video || !video.switchMedia) return;
|
||||||
|
|
||||||
|
// 检查是否在视口中
|
||||||
|
const rect = container.getBoundingClientRect();
|
||||||
|
const viewHeight = window.innerHeight || document.documentElement.clientHeight;
|
||||||
|
const isInView = rect.top < viewHeight * 0.7 && rect.bottom > viewHeight * 0.3;
|
||||||
|
|
||||||
|
// 只对有有效视频的元素调用switchMedia
|
||||||
|
video.switchMedia(isInView);
|
||||||
|
});
|
||||||
|
|
||||||
|
ticking = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用requestAnimationFrame优化性能
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
if (!ticking) {
|
||||||
|
requestAnimationFrame(updateVideoVisibility);
|
||||||
|
ticking = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
initVideoContainers();
|
||||||
|
setupScrollWatcher();
|
||||||
|
|
||||||
|
// 初始检查一次
|
||||||
|
setTimeout(() => {
|
||||||
|
const event = new Event('scroll');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.onload = function () {
|
||||||
|
if (typeof Swiper === 'undefined') {
|
||||||
|
console.error('Swiper加载失败,请刷新页面重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
swiper = new Swiper('.auto-swiper-container', {
|
||||||
|
autoplay: {
|
||||||
|
delay: 3000, // 3秒切换
|
||||||
|
disableOnInteraction: false,
|
||||||
|
},
|
||||||
|
loop: false,
|
||||||
|
slidesPerView: 1,
|
||||||
|
spaceBetween: 0,
|
||||||
|
// 启用分页指示标(核心配置)
|
||||||
|
pagination: {
|
||||||
|
el: '.swiper-pagination', // 对应 HTML 中的指示标容器
|
||||||
|
clickable: true, // 允许点击指示标切换
|
||||||
|
// dynamicBullets: true, // 动态指示标(当前激活放大)
|
||||||
|
//dynamicMainBullets: 3, // 动态模式显示3个核心指示标
|
||||||
|
},
|
||||||
|
navigation: false,
|
||||||
|
scrollbar: false,
|
||||||
|
on: {
|
||||||
|
resize: function () {
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('resize', function () {
|
||||||
|
swiper.update();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化时触发滚动事件,确保状态正确
|
||||||
|
window.dispatchEvent(new Event('scroll'));
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
{/block}
|
||||||
@@ -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"}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<div class="pageMain">
|
<div class="pageMain">
|
||||||
<!-- banner -->
|
<!-- banner -->
|
||||||
{notempty name="focus_images"}
|
{notempty name="focus_images"}
|
||||||
<div class="swiper-container bannerswiper">
|
<div class="swiper-container bannerswiper" style="background: #fff;">
|
||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper">
|
||||||
{volist name="focus_images" id="focus"}
|
{volist name="focus_images" id="focus"}
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
@@ -117,8 +117,8 @@
|
|||||||
<p class="subtitle" {notempty name="scene.desc_txt_color" }style="color:{$scene.desc_txt_color};" {/notempty}>
|
<p class="subtitle" {notempty name="scene.desc_txt_color" }style="color:{$scene.desc_txt_color};" {/notempty}>
|
||||||
{$scene.desc|raw}</p>
|
{$scene.desc|raw}</p>
|
||||||
<a class="sceneMore" href="{$scene.link}">{:lang_i18n('了解更多')} ></a> -->
|
<a class="sceneMore" href="{$scene.link}">{:lang_i18n('了解更多')} ></a> -->
|
||||||
|
<div style="background-image: url('{$scene.image}');" class="sceneimg"></div>
|
||||||
</a>
|
</a>
|
||||||
<div style="background-image: url('{$scene.image}');" class="sceneimg"></div>
|
|
||||||
</div>
|
</div>
|
||||||
{/volist}
|
{/volist}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="orico_Page_category">
|
<div class="orico_Page_category">
|
||||||
<!-- banner轮播 -->
|
<!-- banner轮播 -->
|
||||||
{notempty name="focus_image"}
|
{notempty name="focus_image"}
|
||||||
<div class="opdBanner">
|
<div class="opdBanner" >
|
||||||
{volist name="focus_image" id="fi"}
|
{volist name="focus_image" id="fi"}
|
||||||
<a {notempty name="fi.link" }href="{$fi.link}" {/notempty}>
|
<a {notempty name="fi.link" }href="{$fi.link}" {/notempty}>
|
||||||
<img src="{$fi.image}" class="opdbannerImg" />
|
<img src="{$fi.image}" class="opdbannerImg" />
|
||||||
|
|||||||
@@ -22,7 +22,11 @@
|
|||||||
<a class="pathname" href="/">{:lang_i18n('首页')}</a>
|
<a class="pathname" href="/">{:lang_i18n('首页')}</a>
|
||||||
{volist name="product_categorys" id="ca"}
|
{volist name="product_categorys" id="ca"}
|
||||||
<div class="arrow"></div>
|
<div class="arrow"></div>
|
||||||
|
{eq name="ca.pid" value="0"}
|
||||||
<a class="pathname" href="{:url('product/category', ['id' => $ca.id])}">{$ca.name}</a>
|
<a class="pathname" href="{:url('product/category', ['id' => $ca.id])}">{$ca.name}</a>
|
||||||
|
{else /}
|
||||||
|
<a class="pathname" href="{:url('product/subcategory', ['id' => $ca.id])}">{$ca.name}</a>
|
||||||
|
{/eq}
|
||||||
{/volist}
|
{/volist}
|
||||||
</div>
|
</div>
|
||||||
<!-- 产品主图切换和参数详情-->
|
<!-- 产品主图切换和参数详情-->
|
||||||
@@ -129,8 +133,10 @@
|
|||||||
{/notempty}
|
{/notempty}
|
||||||
</div>
|
</div>
|
||||||
<!-- 富文本渲染-->
|
<!-- 富文本渲染-->
|
||||||
<div class="products_des" id="detail">
|
<div class="ql-container">
|
||||||
{$product.detail|default=''|raw}
|
<div class="products_des ql-editor" id="detail">
|
||||||
|
{$product.detail|default=''|raw}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 关联产品 -->
|
<!-- 关联产品 -->
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
{else/}
|
{else/}
|
||||||
<a href="javascript:void(0);" class="fline">
|
<a href="javascript:void(0);" class="fline">
|
||||||
{$vo.value}
|
{$vo.value}
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{/volist}
|
{/volist}
|
||||||
|
|||||||
@@ -1,250 +1,763 @@
|
|||||||
<header class="header-PC">
|
<link rel="stylesheet" href="__CSS__/header.css">
|
||||||
<div id="header">
|
<div class="header" >
|
||||||
<!-- LOG -->
|
<!-- 导航外容器:1920px宽,下拉框基于此定位 -->
|
||||||
<div class="nav1">
|
<div class="header-nav-outer" >
|
||||||
<a href="/">
|
<!-- 顶部导航栏 -->
|
||||||
<img src="__IMAGES__/logo.png" />
|
<div class="header-nav-bar">
|
||||||
</a>
|
<div style="display:flex;align-items:center">
|
||||||
</div>
|
<a href="/" style="display:flex;align-items:center">
|
||||||
<!--顶部导航栏 -->
|
<img src="__IMAGES__/logo.png" alt="orico" class="header-log">
|
||||||
<div class="nav2">
|
</a>
|
||||||
<nav id="booNavigation" class="booNavigation">
|
</div>
|
||||||
<ul>
|
<div class="header-nav-items">
|
||||||
{if condition="!empty($header_categorys)"}
|
{if condition="!empty($header_categorys)"}
|
||||||
<li class="navItem">
|
<div class="header-nav-item" >
|
||||||
<a href="javascript:void(0);">{:lang_i18n('产品列表')}</a>
|
<div class="header-nav-title">{:lang_i18n('产品列表')}</div>
|
||||||
<img src="__IMAGES__/black-down.png" class="downimg" />
|
<!-- style=" opacity: 1;" -->
|
||||||
<ol class="navItemConten">
|
<div class="header-dropdown" >
|
||||||
<!-- 左边子菜单-->
|
<div class="header-dropdown-tabs">
|
||||||
<ul class="navItem_cyleft">
|
{volist name="header_categorys" id="vo" key="idx"}
|
||||||
{volist name="header_categorys" id="vo"}
|
<a href="{:url('product/category', ['id' => $vo.id])}" class="header-tab-item {if condition="$idx == 1"}active{/if}" data-tab="tag-{$vo.id}">{$vo.name}</a>
|
||||||
<li class="{$key == 0 ? 'it_active' : ''}">
|
{/volist}
|
||||||
<a href="{:url('product/category', ['id' => $vo.id])}">{$vo.name}</a>
|
</div>
|
||||||
</li>
|
{volist name="header_categorys" id="vo" key="idx"}
|
||||||
{/volist}
|
<div class="header-dropdown-content header-tab-content {if condition="$idx == 1"}active{/if}" id="tag-{$vo.id}">
|
||||||
</ul>
|
<div class="header-dropdown-category">
|
||||||
<!-- 右边子菜单-->
|
{if condition="!empty($vo.children)"}
|
||||||
{volist name="header_categorys" id="vo" key="idx"}
|
{volist name="vo.children" id="vc"}
|
||||||
<div class="navItem_cyright" {eq name="idx" value="1" }style="display: block;"{else/}style="display: none;"{/eq}>
|
<div class="header-category-box">
|
||||||
{if condition="!empty($vo.children)"}
|
{volist name="vc" id="vcc"}
|
||||||
{volist name="vo.children" id="vc"}
|
<div class="header-category-block">
|
||||||
<dl class="nav_cyrightit">
|
<div class="header-category-title">
|
||||||
<dt>
|
<a href="{:url('product/subcategory', ['id' => $vcc.id])}" target="_self">
|
||||||
<a href="{:url('product/subcategory', ['id' => $vc.id])}">{$vc.name}</a>
|
{$vcc.name}
|
||||||
</dt>
|
</a>
|
||||||
{if condition="!empty($vc.children)"}
|
</div>
|
||||||
{volist name="vc.children" id="vcc"}
|
<ul class="header-category-list">
|
||||||
<dd>
|
{if condition="!empty($vcc.children)"}
|
||||||
<a href="{:url('product/subcategory', ['id' => $vcc.id])}">{$vcc.name}</a>
|
{volist name="vcc.children" id="vccc" length="5"}
|
||||||
</dd>
|
<li class="header-category-item">
|
||||||
{/volist}
|
<a href="{:url('product/subcategory', ['id' => $vccc.id])}" target="_self">
|
||||||
{/if}
|
{$vccc.name}
|
||||||
</dl>
|
</a>
|
||||||
{/volist}
|
</li>
|
||||||
{/if}
|
{/volist}
|
||||||
</div>
|
{/if}
|
||||||
{/volist}
|
</ul>
|
||||||
</ol>
|
</div>
|
||||||
</li>
|
{/volist}
|
||||||
{/if}
|
</div>
|
||||||
{volist name="header_navigation" id="vo"}
|
{/volist}
|
||||||
<li class="navItem">
|
{/if}
|
||||||
<a href="{$vo.link}" target="{$vo.blank==1?'_blank':'_self'}">{$vo.name}</a>
|
</div>
|
||||||
{if condition="!empty($vo.children)"}
|
<div class="header-dropdown-products">
|
||||||
<img src="__IMAGES__/black-down.png" class="downimg" />
|
{if condition="!empty($vo.recommends)"}
|
||||||
<!--下拉菜单 -->
|
{volist name="vo.recommends" id="recommend"}
|
||||||
<ol class="navItemConten1">
|
<div class="header-product-card">
|
||||||
{volist name="vo.children" id="voc"}
|
<a href="{$recommend.link}">
|
||||||
<li>
|
<div class="header-product-img">
|
||||||
<a href="{$voc.link}" target="{$voc.blank==1?'_blank':'_self'}">{$voc.name}</a>
|
<img src="{$recommend.image}" alt="">
|
||||||
</li>
|
</div>
|
||||||
{/volist}
|
<div class="header-product-name">{$recommend.title}</div>
|
||||||
</ol>
|
</a>
|
||||||
{/if}
|
</div>
|
||||||
</li>
|
{/volist}
|
||||||
{/volist}
|
{/if}
|
||||||
</ul>
|
</div>
|
||||||
</nav>
|
</div>
|
||||||
</div>
|
{/volist}
|
||||||
<!-- 顶部搜索/国家选择/商店-->
|
</div>
|
||||||
<div class="nav3">
|
</div>
|
||||||
<img src="__IMAGES__/icon-search.png" id="openModalBtn" class="searchimg" />
|
{/if}
|
||||||
<div class="choesCountry">
|
{if condition="!empty($header_navigation)"}
|
||||||
<img src="__IMAGES__/icon-language.png" id="countrycheck" class="checkimg" />
|
{volist name="header_navigation" id="nav"}
|
||||||
<!--国家选择 -->
|
<div class="header-nav-item">
|
||||||
<div class="topCountry" id="top-country">
|
{if condition="empty($nav.children)"}
|
||||||
<ul>
|
<div class="header-nav-title">
|
||||||
<li class="closec">
|
<a href="{$nav.link}" target="{$nav.blank==1?'_blank':'_self'}">{$nav.name}</a>
|
||||||
<span class="closecountrybt">×</span>
|
</div>
|
||||||
</li>
|
{else /}
|
||||||
{volist name="header_languages" id="vo"}
|
<div class="header-nav-title">{$nav.name}</div>
|
||||||
<a href="{$vo.lang_url}">
|
<div class="header-dropdown">
|
||||||
<li>
|
<div class="header-dropdown-content1">
|
||||||
<div class="cico">
|
{volist name="nav.children" id="child"}
|
||||||
<img src="{$vo.lang_icon}" class="countryimg" />
|
<div class="header-product-card-1">
|
||||||
</div>
|
<a href="{$child.link}" target="{$child.blank==1?'_blank':'_self'}">
|
||||||
<p class="countryName">{$vo.country_en_name} - {$vo.lang_en_name}</p>
|
<div class="header-product-img-1">
|
||||||
</li>
|
<img src="{$child.image}" alt="">
|
||||||
</a>
|
</div>
|
||||||
{/volist}
|
<div class="header-product-title-1">{$child.name}</div>
|
||||||
</ul>
|
<div class="header-product-name-1">{$child.desc}</div>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{eq name=":cookie('think_lang')" value="en-us"}
|
{/volist}
|
||||||
{notempty name="basic_config['navigation_store_url']['value']"}
|
</div>
|
||||||
<a class="storetopbt" href="{$basic_config['navigation_store_url']['value']}" target="_blank">
|
</div>
|
||||||
<img src="__IMAGES__/shopico.png" class="storeImgico" />{:lang_i18n('店铺')}
|
{/if}
|
||||||
</a>
|
</div>
|
||||||
{/notempty}
|
{/volist}
|
||||||
{/eq}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<!-- 右侧功能按钮 -->
|
||||||
|
<div class="header-nav-actions">
|
||||||
|
<div class="header-search-wrapper">
|
||||||
|
<span class="header-nav-btn">
|
||||||
|
<img src="__IMAGES__/s1.png" alt="" style="width: 20px;height: 20px;">
|
||||||
|
</span>
|
||||||
|
<div class="header-search-dropdown" id="searchDropdown">
|
||||||
|
<span class="header-search-dropdown-delete-icon">✕</span>
|
||||||
|
<div class="header-search-input-wrapper">
|
||||||
|
<input type="text" class="header-search-input" placeholder="{:lang_i18n('搜索产品、分类...')}">
|
||||||
|
<button class="header-search-submit">{:lang_i18n('搜索')}</button>
|
||||||
|
</div>
|
||||||
|
<div class="header-search-history" id="searchHistory">
|
||||||
|
<div class="header-history-title">
|
||||||
|
<span>{:lang_i18n('最近搜索')}</span>
|
||||||
|
<span class="header-clear-history" id="clearHistory">{:lang_i18n('清空')}</span>
|
||||||
|
</div>
|
||||||
|
<div class="header-history-list" id="historyList"></div>
|
||||||
|
</div>
|
||||||
|
<div class="header-hot-products">
|
||||||
|
<div class="header-hot-title">{:lang_i18n('热销产品')}</div>
|
||||||
|
<div class="header-hot-product-list">
|
||||||
|
{if condition="!empty($header_hot_products)"}
|
||||||
|
{volist name="header_hot_products" id="pro"}
|
||||||
|
<div class="header-hot-product-item" data-keyword="keyword-{$pro.id}">
|
||||||
|
<div class="header-hot-product-img">
|
||||||
|
<a href="{:url('product/detail', ['id' => $pro.id])}">
|
||||||
|
<img src="{:thumb($pro.cover_image)}" alt="">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="header-hot-product-name">{$pro.name}</div>
|
||||||
|
</div>
|
||||||
|
{/volist}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="header-lang-wrapper" >
|
||||||
|
<span class="header-nav-btn">
|
||||||
|
<img src="__IMAGES__/l1.png" alt="" style="width: 20px;height:20px">
|
||||||
|
</span>
|
||||||
|
<div class="header-lang-dropdown" id="langDropdown">
|
||||||
|
<span class="header-lang-dropdown-delete-icon">✕</span>
|
||||||
|
{volist name="header_languages" id="vo"}
|
||||||
|
<a href="{$vo.lang_url}" class="header-lang-item" data-lang="zh-CN" target="_self">
|
||||||
|
<img src="{$vo.lang_icon}" alt="">
|
||||||
|
|
||||||
|
{eq name=":cookie('think_lang')" value="zh-cn"}
|
||||||
|
<span class="header-lang-code">{$vo.country_zh_name}</span>
|
||||||
|
<span class="header-lang-name">{$vo.lang_name}</span>
|
||||||
|
{else}
|
||||||
|
<span class="header-lang-code">{$vo.country_en_name}</span>
|
||||||
|
<span class="header-lang-name-en">{$vo.lang_en_name}</span>
|
||||||
|
{/eq}
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="header-buy-wrapper">
|
||||||
|
<button class="header-buy-btn" style="line-height: 1;">
|
||||||
|
<img src="__IMAGES__/g1.png" alt="" style="margin-right:5px;width: 14px;height: 14px;">
|
||||||
|
|
||||||
|
{:lang_i18n('购买')}
|
||||||
|
</button>
|
||||||
|
<!-- <img src="__IMAGES__/gm.png" alt="" style="margin-right: 3px;"> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 购买下拉框 -->
|
||||||
|
<div class="header-buy-dropdown" id="buyDropdown">
|
||||||
|
<div class="header-buy-dropdown-content">
|
||||||
|
{if condition="!empty($header_mall_entrance)"}
|
||||||
|
{volist name="header_mall_entrance" id="ma"}
|
||||||
|
<a class="header-buy-product-card" target="_self" href="{$ma.link}">
|
||||||
|
<div class="header-buy-product-img">
|
||||||
|
<img class="header-default-img" src="{$ma.image}" alt="{$ma.name}">
|
||||||
|
{if condition="!empty($ma.hover_image)"}
|
||||||
|
<img class="header-hover-img" src="{$ma.hover_image}" alt="{$ma.name}">
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="header-buy-product-title">{$ma.name}</div>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="width: 100vw;height: 64px;"></div>
|
||||||
|
<div id="mhk"></div>
|
||||||
|
|
||||||
<!-- 搜索弹框-->
|
|
||||||
<div class="searchmodalMian" id="scmodal">
|
|
||||||
<div class="searchmodalct">
|
|
||||||
<span class="close-btn">×</span>
|
|
||||||
<input type="text" name="keywords" id="serrchinput" autocomplete="off" />
|
|
||||||
<!-- 历史记录 -->
|
|
||||||
<div class="searchhistory">
|
|
||||||
<p class="h_title">{:lang_i18n('搜索记录')}</p>
|
|
||||||
<ul></ul>
|
|
||||||
</div>
|
|
||||||
<div class="popProduct">
|
|
||||||
<p class="h_title">{:lang_i18n('热销产品')}</p>
|
|
||||||
<div class="popmain">
|
|
||||||
{volist name="header_hot_products" id="vo"}
|
|
||||||
<div class="popitem">
|
|
||||||
<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="produc-dec">{$vo.short_name}</div>
|
|
||||||
</div>
|
|
||||||
{/volist}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
// 获取所有包含商品卡片的元素
|
||||||
// 搜索历史记录处理
|
const productCards = document.querySelectorAll('.header-buy-product-card');
|
||||||
function history(keywords) {
|
|
||||||
var history = localStorage.getItem('header_search_keywords');
|
|
||||||
if (!history) {
|
|
||||||
history = [];
|
|
||||||
} else {
|
|
||||||
history = JSON.parse(history);
|
|
||||||
}
|
|
||||||
// 记录搜索关键词
|
|
||||||
if (keywords) {
|
|
||||||
if (history.includes(keywords)) {
|
|
||||||
history.splice(history.indexOf(keywords), 1);
|
|
||||||
}
|
|
||||||
history.unshift(keywords);
|
|
||||||
if (history.length > 3) {
|
|
||||||
history.pop();
|
|
||||||
}
|
|
||||||
localStorage.setItem('header_search_keywords', JSON.stringify(history));
|
|
||||||
return history;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 回显搜索历史记录
|
productCards.forEach(card => {
|
||||||
history.forEach(function (item) {
|
// 获取卡片内的图片容器和两张图片
|
||||||
$('.searchhistory ul').append('<li><a href="{:url(\'product/search\')}?keywords=' + item + '">' + item + '</a></li>');
|
const imgContainer = card.querySelector('.header-buy-product-img');
|
||||||
});
|
const defaultImg = imgContainer?.querySelector('.header-default-img');
|
||||||
|
const hoverImg = imgContainer?.querySelector('.header-hover-img');
|
||||||
|
|
||||||
return history;
|
// 检查悬浮图是否存在(因为HTML中用了if判断,所以可能有也可能没有这个元素)
|
||||||
}
|
const hasHoverImg = hoverImg !== null;
|
||||||
|
|
||||||
// 封装一个函数用于处理鼠标悬停显示和隐藏内容
|
// 如果没有悬浮图,不需要任何交互,直接返回
|
||||||
function handleHover($element, $content) {
|
if (!hasHoverImg) return;
|
||||||
// 同时支持鼠标悬停和点击事件
|
|
||||||
$element
|
|
||||||
.mouseenter(function () {
|
|
||||||
$content.stop(true, true).slideDown(60);
|
|
||||||
})
|
|
||||||
.mouseleave(function () {
|
|
||||||
$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();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理产品列表的下拉菜单
|
// 初始状态确保普通图显示,悬浮图隐藏
|
||||||
var $firstNav = $('.navItem').eq(0);
|
defaultImg.style.opacity = '1';
|
||||||
if ($firstNav.find('.navItemConten').length) {
|
hoverImg.style.opacity = '0';
|
||||||
handleHover($firstNav, $firstNav.find('.navItemConten'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 鼠标移入左侧子菜单切换显示
|
// 鼠标移入事件:显示悬浮图,隐藏普通图
|
||||||
$('.navItem_cyleft li').mouseenter(function () {
|
card.addEventListener('mouseenter', () => {
|
||||||
$(this).addClass('it_active').siblings().removeClass('it_active');
|
defaultImg.style.opacity = '0';
|
||||||
$('.navItem_cyright').hide();
|
hoverImg.style.opacity = '1';
|
||||||
$('.navItem_cyright').eq($(this).index()).show();
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// 动态处理所有带有navItemConten1的导航项
|
// 鼠标移出事件:恢复普通图,隐藏悬浮图
|
||||||
$('.navItem').each(function () {
|
card.addEventListener('mouseleave', () => {
|
||||||
var $this = $(this);
|
defaultImg.style.opacity = '1';
|
||||||
var $dropdown = $this.find('.navItemConten1');
|
hoverImg.style.opacity = '0';
|
||||||
// 只给有下拉菜单的导航项绑定事件
|
});
|
||||||
if ($dropdown.length) {
|
});
|
||||||
handleHover($this, $dropdown);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 点击搜索
|
// 产品列表在hover复位tabs选择
|
||||||
$('#openModalBtn').click(function () {
|
const productNavContainer = document.querySelector('.header-nav-item:first-child');
|
||||||
$('#scmodal').toggle();
|
|
||||||
});
|
|
||||||
$('.close-btn').click(function () {
|
|
||||||
$('#scmodal').hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 点击空白处关闭下拉菜单
|
if (productNavContainer) {
|
||||||
$(document).click(function () {
|
productNavContainer.addEventListener('mouseleave', () => {
|
||||||
$('.navItemConten, .navItemConten1, #top-country').slideUp(60);
|
// 延迟执行,确保下拉菜单已经隐藏
|
||||||
});
|
setTimeout(() => {
|
||||||
|
const tabs = document.querySelectorAll('.header-tab-item');
|
||||||
|
const contents = document.querySelectorAll('.header-tab-content');
|
||||||
|
|
||||||
// 防止下拉菜单内部点击触发空白处关闭事件
|
// 重置到第一个tab
|
||||||
$('.navItemConten, .navItemConten1, #top-country').click(function (e) {
|
if (tabs.length > 0 && tabs[0]) {
|
||||||
e.stopPropagation();
|
tabs.forEach(tab => tab.classList.remove('active'));
|
||||||
});
|
contents.forEach(content => content.classList.remove('active'));
|
||||||
|
|
||||||
|
tabs[0].classList.add('active');
|
||||||
|
const firstContentId = tabs[0].getAttribute('data-tab');
|
||||||
|
const firstContent = document.getElementById(firstContentId);
|
||||||
|
if (firstContent) firstContent.classList.add('active');
|
||||||
|
}
|
||||||
|
}, 350);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabItems1 = document.querySelectorAll('.header-tab-item');
|
||||||
|
const tabContents = document.querySelectorAll('.header-tab-content');
|
||||||
|
|
||||||
|
tabItems1.forEach(tab => {
|
||||||
|
tab.addEventListener('mouseenter', () => {
|
||||||
|
tabItems1.forEach(item => item.classList.remove('active'));
|
||||||
|
tab.classList.add('active');
|
||||||
|
const tabId = tab.getAttribute('data-tab');
|
||||||
|
tabContents.forEach(content => {
|
||||||
|
content.classList.remove('active');
|
||||||
|
if (content.id === tabId) {
|
||||||
|
content.classList.add('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let searchHistory = JSON.parse(localStorage.getItem('searchHistory') || '[]');
|
||||||
|
|
||||||
|
function renderHistory() {
|
||||||
|
const historyList = document.getElementById('historyList');
|
||||||
|
const historySection = document.getElementById('searchHistory');
|
||||||
|
if (searchHistory.length === 0) {
|
||||||
|
if (historySection) historySection.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (historySection) historySection.style.display = 'block';
|
||||||
|
if (historyList) {
|
||||||
|
historyList.innerHTML = searchHistory.map((item, index) => `
|
||||||
|
<div class="header-history-item" data-keyword="${item}">
|
||||||
|
<span>${item}</span>
|
||||||
|
<span class="header-delete-icon" data-index="${index}">✕</span>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
document.querySelectorAll('.header-history-item').forEach(item => {
|
||||||
|
const keyword = item.getAttribute('data-keyword');
|
||||||
|
const deleteBtn = item.querySelector('.header-delete-icon');
|
||||||
|
item.addEventListener('click', (e) => {
|
||||||
|
if (e.target === deleteBtn) return;
|
||||||
|
performSearch(keyword);
|
||||||
|
});
|
||||||
|
if (deleteBtn) {
|
||||||
|
deleteBtn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const index = parseInt(deleteBtn.getAttribute('data-index'));
|
||||||
|
searchHistory.splice(index, 1);
|
||||||
|
localStorage.setItem('searchHistory', JSON.stringify(searchHistory));
|
||||||
|
renderHistory();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToHistory(keyword) {
|
||||||
|
if (!keyword.trim()) return;
|
||||||
|
searchHistory = searchHistory.filter(item => item !== keyword);
|
||||||
|
searchHistory.unshift(keyword);
|
||||||
|
if (searchHistory.length > 10) searchHistory.pop();
|
||||||
|
localStorage.setItem('searchHistory', JSON.stringify(searchHistory));
|
||||||
|
renderHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearHistoryBtn = document.getElementById('clearHistory');
|
||||||
|
if (clearHistoryBtn) {
|
||||||
|
clearHistoryBtn.addEventListener('click', () => {
|
||||||
|
searchHistory = [];
|
||||||
|
localStorage.setItem('searchHistory', JSON.stringify(searchHistory));
|
||||||
|
renderHistory();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function performSearch(keyword) {
|
||||||
|
if (keyword.trim()) {
|
||||||
|
addToHistory(keyword);
|
||||||
|
window.location.href = "{:url('product/search')}?keywords=" + encodeURIComponent(keyword);
|
||||||
|
if (searchDropdown) searchDropdown.classList.remove('show');
|
||||||
|
if (searchInput) searchInput.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchBtn = document.querySelector('.header-search-wrapper .header-nav-btn');
|
||||||
|
const searchDropdown = document.getElementById('searchDropdown');
|
||||||
|
const searchInput = document.querySelector('.header-search-input');
|
||||||
|
const searchSubmit = document.querySelector('.header-search-submit');
|
||||||
|
const langDropdown = document.getElementById('langDropdown');
|
||||||
|
const buyDropdown = document.getElementById('buyDropdown');
|
||||||
|
const mhk = document.getElementById('mhk');
|
||||||
|
const body = document.body;
|
||||||
|
|
||||||
|
const langCloseBtn = document.querySelector('.header-lang-dropdown-delete-icon');
|
||||||
|
const searchCloseBtn = document.querySelector('.header-search-dropdown-delete-icon');
|
||||||
|
|
||||||
|
// 保存滚动位置
|
||||||
|
let scrollTopPosition = 0;
|
||||||
|
|
||||||
|
// 打开蒙版层(禁止滚动,不抖动)
|
||||||
|
function openOverlay() {
|
||||||
|
if (mhk && mhk.style.display !== 'block') {
|
||||||
|
// 保存当前滚动位置
|
||||||
|
scrollTopPosition = window.pageYOffset || document.documentElement.scrollTop;
|
||||||
|
|
||||||
|
mhk.style.display = 'block';
|
||||||
|
|
||||||
|
// 禁止滚动,保持位置
|
||||||
|
body.style.position = 'fixed';
|
||||||
|
body.style.top = `-${scrollTopPosition}px`;
|
||||||
|
body.style.left = '0';
|
||||||
|
body.style.right = '0';
|
||||||
|
body.style.width = '100%';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭蒙版层(恢复滚动)
|
||||||
|
function closeOverlay() {
|
||||||
|
if (mhk && mhk.style.display === 'block') {
|
||||||
|
const isBuyOpen = buyDropdown && buyDropdown.classList.contains('show');
|
||||||
|
const isSearchOpen = searchDropdown && searchDropdown.classList.contains('show');
|
||||||
|
const isLangOpen = langDropdown && langDropdown.classList.contains('show');
|
||||||
|
|
||||||
|
// 检查是否有任何导航下拉菜单打开
|
||||||
|
let hasNavOpen = false;
|
||||||
|
document.querySelectorAll('.header-dropdown').forEach(dropdown => {
|
||||||
|
const style = window.getComputedStyle(dropdown);
|
||||||
|
if (style.opacity === '1') {
|
||||||
|
hasNavOpen = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isBuyOpen && !isSearchOpen && !isLangOpen && !hasNavOpen) {
|
||||||
|
mhk.style.display = 'none';
|
||||||
|
|
||||||
|
// 恢复滚动
|
||||||
|
body.style.position = '';
|
||||||
|
body.style.top = '';
|
||||||
|
body.style.left = '';
|
||||||
|
body.style.right = '';
|
||||||
|
body.style.width = '';
|
||||||
|
|
||||||
|
// 恢复滚动位置
|
||||||
|
window.scrollTo(0, scrollTopPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== header-dropdown 导航下拉菜单打开时显示蒙版 ==========
|
||||||
|
function initNavDropdownOverlay() {
|
||||||
|
const navItems = document.querySelectorAll('.header-nav-item');
|
||||||
|
let hideTimer = null;
|
||||||
|
|
||||||
|
navItems.forEach(item => {
|
||||||
|
const dropdown = item.querySelector('.header-dropdown');
|
||||||
|
if (!dropdown) return;
|
||||||
|
|
||||||
|
// 鼠标移入导航项
|
||||||
|
item.addEventListener('mouseenter', () => {
|
||||||
|
if (hideTimer) clearTimeout(hideTimer);
|
||||||
|
openOverlay();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标移出导航项
|
||||||
|
item.addEventListener('mouseleave', () => {
|
||||||
|
hideTimer = setTimeout(() => {
|
||||||
|
const isHoveringDropdown = dropdown && dropdown.matches(':hover');
|
||||||
|
if (!isHoveringDropdown) {
|
||||||
|
const isBuyOpen = buyDropdown && buyDropdown.classList.contains('show');
|
||||||
|
const isSearchOpen = searchDropdown && searchDropdown.classList.contains('show');
|
||||||
|
const isLangOpen = langDropdown && langDropdown.classList.contains('show');
|
||||||
|
if (!isBuyOpen && !isSearchOpen && !isLangOpen) {
|
||||||
|
closeOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标移入下拉菜单
|
||||||
|
dropdown.addEventListener('mouseenter', () => {
|
||||||
|
if (hideTimer) clearTimeout(hideTimer);
|
||||||
|
openOverlay();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标移出下拉菜单
|
||||||
|
dropdown.addEventListener('mouseleave', () => {
|
||||||
|
hideTimer = setTimeout(() => {
|
||||||
|
const isHoveringNav = item && item.matches(':hover');
|
||||||
|
if (!isHoveringNav) {
|
||||||
|
const isBuyOpen = buyDropdown && buyDropdown.classList.contains('show');
|
||||||
|
const isSearchOpen = searchDropdown && searchDropdown.classList.contains('show');
|
||||||
|
const isLangOpen = langDropdown && langDropdown.classList.contains('show');
|
||||||
|
if (!isBuyOpen && !isSearchOpen && !isLangOpen) {
|
||||||
|
closeOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭所有导航下拉菜单
|
||||||
|
function closeAllNavDropdowns() {
|
||||||
|
document.querySelectorAll('.header-dropdown').forEach(dropdown => {
|
||||||
|
dropdown.style.opacity = '';
|
||||||
|
dropdown.style.transform = '';
|
||||||
|
dropdown.style.pointerEvents = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 语言关闭按钮
|
||||||
|
if (langCloseBtn) {
|
||||||
|
langCloseBtn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (langDropdown) langDropdown.classList.remove('show');
|
||||||
|
closeOverlay();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索关闭按钮
|
||||||
|
if (searchCloseBtn) {
|
||||||
|
searchCloseBtn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (searchDropdown) searchDropdown.classList.remove('show');
|
||||||
|
closeOverlay();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 鼠标移入导航项时,关闭其他弹窗
|
||||||
|
const navItems = document.querySelectorAll('.header-nav-item');
|
||||||
|
navItems.forEach(item => {
|
||||||
|
item.addEventListener('mouseenter', () => {
|
||||||
|
if (buyDropdown) buyDropdown.classList.remove('show');
|
||||||
|
if (langDropdown) langDropdown.classList.remove('show');
|
||||||
|
if (searchDropdown) searchDropdown.classList.remove('show');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 搜索按钮点击
|
||||||
|
if (searchBtn && searchDropdown) {
|
||||||
|
searchBtn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (langDropdown) langDropdown.classList.remove('show');
|
||||||
|
if (buyDropdown) buyDropdown.classList.remove('show');
|
||||||
|
searchDropdown.classList.toggle('show');
|
||||||
|
if (searchDropdown.classList.contains('show')) {
|
||||||
|
renderHistory();
|
||||||
|
openOverlay();
|
||||||
|
} else {
|
||||||
|
closeOverlay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchSubmit) {
|
||||||
|
searchSubmit.addEventListener('click', () => {
|
||||||
|
performSearch(searchInput.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
performSearch(searchInput.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hotProducts = document.querySelectorAll('.header-hot-product-item');
|
||||||
|
hotProducts.forEach(product => {
|
||||||
|
product.addEventListener('click', () => {
|
||||||
|
const keyword = product.getAttribute('data-keyword');
|
||||||
|
if (keyword) performSearch(keyword);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 语言按钮点击
|
||||||
|
const langBtn = document.querySelector('.header-lang-wrapper .header-nav-btn');
|
||||||
|
if (langBtn && langDropdown) {
|
||||||
|
langBtn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (searchDropdown) searchDropdown.classList.remove('show');
|
||||||
|
if (buyDropdown) buyDropdown.classList.remove('show');
|
||||||
|
langDropdown.classList.toggle('show');
|
||||||
|
if (langDropdown.classList.contains('show')) {
|
||||||
|
openOverlay();
|
||||||
|
} else {
|
||||||
|
closeOverlay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 购买按钮点击
|
||||||
|
const buyWrapper = document.querySelector('.header-buy-wrapper');
|
||||||
|
if (buyWrapper && buyDropdown) {
|
||||||
|
buyWrapper.addEventListener('click', () => {
|
||||||
|
buyDropdown.classList.toggle('show');
|
||||||
|
if (buyDropdown.classList.contains('show')) {
|
||||||
|
openOverlay();
|
||||||
|
} else {
|
||||||
|
closeOverlay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全局点击关闭
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (!e.target.closest('.header-search-wrapper')) {
|
||||||
|
if (searchDropdown) searchDropdown.classList.remove('show');
|
||||||
|
}
|
||||||
|
if (!e.target.closest('.header-lang-wrapper')) {
|
||||||
|
if (langDropdown) langDropdown.classList.remove('show');
|
||||||
|
}
|
||||||
|
if (!e.target.closest('.header-buy-wrapper')) {
|
||||||
|
if (buyDropdown) buyDropdown.classList.remove('show');
|
||||||
|
}
|
||||||
|
// 关闭所有导航下拉菜单
|
||||||
|
if (!e.target.closest('.header-nav-item')) {
|
||||||
|
closeAllNavDropdowns();
|
||||||
|
closeOverlay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 阻止弹窗冒泡
|
||||||
|
if (searchDropdown) searchDropdown.addEventListener('click', (e) => e.stopPropagation());
|
||||||
|
if (langDropdown) langDropdown.addEventListener('click', (e) => e.stopPropagation());
|
||||||
|
if (buyDropdown) buyDropdown.addEventListener('click', (e) => e.stopPropagation());
|
||||||
|
|
||||||
|
// 蒙版层点击关闭
|
||||||
|
if (mhk) {
|
||||||
|
mhk.addEventListener('click', () => {
|
||||||
|
if (searchDropdown) searchDropdown.classList.remove('show');
|
||||||
|
if (langDropdown) langDropdown.classList.remove('show');
|
||||||
|
if (buyDropdown) buyDropdown.classList.remove('show');
|
||||||
|
closeAllNavDropdowns();
|
||||||
|
closeOverlay();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听弹窗状态变化关闭蒙版
|
||||||
|
function setupDropdownObserver(dropdown) {
|
||||||
|
if (!dropdown) return;
|
||||||
|
const observer = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach((mutation) => {
|
||||||
|
if (mutation.attributeName === 'class') {
|
||||||
|
if (!dropdown.classList.contains('show')) {
|
||||||
|
closeOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
observer.observe(dropdown, { attributes: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
setupDropdownObserver(buyDropdown);
|
||||||
|
setupDropdownObserver(searchDropdown);
|
||||||
|
setupDropdownObserver(langDropdown);
|
||||||
|
|
||||||
|
// ========== header-dropdown JS 控制版本(带防抖) ==========
|
||||||
|
function initHeaderDropdown() {
|
||||||
|
const navItems = document.querySelectorAll('.header-nav-item');
|
||||||
|
let hoverTimer = null;
|
||||||
|
let leaveTimer = null;
|
||||||
|
let currentOpenDropdown = null;
|
||||||
|
|
||||||
|
// 获取所有下拉菜单并设置初始状态
|
||||||
|
const allDropdowns = document.querySelectorAll('.header-dropdown');
|
||||||
|
allDropdowns.forEach(dropdown => {
|
||||||
|
dropdown.style.opacity = '0';
|
||||||
|
dropdown.style.transform = 'translateY(-1.25em)';
|
||||||
|
dropdown.style.pointerEvents = 'none';
|
||||||
|
dropdown.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示下拉菜单
|
||||||
|
function showDropdown(dropdown) {
|
||||||
|
if (!dropdown) return;
|
||||||
|
// 关闭当前打开的
|
||||||
|
if (currentOpenDropdown && currentOpenDropdown !== dropdown) {
|
||||||
|
hideDropdown(currentOpenDropdown);
|
||||||
|
}
|
||||||
|
dropdown.style.opacity = '1';
|
||||||
|
dropdown.style.transform = 'translateY(0)';
|
||||||
|
dropdown.style.pointerEvents = 'auto';
|
||||||
|
currentOpenDropdown = dropdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏下拉菜单
|
||||||
|
function hideDropdown(dropdown) {
|
||||||
|
if (!dropdown) return;
|
||||||
|
dropdown.style.opacity = '0';
|
||||||
|
dropdown.style.transform = 'translateY(-1.25em)';
|
||||||
|
dropdown.style.pointerEvents = 'none';
|
||||||
|
if (currentOpenDropdown === dropdown) {
|
||||||
|
currentOpenDropdown = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏所有下拉菜单
|
||||||
|
function hideAllDropdowns() {
|
||||||
|
allDropdowns.forEach(dropdown => {
|
||||||
|
dropdown.style.opacity = '0';
|
||||||
|
dropdown.style.transform = 'translateY(-1.25em)';
|
||||||
|
dropdown.style.pointerEvents = 'none';
|
||||||
|
});
|
||||||
|
currentOpenDropdown = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
navItems.forEach(item => {
|
||||||
|
const dropdown = item.querySelector('.header-dropdown');
|
||||||
|
if (!dropdown) return;
|
||||||
|
|
||||||
|
// 鼠标移入导航项
|
||||||
|
item.addEventListener('mouseenter', () => {
|
||||||
|
// 清除离开定时器
|
||||||
|
if (leaveTimer) clearTimeout(leaveTimer);
|
||||||
|
if (hoverTimer) clearTimeout(hoverTimer);
|
||||||
|
|
||||||
|
// 防抖:延迟100ms再显示,避免频繁触发
|
||||||
|
hoverTimer = setTimeout(() => {
|
||||||
|
// 关闭其他弹窗(搜索、语言、购买)
|
||||||
|
if (searchDropdown) searchDropdown.classList.remove('show');
|
||||||
|
if (langDropdown) langDropdown.classList.remove('show');
|
||||||
|
if (buyDropdown) buyDropdown.classList.remove('show');
|
||||||
|
|
||||||
|
showDropdown(dropdown);
|
||||||
|
// 打开蒙版层
|
||||||
|
if (typeof openOverlay === 'function') openOverlay();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标移出导航项
|
||||||
|
item.addEventListener('mouseleave', () => {
|
||||||
|
// 清除移入定时器
|
||||||
|
if (hoverTimer) clearTimeout(hoverTimer);
|
||||||
|
|
||||||
|
// 延迟300ms再隐藏,给用户移动到下拉菜单的时间
|
||||||
|
leaveTimer = setTimeout(() => {
|
||||||
|
// 检查鼠标是否在下拉菜单上
|
||||||
|
const isHoveringDropdown = dropdown.matches(':hover');
|
||||||
|
if (!isHoveringDropdown) {
|
||||||
|
hideDropdown(dropdown);
|
||||||
|
// 关闭蒙版层
|
||||||
|
if (typeof closeOverlay === 'function') closeOverlay();
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标移入下拉菜单
|
||||||
|
dropdown.addEventListener('mouseenter', () => {
|
||||||
|
if (leaveTimer) clearTimeout(leaveTimer);
|
||||||
|
showDropdown(dropdown);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标移出下拉菜单
|
||||||
|
dropdown.addEventListener('mouseleave', () => {
|
||||||
|
leaveTimer = setTimeout(() => {
|
||||||
|
const isHoveringNav = item.matches(':hover');
|
||||||
|
if (!isHoveringNav) {
|
||||||
|
hideDropdown(dropdown);
|
||||||
|
// 关闭蒙版层
|
||||||
|
if (typeof closeOverlay === 'function') closeOverlay();
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 点击其他地方关闭所有下拉菜单
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (!e.target.closest('.header-nav-item')) {
|
||||||
|
hideAllDropdowns();
|
||||||
|
if (typeof closeOverlay === 'function') closeOverlay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 暴露方法供外部调用
|
||||||
|
window.headerDropdown = {
|
||||||
|
hideAll: hideAllDropdowns,
|
||||||
|
show: showDropdown,
|
||||||
|
hide: hideDropdown
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化(在 DOM 加载完成后执行)
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', initHeaderDropdown);
|
||||||
|
} else {
|
||||||
|
initHeaderDropdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 页面卸载时恢复滚动
|
||||||
|
window.addEventListener('beforeunload', () => {
|
||||||
|
if (body) {
|
||||||
|
body.style.position = '';
|
||||||
|
body.style.top = '';
|
||||||
|
body.style.left = '';
|
||||||
|
body.style.right = '';
|
||||||
|
body.style.width = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化导航下拉菜单蒙版层
|
||||||
|
initNavDropdownOverlay();
|
||||||
|
|
||||||
|
// 初始化渲染
|
||||||
|
renderHistory();
|
||||||
|
closeOverlay();
|
||||||
|
|
||||||
// 搜索历史记录回显
|
|
||||||
history();
|
|
||||||
|
|
||||||
// 执行搜索
|
|
||||||
$('#serrchinput').keydown(function (event) {
|
|
||||||
if (event.originalEvent.keyCode == 13) {
|
|
||||||
var keywords = $(this).val();
|
|
||||||
if (keywords == '') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// 记录搜索关键词
|
|
||||||
history(keywords);
|
|
||||||
|
|
||||||
// 跳转到搜索页面
|
|
||||||
window.location.href = "{:url('product/search')}" + '?keywords=' + keywords;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 点击选择国家
|
|
||||||
$('#countrycheck').click(function (e) {
|
|
||||||
$('#top-country').toggle();
|
|
||||||
e.stopPropagation();
|
|
||||||
});
|
|
||||||
$('.closecountrybt').click(function () {
|
|
||||||
$('#top-country').hide();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
1499
app/index/view/pc/topic_laptop/index.html
Normal file
1499
app/index/view/pc/topic_laptop/index.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -32,7 +32,7 @@
|
|||||||
</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}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{extend name="public/nas_base" /}
|
{extend name="public/nas_base" /}
|
||||||
{block name="title"}
|
{block name="title"}
|
||||||
{notempty name="article.seo_title"}<title>{$article.seo_title}</title>{else /}{__BLOCK__}{/notempty}
|
{notempty name="article.seo_title"}<title>{$article.seo_title}</title>{else /}{__BLOCK__}{/notempty}
|
||||||
{/block}
|
{/block}
|
||||||
{block name="seo"}
|
{block name="seo"}
|
||||||
{notempty name="article.seo_keywords"}
|
{notempty name="article.seo_keywords"}
|
||||||
<meta name="keywords" content="{$article.seo_keywords}" />
|
<meta name="keywords" content="{$article.seo_keywords}" />
|
||||||
<meta name="description" content="{$article.seo_desc}" />
|
<meta name="description" content="{$article.seo_desc}" />
|
||||||
{else /}
|
{else /}
|
||||||
{__BLOCK__}
|
{__BLOCK__}
|
||||||
{/notempty}
|
{/notempty}
|
||||||
{/block}
|
{/block}
|
||||||
{block name="style"}
|
{block name="style"}
|
||||||
<link rel="stylesheet" href="__CSS__/topic_nas_help-detail.css"/>
|
<link rel="stylesheet" href="__CSS__/topic_nas_help-detail.css" />
|
||||||
{/block}
|
{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<div class="orico_Page_index">
|
<div class="orico_Page_index">
|
||||||
@@ -32,28 +32,42 @@
|
|||||||
<div class="nars-hlpdt-ml">
|
<div class="nars-hlpdt-ml">
|
||||||
{notempty name="article_categorys"}
|
{notempty name="article_categorys"}
|
||||||
<div class="nav-tree">
|
<div class="nav-tree">
|
||||||
|
|
||||||
|
<!-- start 三级菜单 -->
|
||||||
{volist name="article_categorys" id="ac"}
|
{volist name="article_categorys" id="ac"}
|
||||||
<div class="category">
|
<div class="category">
|
||||||
|
<!-- 一级 -->
|
||||||
<div class="category-title">
|
<div class="category-title">
|
||||||
<div class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}">
|
<div class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}"><img src="__IMAGES__/nas-jt.png" class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}" /></div>
|
||||||
<img src="__IMAGES__/nas-jt.png" class="arrow {if condition='$ac.id == $Request.get.cid'}rotate{/if}" />
|
|
||||||
</div>
|
|
||||||
<span>{$ac.name}</span>
|
<span>{$ac.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<ul class="sub-list" {if condition='$ac.id == $Request.get.cid'}style="display: block;"{/if}>
|
<!-- 二级-->
|
||||||
{volist name="ac.article" id="ar"}
|
<ul class="sub-list" {if condition='$ac.id == $Request.get.cid' }style="display: block;" {/if}>
|
||||||
<li>
|
{volist name="ac.child" id="ad"}
|
||||||
<a
|
<li class="two-mues">
|
||||||
href="{:url('/index/topic/nas/help_detail', ['cid' => $ac.id, 'id' => $ar.id])}"
|
<a href="#" class="two-a">
|
||||||
{eq name="ar.id" value="$Request.get.id"}class="active"{/eq}
|
<div class="arrow {if condition='$ad.id == $Request.get.pid'}rotate{/if}"><img src="__IMAGES__/nas-jt.png" class="arrow {if condition='$ad.id == $Request.get.pid'}rotate{/if}" /></div>
|
||||||
>
|
<span>{$ad.name}</span>
|
||||||
{$ar.title}
|
|
||||||
</a>
|
</a>
|
||||||
|
<ul class="thress-mues" {if condition='$ad.id == $Request.get.pid' }style="display: block;" {/if}>
|
||||||
|
{volist name="ad.article" id="ae"}
|
||||||
|
<li 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>
|
||||||
@@ -75,10 +89,22 @@
|
|||||||
{block name="script"}
|
{block name="script"}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
// 一级菜单点击事件
|
||||||
$('.category-title').click(function () {
|
$('.category-title').click(function () {
|
||||||
$(this).next('.sub-list').slideToggle();
|
$(this).next('.sub-list').slideToggle();
|
||||||
$(this).find('.arrow').toggleClass('rotate');
|
$(this).find('.arrow').toggleClass('rotate');
|
||||||
});
|
});
|
||||||
|
// 二级菜单点击事件
|
||||||
|
$('.two-a').click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation(); // 阻止事件冒泡
|
||||||
|
|
||||||
|
// 切换当前二级菜单的箭头方向
|
||||||
|
$(this).find('.arrow').toggleClass('rotate');
|
||||||
|
|
||||||
|
// 切换对应的三级菜单显示/隐藏
|
||||||
|
$(this).siblings('.thress-mues').slideToggle();
|
||||||
|
});
|
||||||
// 搜索
|
// 搜索
|
||||||
$(document).on('click', function (e) {
|
$(document).on('click', function (e) {
|
||||||
var target = $(e.target);
|
var target = $(e.target);
|
||||||
@@ -109,7 +135,7 @@
|
|||||||
html = '<ul>'
|
html = '<ul>'
|
||||||
$.each(r.data, function (k, v) {
|
$.each(r.data, function (k, v) {
|
||||||
html +=
|
html +=
|
||||||
'<li><a href="{:url(\'/index/topic/nas/help_detail\')}?cid=' + v.category_id + '&id=' + v.id + '">' + v.title + '</a></li>'
|
'<li><a href="{:url(\'/index/topic/nas/help_detail\')}?cid=' + v.category_id + '&id=' + v.id + '&pid=' + v.pid + '">' + v.title + '</a></li>'
|
||||||
})
|
})
|
||||||
html += '</ul>'
|
html += '</ul>'
|
||||||
}
|
}
|
||||||
|
|||||||
573
app/index/view/pc/topic_power_prodline/index.html
Normal file
573
app/index/view/pc/topic_power_prodline/index.html
Normal file
@@ -0,0 +1,573 @@
|
|||||||
|
{extend name="public/base" /}
|
||||||
|
{block name="style"}
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/index.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/swiper.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/nav.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/advantage.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/mask.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/product.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/product_list.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/product_card.css">
|
||||||
|
<link rel="stylesheet" href="__CSS__/topic_power_prodline/footer.css">
|
||||||
|
{/block}
|
||||||
|
{block name="main"}
|
||||||
|
<!-- 轮播核心容器 -->
|
||||||
|
<div class="swiper-container auto-swiper-container">
|
||||||
|
{notempty name="data.focus_image"}
|
||||||
|
<div class="swiper-wrapper">
|
||||||
|
{volist name="data.focus_image" id="fo"}
|
||||||
|
<a class="swiper-slide auto-swiper-slide" href="{$fo.link}">
|
||||||
|
<img src="{$fo.image}" alt="{$fo.title}" />
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
<div class="swiper-pagination"></div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
<!-- 分类 -->
|
||||||
|
{notempty name="data.category"}
|
||||||
|
<div class="nav-box">
|
||||||
|
{volist name="data.category" id="ca"}
|
||||||
|
<a class="nav-item" href="{$ca.link}">
|
||||||
|
<img src="{$ca.image}" alt="{$ca.title}">
|
||||||
|
<p {:style(['color'=>$ca.title_txt_color])}>{$ca.title}</p>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 500万 -->
|
||||||
|
{notempty name="data.why_choose"}
|
||||||
|
<div class="advantage-section">
|
||||||
|
{assign name="why_choose_title" value=":array_shift($data.why_choose)" /}
|
||||||
|
<h2 class="advantage-section__title">{$why_choose_title.title|default=''|raw}</h2>
|
||||||
|
<div class="advantage-section__list">
|
||||||
|
{volist name="data.why_choose" id="ch"}
|
||||||
|
<div class="advantage-card-wrap">
|
||||||
|
<div class="advantage-card" data-target="design">
|
||||||
|
<img src="{$ch.image}" alt="{$ch.title}:{$ch.short_title}" class="advantage-card__img">
|
||||||
|
<div class="advantage-card__content">
|
||||||
|
<!-- 标题+箭头容器:水平+垂直双居中,内部文字左、箭头右 -->
|
||||||
|
<div class="advantage-card__heading-wrap">
|
||||||
|
<div class="advantage-card__heading" {:style(['color'=>$ch.title_txt_color])}>{$ch.title}</div>
|
||||||
|
<img src="__IMAGES__/jiant.png" alt="" class="card-arrow">
|
||||||
|
</div>
|
||||||
|
<div class="advantage-card__description" {:style(['color'=>$ch.short_title_txt_color])}>{$ch.short_title}</div>
|
||||||
|
<div style="display:none;" class="mack-conten-text">{$ch.desc|raw}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 产品差旅充 -->
|
||||||
|
{notempty name="data.travel_charger"}
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="tc_title" value=":array_shift($data.travel_charger)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$tc_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$tc_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
<div class="product-container" >
|
||||||
|
{assign name="tc_first_section_lf" value=":array_shift($data.travel_charger)" /}
|
||||||
|
{notempty name="tc_first_section_lf"}
|
||||||
|
<a class="product-left" href="{$tc_first_section_lf.link}">
|
||||||
|
<img src="{$tc_first_section_lf.image}" alt="{$tc_first_section_lf.title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸统一,定位不同 -->
|
||||||
|
<div class="product-img-hover product-img-1">
|
||||||
|
<img src="{$tc_first_section_lf.extra_image}" alt="{$tc_first_section_lf.short_title}">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="tc_first_section_lr" value=":array_shift($data.travel_charger)" /}
|
||||||
|
{notempty name="tc_first_section_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$tc_first_section_lr.image}" alt="{$tc_first_section_lr.title}" class="right-content right-img">
|
||||||
|
<video src="{$tc_first_section_lr.video}" class="right-content right-video" muted loop playsinline controls>
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{assign name="tc_second_section" value=":array_splice($data.travel_charger, 0, 4)" /}
|
||||||
|
{notempty name="tc_second_section"}
|
||||||
|
<div class="product-card-box">
|
||||||
|
<div class="product-card-container">
|
||||||
|
{volist name="tc_second_section" id="tss"}
|
||||||
|
<a class="product-card-wrap" href="{$tss.link}">
|
||||||
|
<div class="product-card" >
|
||||||
|
<div class="product-card-img">
|
||||||
|
<img src="{$tss.image}" alt="{$tss.title}">
|
||||||
|
</div>
|
||||||
|
<div class="product-card-text">
|
||||||
|
<div class="product-card-title" {:style(['color'=>$tss.title_txt_color])}>{$tss.title}</div>
|
||||||
|
<div class="product-card-desc" {:style(['color'=>$tss.short_title_txt_color])}>{$tss.short_title}</div>
|
||||||
|
</div>
|
||||||
|
<div class="product-card-link">
|
||||||
|
<img src="__IMAGES__/ljgd.png" alt="查看更多">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{assign name="tc_three_section" value=":array_shift($data.travel_charger)" /}
|
||||||
|
{notempty name="tc_three_section"}
|
||||||
|
<a href="{$tc_three_section.link}" class="more">
|
||||||
|
<div class="more-img">
|
||||||
|
{$tc_three_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 产品 家居充-->
|
||||||
|
{notempty name="data.home_charger"}
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="hc_title" value=":array_shift($data.home_charger)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$hc_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$hc_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
<div class="product-container">
|
||||||
|
{assign name="hc_first_section_lf" value=":array_shift($data.home_charger)" /}
|
||||||
|
{notempty name="hc_first_section_lf"}
|
||||||
|
<a class="product-left" href="{$hc_first_section_lf.link}">
|
||||||
|
<img src="{$hc_first_section_lf.image}" alt="{$hc_first_section_lf.title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸统一,定位不同 -->
|
||||||
|
<div class="product-img-hover product-img-1">
|
||||||
|
<img src="{$hc_first_section_lf.extra_image}" alt="{$hc_first_section_lf.short_title}">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="hc_first_section_lr" value=":array_shift($data.home_charger)" /}
|
||||||
|
{notempty name="hc_first_section_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$hc_first_section_lr.image}" alt="{$hc_first_section_lr.title}" class="right-content right-img">
|
||||||
|
<video src="{$hc_first_section_lr.video}" class="right-content right-video" muted loop playsinline controls>
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{assign name="hc_second_section" value=":array_splice($data.home_charger, 0, 4)" /}
|
||||||
|
{notempty name="hc_second_section"}
|
||||||
|
<div class="product-card-box">
|
||||||
|
<div class="product-card-container">
|
||||||
|
{volist name="hc_second_section" id="hcs"}
|
||||||
|
<a class="product-card-wrap" href="{$hcs.link}">
|
||||||
|
<div class="product-card" href="#">
|
||||||
|
<div class="product-card-img">
|
||||||
|
<img src="{$hcs.image}" alt="{$hcs.short_title}">
|
||||||
|
</div>
|
||||||
|
<div class="product-card-text">
|
||||||
|
<div class="product-card-title">{$hcs.title}</div>
|
||||||
|
<div class="product-card-desc">{$hcs.short_title}</div>
|
||||||
|
</div>
|
||||||
|
<div class="product-card-link">
|
||||||
|
<img src="__IMAGES__/ljgd.png" alt="查看更多">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="hc_three_section" value=":array_shift($data.home_charger)" /}
|
||||||
|
{notempty name="hc_three_section"}
|
||||||
|
<a href="{$hc_three_section.link}" class="more">
|
||||||
|
<div class="more-img">
|
||||||
|
{$hc_three_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 产品 桌面充(悬浮图上右超出)底部列表样式不一样(左文右图) -->
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="dc_title" value=":array_shift($data.desktop_charger)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$dc_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$dc_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
<div class="product-container">
|
||||||
|
{assign name="dc_first_section_lf" value=":array_shift($data.desktop_charger)" /}
|
||||||
|
{notempty name="dc_first_section_lf"}
|
||||||
|
<a class="product-left" href="{$dc_first_section_lf.link}">
|
||||||
|
<img src="{$dc_first_section_lf.image}" alt="{$dc_first_section_lf.short_title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸和第一个完全一致,仅定位不同 -->
|
||||||
|
<div class="product-img-hover product-img-2" >
|
||||||
|
<img src="{$dc_first_section_lf.extra_image}" alt="{$dc_first_section_lf.short_title}">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="dc_first_section_lr" value=":array_shift($data.desktop_charger)" /}
|
||||||
|
{notempty name="dc_first_section_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$dc_first_section_lr.image}"
|
||||||
|
alt="使用场景" class="right-content right-img">
|
||||||
|
<!--muted loop playsinline controls-->
|
||||||
|
<video
|
||||||
|
src="{$dc_first_section_lr.video}"
|
||||||
|
class="right-content right-video" muted loop playsinline controls>
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{assign name="dc_second_section" value=":array_splice($data.desktop_charger, 0, 2)" /}
|
||||||
|
{notempty name="dc_second_section"}
|
||||||
|
<div class="product-card-box">
|
||||||
|
<div class="product-card-container2">
|
||||||
|
{volist name="dc_second_section" id="dcs"}
|
||||||
|
<a class="product-card2" href="{$dcs.link}">
|
||||||
|
<div class="product-text2">
|
||||||
|
<!-- 新增内部容器,确保所有内容左对齐一致性 -->
|
||||||
|
<div class="product-text-content2">
|
||||||
|
<div class="product-card-title2">{$dcs.title}</div> <!-- 测试超出一行省略 -->
|
||||||
|
<div class="product-card-desc2">{$dcs.short_title}</div> <!-- 测试超出2行省略 -->
|
||||||
|
<div class="product-card-link2">
|
||||||
|
<img src="__IMAGES__/ljgd.png" alt="了解更多">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="product-card-img2">
|
||||||
|
<img src="{$dcs.image}" alt="{$dcs.title}">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/volist}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="dc_three_section" value=":array_shift($data.desktop_charger)" /}
|
||||||
|
{notempty name="dc_three_section"}
|
||||||
|
<a href="{$dc_three_section.link}" class="more">
|
||||||
|
<div class="more-img">
|
||||||
|
{$dc_three_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
<!-- 墙插 -->
|
||||||
|
{notempty name="data.wall_charger"}
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="wc_title" value=":array_shift($data.wall_charger)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$wc_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$wc_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
<div class="product-container">
|
||||||
|
{assign name="wc_first_section_lf" value=":array_shift($data.wall_charger)" /}
|
||||||
|
{notempty name="wc_first_section_lf"}
|
||||||
|
<a class="product-left" href="{$wc_first_section_lf.link}">
|
||||||
|
<img src="{$wc_first_section_lf.image}" alt="{$wc_first_section_lf.title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸统一,定位不同 -->
|
||||||
|
<div class="product-img-hover product-img-1">
|
||||||
|
<img src="{$wc_first_section_lf.extra_image}" alt="{$wc_first_section_lf.title}">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="wc_first_section_lr" value=":array_shift($data.wall_charger)" /}
|
||||||
|
{notempty name="wc_first_section_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$wc_first_section_lr.image}" alt="{$wc_first_section_lr.title}" class="right-content right-img">
|
||||||
|
<video src="{$wc_first_section_lr.video}" class="right-content right-video" muted loop playsinline controls>
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{assign name="wc_more_section" value=":array_shift($data.wall_charger)" /}
|
||||||
|
{notempty name="wc_more_section"}
|
||||||
|
<a href="{$wc_more_section.link}" class="more">
|
||||||
|
<div class="more-img">
|
||||||
|
{$wc_more_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
{notempty name="data.converter"}
|
||||||
|
<!-- 转换器 -->
|
||||||
|
<div class="product-box">
|
||||||
|
{assign name="ct_title" value=":array_shift($data.converter)" /}
|
||||||
|
<div class="product-title">
|
||||||
|
<h2 class="product-title-h2">{$ct_title.title|default=''}</h2>
|
||||||
|
<p class="product-title-p">{$ct_title.short_title|default=''}</p>
|
||||||
|
</div>
|
||||||
|
{assign name="ct_more_section" value=":array_pop($data.converter)" /}
|
||||||
|
{assign name="ct_chunk_section" value=":array_chunk($data.converter, 2)" /}
|
||||||
|
{assign name="ct_chunk_section_len" value=":count($ct_chunk_section)" /}
|
||||||
|
{volist name="ct_chunk_section" id="cts" key="k"}
|
||||||
|
<div class="product-container">
|
||||||
|
{assign name="cts_lf" value=":array_shift($cts)" /}
|
||||||
|
{notempty name="cts_lf"}
|
||||||
|
<a class="product-left" href="{$cts_lf.link}">
|
||||||
|
<img src="{$cts_lf.image}" alt="{$cts_lf.title}" class="product-img">
|
||||||
|
<!-- 公共类+定位类:尺寸统一,定位不同 -->
|
||||||
|
<!--style="display:flex;justify-content: center;"-->
|
||||||
|
<div class="product-img-hover product-img-1" >
|
||||||
|
<!-- style="width:70%"-->
|
||||||
|
<img src="{$cts_lf.extra_image}" alt="{$cts_lf.title}">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
{assign name="cts_lr" value=":array_shift($cts)" /}
|
||||||
|
{notempty name="cts_lr"}
|
||||||
|
<div class="product-right">
|
||||||
|
<img src="{$cts_lr.image}" alt="{$cts_lr.title}" class="right-content right-img">
|
||||||
|
<video src="{$cts_lr.video}" class="right-content right-video" muted loop playsinline controls>
|
||||||
|
您的浏览器不支持HTML5视频播放,请升级浏览器
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{neq name="k" value="$ct_chunk_section_len"}
|
||||||
|
<div class="line"></div>
|
||||||
|
{/neq}
|
||||||
|
{/volist}
|
||||||
|
{notempty name="ct_more_section"}
|
||||||
|
<a href="{$ct_more_section.link}" class="more" style="padding: clamp(1.5rem, 3vw, 3rem) 0">
|
||||||
|
<div class="more-img">
|
||||||
|
{$ct_more_section.title}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/notempty}
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
{notempty name="data.footer_info"}
|
||||||
|
<!-- 底部 -->
|
||||||
|
<div class="prodline-footer-box">
|
||||||
|
<div class="prodline-footer-box-img">
|
||||||
|
<img src="{$data.footer_info.0.image}" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/notempty}
|
||||||
|
<!-- 蒙版 -->
|
||||||
|
<div class="mask" id="mask">
|
||||||
|
<div class="mask-content" >
|
||||||
|
<span class="close-btn">×</span>
|
||||||
|
<div class="mask-scroll-content"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/block}
|
||||||
|
{block name="script"}
|
||||||
|
<script type="text/javascript">
|
||||||
|
let swiper=null;
|
||||||
|
const advantageItems = document.querySelectorAll('.advantage-card');
|
||||||
|
let scrollTop = 0; // 保存页面滚动位置
|
||||||
|
let closeBtnHtml = null; // 关闭按钮元素(全局变量,避免重复创建)
|
||||||
|
const mask = document.getElementById('mask');
|
||||||
|
const maskContent = document.querySelector('.mask-content');
|
||||||
|
const maskScrollContent = document.querySelector('.mask-scroll-content'); // 滚动容器(关键!)
|
||||||
|
const closeBtn = document.querySelector('.close-btn')
|
||||||
|
// 初始化:确保 maskScrollContent 存在于 maskContent 中(避免被清空)
|
||||||
|
if (!maskScrollContent) {
|
||||||
|
// 如果页面没有 mask-scroll-content,动态创建(确保结构稳定)
|
||||||
|
const scrollContent = document.createElement('div');
|
||||||
|
scrollContent.className = 'mask-scroll-content';
|
||||||
|
maskContent.appendChild(scrollContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createCloseBtn() {
|
||||||
|
if (closeBtnHtml) {
|
||||||
|
closeBtnHtml.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
closeBtnHtml = document.createElement('span');
|
||||||
|
closeBtnHtml.className = 'close-btn';
|
||||||
|
closeBtnHtml.innerHTML = '×';
|
||||||
|
|
||||||
|
closeBtnHtml.addEventListener('click', hideMask);
|
||||||
|
|
||||||
|
// 挂载到 maskContent(而非 scrollContent),避免被滚动影响位置
|
||||||
|
maskContent.prepend(closeBtnHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMask(contentHtml) {
|
||||||
|
// 保存页面滚动位置
|
||||||
|
scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
|
||||||
|
|
||||||
|
// 关键:将内容填充到 scrollContent 中(而非直接替换 maskContent)
|
||||||
|
maskScrollContent.innerHTML = contentHtml;
|
||||||
|
createCloseBtn();
|
||||||
|
|
||||||
|
// 显示蒙版
|
||||||
|
mask.style.display = 'flex';
|
||||||
|
|
||||||
|
// 禁止滚动(复用你的逻辑)
|
||||||
|
document.documentElement.classList.add('no-scroll');
|
||||||
|
document.body.classList.add('no-scroll');
|
||||||
|
document.body.style.top = `-${scrollTop}px`;
|
||||||
|
|
||||||
|
// 额外:打开蒙版时就重置滚动位置(避免残留上次滚动状态)
|
||||||
|
maskScrollContent.scrollTop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideMask() {
|
||||||
|
// 关键步骤 1:先重置 scrollContent 的滚动位置(此时元素还未被销毁)
|
||||||
|
maskScrollContent.scrollTop = 0;
|
||||||
|
|
||||||
|
// 关键步骤 2:清空 scrollContent 的内容(而非 maskContent)
|
||||||
|
maskScrollContent.innerHTML = "";
|
||||||
|
|
||||||
|
// 隐藏蒙版
|
||||||
|
mask.style.display = 'none';
|
||||||
|
|
||||||
|
// 恢复滚动(复用你的逻辑)
|
||||||
|
document.documentElement.classList.remove('no-scroll');
|
||||||
|
document.body.classList.remove('no-scroll');
|
||||||
|
document.body.style.top = '';
|
||||||
|
|
||||||
|
// 还原页面滚动位置
|
||||||
|
window.scrollTo(0, scrollTop);
|
||||||
|
|
||||||
|
// 移除关闭按钮(可选,避免残留)
|
||||||
|
if (closeBtnHtml) {
|
||||||
|
closeBtnHtml.remove();
|
||||||
|
closeBtnHtml = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 点击卡片显示详情
|
||||||
|
advantageItems.forEach((item) => {
|
||||||
|
item.addEventListener('click', (e) => {
|
||||||
|
// 获取当前点击卡片内的.mack-conten-text元素
|
||||||
|
const currentMackContent = e.currentTarget.querySelector('.mack-conten-text');
|
||||||
|
if (currentMackContent) {
|
||||||
|
// 关键修改:获取该元素的子内容(innerHTML 本身就是内部HTML,不含当前元素标签)
|
||||||
|
// 若想更彻底,可遍历子节点拼接内容(兼容特殊场景)
|
||||||
|
let contentHtml = '';
|
||||||
|
Array.from(currentMackContent.childNodes).forEach(child => {
|
||||||
|
// 只保留元素节点和文本节点(过滤空节点)
|
||||||
|
if (child.nodeType === 1 || child.nodeType === 3) {
|
||||||
|
contentHtml += child.outerHTML || child.textContent;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 显示蒙版并传入纯净的子内容
|
||||||
|
showMask(contentHtml);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 关闭按钮事件
|
||||||
|
closeBtn.addEventListener('click', hideMask);
|
||||||
|
// 点击蒙版背景关闭(可选)
|
||||||
|
mask.addEventListener('click', (e) => {
|
||||||
|
if (e.target === mask) hideMask();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ESC 键关闭(可选)
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape' && mask.style.display === 'flex') hideMask();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 关键:拦截蒙版的 touchmove 事件,阻止滚动穿透(移动端核心)
|
||||||
|
mask.addEventListener(
|
||||||
|
'touchmove',
|
||||||
|
(e) => {
|
||||||
|
// 只有点击蒙版背景(不是内容区域)才阻止滚动
|
||||||
|
if (e.target === mask) {
|
||||||
|
e.preventDefault(); // 阻止默认触摸滚动行为
|
||||||
|
e.stopPropagation(); // 阻止事件冒泡
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ passive: false }
|
||||||
|
); // passive: false 必须,否则 preventDefault 无效
|
||||||
|
|
||||||
|
const allVideos = document.querySelectorAll('.right-video');
|
||||||
|
// 停止所有视频播放
|
||||||
|
function stopAllVideos() {
|
||||||
|
allVideos.forEach((video) => {
|
||||||
|
video.pause();
|
||||||
|
video.style.display = 'none';
|
||||||
|
// 显示对应图片
|
||||||
|
const img = video.parentElement.querySelector('.right-img');
|
||||||
|
if (img) img.style.display = 'block';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动切换图片/视频(核心逻辑)
|
||||||
|
window.addEventListener('scroll', function () {
|
||||||
|
const productRights = document.querySelectorAll('.product-right');
|
||||||
|
let activeVideo = null;
|
||||||
|
// 找出当前在视口中的视频容器
|
||||||
|
productRights.forEach((rightContainer) => {
|
||||||
|
const img = rightContainer.querySelector('.right-img');
|
||||||
|
const video = rightContainer.querySelector('.right-video');
|
||||||
|
const videoSrc = video.src.trim()
|
||||||
|
if (!img || !video) return;
|
||||||
|
if(!videoSrc) return;
|
||||||
|
const rect = rightContainer.getBoundingClientRect();
|
||||||
|
// 视口判断:容器进入视口50%以上视为活跃
|
||||||
|
const isInView =
|
||||||
|
rect.top < window.innerHeight * 0.7 &&
|
||||||
|
rect.bottom > window.innerHeight * 0.3;
|
||||||
|
|
||||||
|
if (isInView) {
|
||||||
|
activeVideo = video;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理活跃视频
|
||||||
|
if (activeVideo) {
|
||||||
|
stopAllVideos(); // 先停止其他视频
|
||||||
|
const img = activeVideo.parentElement.querySelector('.right-img');
|
||||||
|
img.style.display = 'none';
|
||||||
|
activeVideo.style.display = 'block';
|
||||||
|
|
||||||
|
// 自动播放(兼容原生控制栏,用户手动暂停后不会强制播放)
|
||||||
|
if (activeVideo.paused) {
|
||||||
|
activeVideo.play().catch((err) => {
|
||||||
|
console.log('视频播放失败(浏览器限制):', err);
|
||||||
|
// 播放失败时回退到图片
|
||||||
|
activeVideo.style.display = 'none';
|
||||||
|
img.style.display = 'block';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stopAllVideos(); // 无活跃视频时停止所有播放
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.onload = function () {
|
||||||
|
if (typeof Swiper === 'undefined') {
|
||||||
|
console.error('Swiper加载失败,请刷新页面重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
swiper = new Swiper('.auto-swiper-container', {
|
||||||
|
autoplay: {
|
||||||
|
delay: 3000, // 3秒切换
|
||||||
|
disableOnInteraction: false,
|
||||||
|
},
|
||||||
|
loop: false,
|
||||||
|
slidesPerView: 1,
|
||||||
|
spaceBetween: 0,
|
||||||
|
// 启用分页指示标(核心配置)
|
||||||
|
pagination: {
|
||||||
|
el: '.swiper-pagination', // 对应 HTML 中的指示标容器
|
||||||
|
clickable: true, // 允许点击指示标切换
|
||||||
|
// dynamicBullets: true, // 动态指示标(当前激活放大)
|
||||||
|
//dynamicMainBullets: 3, // 动态模式显示3个核心指示标
|
||||||
|
},
|
||||||
|
navigation: false,
|
||||||
|
scrollbar: false,
|
||||||
|
on: {
|
||||||
|
resize: function () {
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('resize', function () {
|
||||||
|
swiper.update();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化时触发滚动事件,确保状态正确
|
||||||
|
window.dispatchEvent(new Event('scroll'));
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
{/block}
|
||||||
@@ -18,7 +18,7 @@ if (!function_exists('image_domain_concat')) {
|
|||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtrim($domain, '/') . '/' . ltrim($path, '/');
|
return url_join($domain, $path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ if (!function_exists('video_domain_concat')) {
|
|||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtrim($domain, '/') . '/' . ltrim($path, '/');
|
return url_join($domain, $path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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' => '视频地址'])
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ class CreateSysNavigationItem extends Migrator
|
|||||||
$table->addColumn('nav_id', 'string', ['limit' => 64, 'null' => false, 'comment' => '所属导航ID'])
|
$table->addColumn('nav_id', 'string', ['limit' => 64, 'null' => false, 'comment' => '所属导航ID'])
|
||||||
->addColumn('pid', 'integer', ['null' => false, 'default' => 0, 'comment' => '父级ID'])
|
->addColumn('pid', 'integer', ['null' => false, 'default' => 0, 'comment' => '父级ID'])
|
||||||
->addColumn('name', 'string', ['limit' => 64, 'null' => false, 'comment' => '名称'])
|
->addColumn('name', 'string', ['limit' => 64, 'null' => false, 'comment' => '名称'])
|
||||||
|
->addColumn('desc', 'string', ['limit' => 255, 'null' => true, 'default' => null, 'comment' => '描述'])
|
||||||
->addColumn('icon', 'string', ['limit' => 64, 'null' => true, 'default' => null, 'comment' => '图标'])
|
->addColumn('icon', 'string', ['limit' => 64, 'null' => true, 'default' => null, 'comment' => '图标'])
|
||||||
|
->addColumn('image', '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' => 255, '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' => '排序'])
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ class CreateSysBannerItem extends Migrator
|
|||||||
$table->addColumn('banner_id', 'integer', ['null' => false, 'comment' => '所属Banner ID'])
|
$table->addColumn('banner_id', 'integer', ['null' => false, 'comment' => '所属Banner ID'])
|
||||||
->addColumn('title', 'string', ['limit' => 256, 'null' => false, 'comment' => '标题'])
|
->addColumn('title', 'string', ['limit' => 256, 'null' => false, 'comment' => '标题'])
|
||||||
->addColumn('title_txt_color', 'string', ['limit' => 7, 'null' => false, 'default' => '', 'comment' => '标题文本颜色'])
|
->addColumn('title_txt_color', 'string', ['limit' => 7, 'null' => false, 'default' => '', 'comment' => '标题文本颜色'])
|
||||||
|
->addColumn('short_title', 'string', ['limit' => 255, 'null' => true, 'comment' => 'banner简称'])
|
||||||
|
->addColumn('short_title_txt_color', 'string', ['limit' => 7, 'null' => true, 'comment' => 'banner简称文本颜色'])
|
||||||
->addColumn('desc', MysqlAdapter::PHINX_TYPE_TEXT, ['null' => true, 'default' => null, 'comment' => '描述'])
|
->addColumn('desc', MysqlAdapter::PHINX_TYPE_TEXT, ['null' => true, 'default' => null, 'comment' => '描述'])
|
||||||
->addColumn('desc_txt_color', 'string', ['limit' => 7, 'null' => false, 'default' => '', 'comment' => '描述文本颜色'])
|
->addColumn('desc_txt_color', 'string', ['limit' => 7, 'null' => false, 'default' => '', 'comment' => '描述文本颜色'])
|
||||||
->addColumn('type', 'string', ['limit' => 16, 'null' => false, 'comment' => '类型: image为图片, video为视频'])
|
->addColumn('type', 'string', ['limit' => 16, 'null' => false, 'comment' => '类型: image为图片, video为视频'])
|
||||||
@@ -39,7 +41,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' => '创建时间'])
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use think\migration\Migrator;
|
||||||
|
use think\migration\db\Column;
|
||||||
|
|
||||||
|
class CreateProductCategoryRecommend extends Migrator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Change Method.
|
||||||
|
*
|
||||||
|
* Write your reversible migrations using this method.
|
||||||
|
*
|
||||||
|
* More information on writing migrations is available here:
|
||||||
|
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||||
|
*
|
||||||
|
* The following commands can be used in this method and Phinx will
|
||||||
|
* automatically reverse them when rolling back:
|
||||||
|
*
|
||||||
|
* createTable
|
||||||
|
* renameTable
|
||||||
|
* addColumn
|
||||||
|
* renameColumn
|
||||||
|
* addIndex
|
||||||
|
* addForeignKey
|
||||||
|
*
|
||||||
|
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||||
|
* with the Table class.
|
||||||
|
*/
|
||||||
|
public function change()
|
||||||
|
{
|
||||||
|
$table = $this->table('product_category_recommend', [
|
||||||
|
'engine' => 'MyISAM',
|
||||||
|
'collation' => 'utf8mb4_general_ci',
|
||||||
|
'comment' => '产品分类推荐表'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$table->addColumn('language_id', 'integer', ['signed' => false, 'null' => false, 'comment' => '语言ID'])
|
||||||
|
->addColumn('category_id', 'integer', ['signed' => false, 'null' => false, 'comment' => '分类ID'])
|
||||||
|
->addColumn('title', 'string', ['limit' => 255, 'comment' => '标题'])
|
||||||
|
->addColumn('image', 'string', ['limit' => 255, 'default' => '', 'comment' => '图片'])
|
||||||
|
->addColumn('desc', 'string', ['limit' => 255, 'comment' => '描述'])
|
||||||
|
->addColumn('link', 'string', ['limit' => 500, 'default' => '', 'comment' => '外链地址'])
|
||||||
|
->addColumn('sort', 'integer', ['default' => 0, 'comment' => '排序'])
|
||||||
|
->addColumn('disabled', 'boolean', ['default' => 0, 'comment' => '是否禁用 0:启用 1:禁用'])
|
||||||
|
->addColumn('created_at', 'timestamp', ["null" => false,'default' => 'CURRENT_TIMESTAMP', 'comment' => '创建时间'])
|
||||||
|
->addColumn('updated_at', 'timestamp', ["null" => false,'default' => 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP', 'comment' => '更新时间'])
|
||||||
|
->addColumn('deleted_at', 'timestamp', ['null' => true, 'comment' => '删除时间'])
|
||||||
|
->create();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use think\migration\Migrator;
|
||||||
|
use think\migration\db\Column;
|
||||||
|
|
||||||
|
class SysMallStoreEntrance extends Migrator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Change Method.
|
||||||
|
*
|
||||||
|
* Write your reversible migrations using this method.
|
||||||
|
*
|
||||||
|
* More information on writing migrations is available here:
|
||||||
|
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||||
|
*
|
||||||
|
* The following commands can be used in this method and Phinx will
|
||||||
|
* automatically reverse them when rolling back:
|
||||||
|
*
|
||||||
|
* createTable
|
||||||
|
* renameTable
|
||||||
|
* addColumn
|
||||||
|
* renameColumn
|
||||||
|
* addIndex
|
||||||
|
* addForeignKey
|
||||||
|
*
|
||||||
|
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||||
|
* with the Table class.
|
||||||
|
*/
|
||||||
|
public function change()
|
||||||
|
{
|
||||||
|
$table = $this->table('sys_mall_store_entrance', [
|
||||||
|
'engine' => 'MyISAM',
|
||||||
|
'collation' => 'utf8mb4_general_ci',
|
||||||
|
'comment' => '系统商城店铺入口表'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$table->addColumn('language_id', 'integer', ['signed' => false, 'null' => false, 'comment' => '语言ID'])
|
||||||
|
->addColumn('name', 'string', ['limit' => 255, 'null' => false, 'comment' => '商城名称'])
|
||||||
|
->addColumn('image', 'string', ['limit' => 255, 'default' => '', 'comment' => '图片'])
|
||||||
|
->addColumn('hover_image', 'string', ['limit' => 255, 'default' => '', 'comment' => '悬浮图'])
|
||||||
|
->addColumn('link', 'string', ['limit' => 500, 'default' => '', 'comment' => '链接地址'])
|
||||||
|
->addColumn('sort', 'integer', ['default' => 0, 'comment' => '排序'])
|
||||||
|
->addColumn('disabled', 'boolean', ['default' => 0, 'comment' => '是否禁用 0:启用 1:禁用'])
|
||||||
|
->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP', 'comment' => '创建时间'])
|
||||||
|
->addColumn('updated_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP', 'comment' => '更新时间'])
|
||||||
|
->addColumn('deleted_at', 'timestamp', ['null' => true, 'comment' => '删除时间'])
|
||||||
|
->addIndex(['language_id'], ['name' => 'idx_language_id'])
|
||||||
|
->create();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -73,8 +73,8 @@ class SysConfigInit extends Seeder
|
|||||||
["id" => 56, "group_id" => 12, "title" => "Instagram URL新窗口打开", "name" => "article_share_to_instagram.is_blank", "value" => "1", "extra" => "1:是\n0:否", "type" => "radio", "sort" => 6, "remark" => "", "created_at" => "2025-04-23 17:49:12", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 56, "group_id" => 12, "title" => "Instagram URL新窗口打开", "name" => "article_share_to_instagram.is_blank", "value" => "1", "extra" => "1:是\n0:否", "type" => "radio", "sort" => 6, "remark" => "", "created_at" => "2025-04-23 17:49:12", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 57, "group_id" => 12, "title" => "Twitter URL新窗口打开", "name" => "article_share_to_twitter.is_blank", "value" => "1", "extra" => "1:是\n0:否", "type" => "radio", "sort" => 9, "remark" => "", "created_at" => "2025-04-23 17:49:12", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 57, "group_id" => 12, "title" => "Twitter URL新窗口打开", "name" => "article_share_to_twitter.is_blank", "value" => "1", "extra" => "1:是\n0:否", "type" => "radio", "sort" => 9, "remark" => "", "created_at" => "2025-04-23 17:49:12", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 58, "group_id" => 12, "title" => "Reddit URL新窗口打开", "name" => "article_share_to_reddit.is_blank", "value" => "1", "extra" => "1:是\n0:否", "type" => "radio", "sort" => 12, "remark" => "", "created_at" => "2025-04-23 17:49:12", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 58, "group_id" => 12, "title" => "Reddit URL新窗口打开", "name" => "article_share_to_reddit.is_blank", "value" => "1", "extra" => "1:是\n0:否", "type" => "radio", "sort" => 12, "remark" => "", "created_at" => "2025-04-23 17:49:12", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
||||||
["id" => 59, "group_id" => 1, "title" => "产品询盘可选国家", "name" => "optional_country_for_product_inquiry", "value" => "Afghanistan\nAlbania\nAlgeria\nAmerican Samoa\nAndorra\nAngola\nAnguilla\nAntigua and Barbuda\nArgentina\nArmenia\nAruba\nAustralia\nAustria\nAzerbaijan\nAzores\nBahamas\nBahrain\nBangladesh\nBarbados\nBelarus\nBelgium\nBelize\nBenin\nBermuda\nBhutan\nBolivia\nBosnia and Herzegovina\nBotswana\nBrazil\nBrunei\nBulgaria\nBurkina Faso\nBurundi\nCambodia\nCameroon\nCanada\nCanarias\nCape Verde\nCayman\nCentral African Republic\nChad\nChile\nChina\nColombia\nComoros\nCongo (Congo-Kinshasa)\nCongo\nCook Islands\nCosta Rica\nCote D'Ivoire\nCroatia\nCuba\nCyprus\nCzech\nDenmark\nDjibouti\nDominica\nDominican\nEcuador\nEgypt\nEl Salvador\nEquatorial Guinea\nEritrea\nEstonia\nEthiopia\nFiji\nFinland\nFrance\nFrench Guiana\nFrench Polynesia\nGabon\nGambia\nGeorgia\nGermany\nGhana\nGreece\nGreenland\nGrenada\nGuadeloupe\nGuam\nGuatemala\nGuinea\nGuinea-Bissau\nGuyana\nHaiti\nHonduras\nHungary\nIceland\nIndia\nIndonesia\nIran\nIraq\nIreland\nIsrael\nItaly\nJamaica\nJapan\nJordan\nKazakhstan\nKenya\nKiribati\nKorea (North)\nKorea (South)\nKuwait\nKyrgyzstan\nLaos\nLatvia\nLebanon\nLesotho\nLiberia\nLibya\nLiechtenstein\nLithuania\nLuxembourg\nMacedonia\nMadagascar\nMadeira\nMalawi\nMalaysia\nMaldives\nMali\nMalta\nMarshall Islands\nMartinique\nMauritania\nMauritius\nMexico\nMicronesia\nMoldova\nMonaco\nMongolia\nMontserrat\nMorocco\nMozambique\nMyanmar\nNamibia\nNauru\nNepal\nNetherlands Antilles\nNetherlands\nNew Caledonia\nNew Zealand\nNicaragua\nNiger\nNiue\nNorthern Mariana\nNorway\nOman\nPakistan\nPalau\nPalestine\nPanama\nPapua New Guinea\nParaguay\nPeru\nPhilippines\nPitcairn Islands\nPoland\nPortugal\nPuerto Rico\nQatar\nReunion\nRomania\nRussian Federation\nRwanda\nSaint Helena\nSaint Kitts-Nevis\nSaint Lucia\nSaint Vincent and the Grenadines\nSamoa\nSan Marino\nSao Tome and Principe\nSaudi Arabia\nSenegal\nSerbia\nSeychelles\nSierra Leone\nSingapore\nSlovakia\nSlovenia\nSolomon Islands\nSomalia\nSouth Africa\nSpain\nSri Lanka\nSudan\nSuriname\nSwaziland\nSweden\nSwitzerland\nSyria\nTajikistan\nTanzania\nThailand\nThe British Virgin Islands\nThe United States Virgin Islands\nTimor-Leste\nTogo\nTokelau\nTonga\nTrinidad and Tobago\nTunisia\nTurkey\nTurkmenistan\nTurks and Caicos Islands\nTuvalu\nUganda\nUkraine\nUnited Arab Emirates\nUnited Kingdom\nUnited States\nUruguay\nUzbekistan\nVanuatu\nVatican City\nVenezuela\nVietnam\nWallis and Futuna\nWestern Sahara\nYemen\nZambia\nZimbabwe", "extra" => "", "type" => "textarea", "sort" => 7, "remark" => "", "created_at" => "2025-04-27 11:10:22", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
["id" => 59, "group_id" => 1, "title" => "产品询盘可选国家", "name" => "optional_country_for_product_inquiry", "value" => "Afghanistan\nAlbania\nAlgeria\nAmerican Samoa\nAndorra\nAngola\nAnguilla\nAntigua and Barbuda\nArgentina\nArmenia\nAruba\nAustralia\nAustria\nAzerbaijan\nAzores\nBahamas\nBahrain\nBangladesh\nBarbados\nBelarus\nBelgium\nBelize\nBenin\nBermuda\nBhutan\nBolivia\nBosnia and Herzegovina\nBotswana\nBrazil\nBrunei\nBulgaria\nBurkina Faso\nBurundi\nCambodia\nCameroon\nCanada\nCanarias\nCape Verde\nCayman\nCentral African Republic\nChad\nChile\nChina\nColombia\nComoros\nCongo (Congo-Kinshasa)\nCongo\nCook Islands\nCosta Rica\nCote D'Ivoire\nCroatia\nCuba\nCyprus\nCzech\nDenmark\nDjibouti\nDominica\nDominican\nEcuador\nEgypt\nEl Salvador\nEquatorial Guinea\nEritrea\nEstonia\nEthiopia\nFiji\nFinland\nFrance\nFrench Guiana\nFrench Polynesia\nGabon\nGambia\nGeorgia\nGermany\nGhana\nGreece\nGreenland\nGrenada\nGuadeloupe\nGuam\nGuatemala\nGuinea\nGuinea-Bissau\nGuyana\nHaiti\nHonduras\nHungary\nIceland\nIndia\nIndonesia\nIran\nIraq\nIreland\nIsrael\nItaly\nJamaica\nJapan\nJordan\nKazakhstan\nKenya\nKiribati\nKorea (North)\nKorea (South)\nKuwait\nKyrgyzstan\nLaos\nLatvia\nLebanon\nLesotho\nLiberia\nLibya\nLiechtenstein\nLithuania\nLuxembourg\nMacedonia\nMadagascar\nMadeira\nMalawi\nMalaysia\nMaldives\nMali\nMalta\nMarshall Islands\nMartinique\nMauritania\nMauritius\nMexico\nMicronesia\nMoldova\nMonaco\nMongolia\nHarmonyOS\nMorocco\nMozambique\nMyanmar\nNamibia\nNauru\nNepal\nNetherlands Antilles\nNetherlands\nNew Caledonia\nNew Zealand\nNicaragua\nNiger\nNiue\nNorthern Mariana\nNorway\nOman\nPakistan\nPalau\nPalestine\nPanama\nPapua New Guinea\nParaguay\nPeru\nPhilippines\nPitcairn Islands\nPoland\nPortugal\nPuerto Rico\nQatar\nReunion\nRomania\nRussian Federation\nRwanda\nSaint Helena\nSaint Kitts-Nevis\nSaint Lucia\nSaint Vincent and the Grenadines\nSamoa\nSan Marino\nSao Tome and Principe\nSaudi Arabia\nSenegal\nSerbia\nSeychelles\nSierra Leone\nSingapore\nSlovakia\nSlovenia\nSolomon Islands\nSomalia\nSouth Africa\nSpain\nSri Lanka\nSudan\nSuriname\nSwaziland\nSweden\nSwitzerland\nSyria\nTajikistan\nTanzania\nThailand\nThe British Virgin Islands\nThe United States Virgin Islands\nTimor-Leste\nTogo\nTokelau\nTonga\nTrinidad and Tobago\nTunisia\nTurkey\nTurkmenistan\nTurks and Caicos Islands\nTuvalu\nUganda\nUkraine\nUnited Arab Emirates\nUnited Kingdom\nUnited States\nUruguay\nUzbekistan\nVanuatu\nVatican City\nVenezuela\nVietnam\nWallis and Futuna\nWestern Sahara\nYemen\nZambia\nZimbabwe", "extra" => "", "type" => "textarea", "sort" => 7, "remark" => "", "created_at" => "2025-04-27 11:10:22", "updated_at" => "2025-06-11 17:09:13", "deleted_at" => null],
|
||||||
["id" => 60, "group_id" => 4, "title" => "产品询盘可选国家", "name" => "optional_country_for_product_inquiry", "value" => "Afghanistan\nAlbania\nAlgeria\nAmerican Samoa\nAndorra\nAngola\nAnguilla\nAntigua and Barbuda\nArgentina\nArmenia\nAruba\nAustralia\nAustria\nAzerbaijan\nAzores\nBahamas\nBahrain\nBangladesh\nBarbados\nBelarus\nBelgium\nBelize\nBenin\nBermuda\nBhutan\nBolivia\nBosnia and Herzegovina\nBotswana\nBrazil\nBrunei\nBulgaria\nBurkina Faso\nBurundi\nCambodia\nCameroon\nCanada\nCanarias\nCape Verde\nCayman\nCentral African Republic\nChad\nChile\nChina\nColombia\nComoros\nCongo (Congo-Kinshasa)\nCongo\nCook Islands\nCosta Rica\nCote D'Ivoire\nCroatia\nCuba\nCyprus\nCzech\nDenmark\nDjibouti\nDominica\nDominican\nEcuador\nEgypt\nEl Salvador\nEquatorial Guinea\nEritrea\nEstonia\nEthiopia\nFiji\nFinland\nFrance\nFrench Guiana\nFrench Polynesia\nGabon\nGambia\nGeorgia\nGermany\nGhana\nGreece\nGreenland\nGrenada\nGuadeloupe\nGuam\nGuatemala\nGuinea\nGuinea-Bissau\nGuyana\nHaiti\nHonduras\nHungary\nIceland\nIndia\nIndonesia\nIran\nIraq\nIreland\nIsrael\nItaly\nJamaica\nJapan\nJordan\nKazakhstan\nKenya\nKiribati\nKorea (North)\nKorea (South)\nKuwait\nKyrgyzstan\nLaos\nLatvia\nLebanon\nLesotho\nLiberia\nLibya\nLiechtenstein\nLithuania\nLuxembourg\nMacedonia\nMadagascar\nMadeira\nMalawi\nMalaysia\nMaldives\nMali\nMalta\nMarshall Islands\nMartinique\nMauritania\nMauritius\nMexico\nMicronesia\nMoldova\nMonaco\nMongolia\nMontserrat\nMorocco\nMozambique\nMyanmar\nNamibia\nNauru\nNepal\nNetherlands Antilles\nNetherlands\nNew Caledonia\nNew Zealand\nNicaragua\nNiger\nNiue\nNorthern Mariana\nNorway\nOman\nPakistan\nPalau\nPalestine\nPanama\nPapua New Guinea\nParaguay\nPeru\nPhilippines\nPitcairn Islands\nPoland\nPortugal\nPuerto Rico\nQatar\nReunion\nRomania\nRussian Federation\nRwanda\nSaint Helena\nSaint Kitts-Nevis\nSaint Lucia\nSaint Vincent and the Grenadines\nSamoa\nSan Marino\nSao Tome and Principe\nSaudi Arabia\nSenegal\nSerbia\nSeychelles\nSierra Leone\nSingapore\nSlovakia\nSlovenia\nSolomon Islands\nSomalia\nSouth Africa\nSpain\nSri Lanka\nSudan\nSuriname\nSwaziland\nSweden\nSwitzerland\nSyria\nTajikistan\nTanzania\nThailand\nThe British Virgin Islands\nThe United States Virgin Islands\nTimor-Leste\nTogo\nTokelau\nTonga\nTrinidad and Tobago\nTunisia\nTurkey\nTurkmenistan\nTurks and Caicos Islands\nTuvalu\nUganda\nUkraine\nUnited Arab Emirates\nUnited Kingdom\nUnited States\nUruguay\nUzbekistan\nVanuatu\nVatican City\nVenezuela\nVietnam\nWallis and Futuna\nWestern Sahara\nYemen\nZambia\nZimbabwe", "extra" => null, "type" => "textarea", "sort" => 7, "remark" => null, "created_at" => "2025-04-27 11:23:25", "updated_at" => "2025-06-12 09:55:21", "deleted_at" => null],
|
["id" => 60, "group_id" => 4, "title" => "产品询盘可选国家", "name" => "optional_country_for_product_inquiry", "value" => "Afghanistan\nAlbania\nAlgeria\nAmerican Samoa\nAndorra\nAngola\nAnguilla\nAntigua and Barbuda\nArgentina\nArmenia\nAruba\nAustralia\nAustria\nAzerbaijan\nAzores\nBahamas\nBahrain\nBangladesh\nBarbados\nBelarus\nBelgium\nBelize\nBenin\nBermuda\nBhutan\nBolivia\nBosnia and Herzegovina\nBotswana\nBrazil\nBrunei\nBulgaria\nBurkina Faso\nBurundi\nCambodia\nCameroon\nCanada\nCanarias\nCape Verde\nCayman\nCentral African Republic\nChad\nChile\nChina\nColombia\nComoros\nCongo (Congo-Kinshasa)\nCongo\nCook Islands\nCosta Rica\nCote D'Ivoire\nCroatia\nCuba\nCyprus\nCzech\nDenmark\nDjibouti\nDominica\nDominican\nEcuador\nEgypt\nEl Salvador\nEquatorial Guinea\nEritrea\nEstonia\nEthiopia\nFiji\nFinland\nFrance\nFrench Guiana\nFrench Polynesia\nGabon\nGambia\nGeorgia\nGermany\nGhana\nGreece\nGreenland\nGrenada\nGuadeloupe\nGuam\nGuatemala\nGuinea\nGuinea-Bissau\nGuyana\nHaiti\nHonduras\nHungary\nIceland\nIndia\nIndonesia\nIran\nIraq\nIreland\nIsrael\nItaly\nJamaica\nJapan\nJordan\nKazakhstan\nKenya\nKiribati\nKorea (North)\nKorea (South)\nKuwait\nKyrgyzstan\nLaos\nLatvia\nLebanon\nLesotho\nLiberia\nLibya\nLiechtenstein\nLithuania\nLuxembourg\nMacedonia\nMadagascar\nMadeira\nMalawi\nMalaysia\nMaldives\nMali\nMalta\nMarshall Islands\nMartinique\nMauritania\nMauritius\nMexico\nMicronesia\nMoldova\nMonaco\nMongolia\nHarmonyOS\nMorocco\nMozambique\nMyanmar\nNamibia\nNauru\nNepal\nNetherlands Antilles\nNetherlands\nNew Caledonia\nNew Zealand\nNicaragua\nNiger\nNiue\nNorthern Mariana\nNorway\nOman\nPakistan\nPalau\nPalestine\nPanama\nPapua New Guinea\nParaguay\nPeru\nPhilippines\nPitcairn Islands\nPoland\nPortugal\nPuerto Rico\nQatar\nReunion\nRomania\nRussian Federation\nRwanda\nSaint Helena\nSaint Kitts-Nevis\nSaint Lucia\nSaint Vincent and the Grenadines\nSamoa\nSan Marino\nSao Tome and Principe\nSaudi Arabia\nSenegal\nSerbia\nSeychelles\nSierra Leone\nSingapore\nSlovakia\nSlovenia\nSolomon Islands\nSomalia\nSouth Africa\nSpain\nSri Lanka\nSudan\nSuriname\nSwaziland\nSweden\nSwitzerland\nSyria\nTajikistan\nTanzania\nThailand\nThe British Virgin Islands\nThe United States Virgin Islands\nTimor-Leste\nTogo\nTokelau\nTonga\nTrinidad and Tobago\nTunisia\nTurkey\nTurkmenistan\nTurks and Caicos Islands\nTuvalu\nUganda\nUkraine\nUnited Arab Emirates\nUnited Kingdom\nUnited States\nUruguay\nUzbekistan\nVanuatu\nVatican City\nVenezuela\nVietnam\nWallis and Futuna\nWestern Sahara\nYemen\nZambia\nZimbabwe", "extra" => null, "type" => "textarea", "sort" => 7, "remark" => null, "created_at" => "2025-04-27 11:23:25", "updated_at" => "2025-06-12 09:55:21", "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" => 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],
|
||||||
@@ -119,6 +119,10 @@ class SysConfigInit extends Seeder
|
|||||||
["id" => 102, "group_id" => 13, "title" => "视频 - 唯一性保持", "name" => "upload_video.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 5, "remark" => "如果保持视频文件唯一,重复视频上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:24:24", "updated_at" => "2025-06-12 11:25:18", "deleted_at" => NULL],
|
["id" => 102, "group_id" => 13, "title" => "视频 - 唯一性保持", "name" => "upload_video.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 5, "remark" => "如果保持视频文件唯一,重复视频上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:24:24", "updated_at" => "2025-06-12 11:25:18", "deleted_at" => NULL],
|
||||||
["id" => 103, "group_id" => 13, "title" => "附件 - 保留原文件名", "name" => "upload_attachment.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 6, "remark" => "默认为否", "created_at" => "2025-06-12 11:27:08", "updated_at" => "2025-06-12 11:27:08", "deleted_at" => NULL],
|
["id" => 103, "group_id" => 13, "title" => "附件 - 保留原文件名", "name" => "upload_attachment.filename_keep", "value" => NULL, "extra" => "0:否\n1:是", "type" => "radio", "sort" => 6, "remark" => "默认为否", "created_at" => "2025-06-12 11:27:08", "updated_at" => "2025-06-12 11:27:08", "deleted_at" => NULL],
|
||||||
["id" => 104, "group_id" => 13, "title" => "附件 - 唯一性保持", "name" => "upload_attachment.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 7, "remark" => "如果保持附件文件唯一,重复附件上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:28:22", "updated_at" => "2025-06-12 11:28:22", "deleted_at" => NULL],
|
["id" => 104, "group_id" => 13, "title" => "附件 - 唯一性保持", "name" => "upload_attachment.filemd5_unique", "value" => "1", "extra" => "0:否\n1:是", "type" => "radio", "sort" => 7, "remark" => "如果保持附件文件唯一,重复附件上传时将立即返回已存在的地址;如果不保持,则同模块同一天上传的文件根据原文件名覆盖。", "created_at" => "2025-06-12 11:28:22", "updated_at" => "2025-06-12 11:28:22", "deleted_at" => NULL],
|
||||||
|
['id' => 105, 'group_id' => 13, 'title' => '视频 - 保存到', 'name' => 'upload_video.save_to', 'value' => 'qiniu_cloud', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 6, 'remark' => '视频保存位置,默认为“本地” - [本地为本站点服务器;七牛云为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:46:24', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
|
||||||
|
['id' => 106, 'group_id' => 13, 'title' => '附件 - 保存到', 'name' => 'upload_attachment.save_to', 'value' => 'local', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 9, 'remark' => '附件保存位置,默认为“本地” - [本地为本站点服务器;七牛云为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:51:34', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
|
||||||
|
['id' => 107, 'group_id' => 14, 'title' => '视频 - 保存到', 'name' => 'upload_video.save_to', 'value' => 'qiniu_cloud', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 6, 'remark' => '视频保存位置,默认为“本地” - [本地为本站点服务器;七牛云为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:46:24', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
|
||||||
|
['id' => 108, 'group_id' => 14, 'title' => '附件 - 保存到', 'name' => 'upload_attachment.save_to', 'value' => 'local', 'extra' => 'local:本地\nqiniu_cloud:七牛云', 'type' => 'radio', 'sort' => 9, 'remark' => '附件保存位置,默认为“本地” - [本地为本站点服务器;七牛云为七牛云对象存储,上传经这本站点服务器中转,上传耗时稍慢于“本地”]', 'created_at' => '2025-07-25 10:51:34', 'updated_at' => '2025-07-25 16:41:53', 'deleted_at' => NULL],
|
||||||
];
|
];
|
||||||
|
|
||||||
$table = $this->table('sys_config');
|
$table = $this->table('sys_config');
|
||||||
|
|||||||
295
extend/filesystem/adapter/QiniuAdapter.php
Normal file
295
extend/filesystem/adapter/QiniuAdapter.php
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
<?php
|
||||||
|
namespace filesystem\adapter;
|
||||||
|
|
||||||
|
use League\Flysystem\Config;
|
||||||
|
use League\Flysystem\FilesystemAdapter;
|
||||||
|
use League\Flysystem\FileAttributes;
|
||||||
|
use League\Flysystem\UnableToCopyFile;
|
||||||
|
use League\Flysystem\UnableToDeleteFile;
|
||||||
|
use League\Flysystem\UnableToMoveFile;
|
||||||
|
use League\Flysystem\UnableToReadFile;
|
||||||
|
use League\Flysystem\UnableToRetrieveMetadata;
|
||||||
|
use League\Flysystem\UnableToSetVisibility;
|
||||||
|
use League\Flysystem\UnableToWriteFile;
|
||||||
|
use Qiniu\Auth;
|
||||||
|
use Qiniu\Storage\UploadManager;
|
||||||
|
use Qiniu\Storage\BucketManager;
|
||||||
|
|
||||||
|
class QiniuAdapter implements FilesystemAdapter
|
||||||
|
{
|
||||||
|
protected ?Auth $authMgr;
|
||||||
|
protected ?UploadManager $uploadMgr;
|
||||||
|
protected ?BucketManager $bucketMgr;
|
||||||
|
|
||||||
|
public function __construct(protected string $access_key, protected string $secret_key, protected string $bucket, protected string $base_url, protected string $path)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAuthMgr(): Auth
|
||||||
|
{
|
||||||
|
return $this->authMgr ?? new Auth($this->access_key, $this->secret_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUploadMgr(): UploadManager
|
||||||
|
{
|
||||||
|
return $this->uploadMgr ?? new UploadManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getBucketMgr(): BucketManager
|
||||||
|
{
|
||||||
|
return $this->bucketMgr ?? new BucketManager($this->authMgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPathPrefix(): string
|
||||||
|
{
|
||||||
|
$path = ltrim($this->path, '\\/');
|
||||||
|
if ($path !== '' && !str_ends_with($path, '/')) {
|
||||||
|
$path = $path . '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyPathPrefix(string $path): string
|
||||||
|
{
|
||||||
|
$path = ltrim($path, '\\/');
|
||||||
|
return $this->getPathPrefix() . $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function parseUrl($url): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Build arrays of values we need to decode before parsing
|
||||||
|
$entities = [
|
||||||
|
'%21',
|
||||||
|
'%2A',
|
||||||
|
'%27',
|
||||||
|
'%28',
|
||||||
|
'%29',
|
||||||
|
'%3B',
|
||||||
|
'%3A',
|
||||||
|
'%40',
|
||||||
|
'%26',
|
||||||
|
'%3D',
|
||||||
|
'%24',
|
||||||
|
'%2C',
|
||||||
|
'%2F',
|
||||||
|
'%3F',
|
||||||
|
'%23',
|
||||||
|
'%5B',
|
||||||
|
'%5D',
|
||||||
|
'%5C'
|
||||||
|
];
|
||||||
|
$replacements = ['!', '*', "'", '(', ')', ';', ':', '@', '&', '=', '$', ',', '/', '?', '#', '[', ']', '/'];
|
||||||
|
|
||||||
|
// Create encoded URL with special URL characters decoded so it can be parsed
|
||||||
|
// All other characters will be encoded
|
||||||
|
$encodedURL = str_replace($entities, $replacements, urlencode($url));
|
||||||
|
|
||||||
|
// Parse the encoded URL
|
||||||
|
$encodedParts = parse_url($encodedURL);
|
||||||
|
|
||||||
|
// Now, decode each value of the resulting array
|
||||||
|
if ($encodedParts) {
|
||||||
|
foreach ($encodedParts as $key => $value) {
|
||||||
|
$result[$key] = urldecode(str_replace($replacements, $entities, $value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeHost($domain): string
|
||||||
|
{
|
||||||
|
if (0 !== stripos($domain, 'https://') && 0 !== stripos($domain, 'http://')) {
|
||||||
|
$domain = "http://{$domain}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtrim($domain, '/') . '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUrl(string $path): string
|
||||||
|
{
|
||||||
|
$segments = $this->parseUrl($path);
|
||||||
|
$query = empty($segments['query']) ? '' : '?' . $segments['query'];
|
||||||
|
|
||||||
|
return $this->normalizeHost($this->base_url) . ltrim(implode('/', array_map('rawurlencode', explode('/', $segments['path']))), '/') . $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function privateDownloadUrl(string $path, int $expires = 3600): string
|
||||||
|
{
|
||||||
|
return $this->getAuthMgr()->privateDownloadUrl($this->getUrl($path), $expires);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getMetadata($path): FileAttributes|array
|
||||||
|
{
|
||||||
|
$result = $this->getBucketMgr()->stat($this->bucket, $path);
|
||||||
|
$result[0]['key'] = $path;
|
||||||
|
|
||||||
|
return $this->normalizeFileInfo($result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeFileInfo(array $stats): FileAttributes
|
||||||
|
{
|
||||||
|
return new FileAttributes(
|
||||||
|
$stats['key'],
|
||||||
|
$stats['fsize'] ?? null,
|
||||||
|
null,
|
||||||
|
isset($stats['putTime']) ? floor($stats['putTime'] / 10000000) : null,
|
||||||
|
$stats['mimeType'] ?? null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fileExists(string $path): bool
|
||||||
|
{
|
||||||
|
[, $error] = $this->getBucketMgr()->stat($this->bucket, $this->applyPathPrefix($path));
|
||||||
|
return is_null($error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function directoryExists(string $path): bool
|
||||||
|
{
|
||||||
|
return $this->fileExists($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(string $path, string $contents, Config $config): void
|
||||||
|
{
|
||||||
|
$mime = $config->get('mime', 'application/octet-stream');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Error|null $error
|
||||||
|
*/
|
||||||
|
[, $error] = $this->getUploadMgr()->put(
|
||||||
|
$this->getAuthMgr()->uploadToken($this->bucket),
|
||||||
|
$this->applyPathPrefix($path),
|
||||||
|
$contents,
|
||||||
|
null,
|
||||||
|
$mime,
|
||||||
|
$path
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($error) {
|
||||||
|
throw UnableToWriteFile::atLocation($path, $error->message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function writeStream(string $path, $resource, Config $config): void
|
||||||
|
{
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
while (!feof($resource)) {
|
||||||
|
$data .= fread($resource, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->write($path, $data, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read(string $path): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$result = file_get_contents($this->privateDownloadUrl($path));
|
||||||
|
} catch (\Exception $th) {
|
||||||
|
throw UnableToReadFile::fromLocation($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $result) {
|
||||||
|
throw UnableToReadFile::fromLocation($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readStream(string $path)
|
||||||
|
{
|
||||||
|
if (ini_get('allow_url_fopen')) {
|
||||||
|
if ($result = fopen($this->privateDownloadUrl($path), 'r')) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw UnableToReadFile::fromLocation($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $path): void
|
||||||
|
{
|
||||||
|
[, $error] = $this->getBucketMgr()->delete($this->bucket, $this->applyPathPrefix($path));
|
||||||
|
if (!is_null($error)) {
|
||||||
|
throw UnableToDeleteFile::atLocation($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteDirectory(string $path): void
|
||||||
|
{
|
||||||
|
$this->delete($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createDirectory(string $path, Config $config): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setVisibility(string $path, string $visibility): void
|
||||||
|
{
|
||||||
|
throw UnableToSetVisibility::atLocation($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function visibility(string $path): FileAttributes
|
||||||
|
{
|
||||||
|
throw UnableToRetrieveMetadata::visibility($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mimeType(string $path): FileAttributes
|
||||||
|
{
|
||||||
|
$meta = $this->getMetadata($path);
|
||||||
|
|
||||||
|
if ($meta->mimeType() === null) {
|
||||||
|
throw UnableToRetrieveMetadata::mimeType($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lastModified(string $path): FileAttributes
|
||||||
|
{
|
||||||
|
$meta = $this->getMetadata($path);
|
||||||
|
|
||||||
|
if ($meta->lastModified() === null) {
|
||||||
|
throw UnableToRetrieveMetadata::lastModified($path);
|
||||||
|
}
|
||||||
|
return $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fileSize(string $path): FileAttributes
|
||||||
|
{
|
||||||
|
$meta = $this->getMetadata($path);
|
||||||
|
|
||||||
|
if ($meta->fileSize() === null) {
|
||||||
|
throw UnableToRetrieveMetadata::fileSize($path);
|
||||||
|
}
|
||||||
|
return $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listContents(string $path, bool $deep): iterable
|
||||||
|
{
|
||||||
|
$result = $this->getBucketMgr()->listFiles($this->bucket, $path);
|
||||||
|
|
||||||
|
foreach ($result[0]['items'] ?? [] as $files) {
|
||||||
|
yield $this->normalizeFileInfo($files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function move(string $source, string $destination, Config $config): void
|
||||||
|
{
|
||||||
|
[, $error] = $this->getBucketMgr()->rename($this->bucket, $source, $destination);
|
||||||
|
if (!is_null($error)) {
|
||||||
|
throw UnableToMoveFile::fromLocationTo($source, $destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function copy(string $source, string $destination, Config $config): void
|
||||||
|
{
|
||||||
|
[, $error] = $this->getBucketMgr()->copy($this->bucket, $source, $this->bucket, $destination);
|
||||||
|
if (!is_null($error)) {
|
||||||
|
throw UnableToCopyFile::fromLocationTo($source, $destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
extend/filesystem/driver/Qiniu.php
Normal file
56
extend/filesystem/driver/Qiniu.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
namespace filesystem\driver;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use filesystem\adapter\QiniuAdapter;
|
||||||
|
use League\Flysystem\FilesystemAdapter;
|
||||||
|
|
||||||
|
class Qiniu extends \think\filesystem\Driver
|
||||||
|
{
|
||||||
|
protected function createAdapter(): FilesystemAdapter
|
||||||
|
{
|
||||||
|
return new QiniuAdapter(
|
||||||
|
$this->config['access_key'],
|
||||||
|
$this->config['secret_key'],
|
||||||
|
$this->config['bucket'],
|
||||||
|
$this->config['base_url'],
|
||||||
|
$this->config['path_prefix']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存文件
|
||||||
|
* @param string $path 路径
|
||||||
|
* @param \think\File $file 文件
|
||||||
|
* @param null|string|\Closure $rule 文件名规则
|
||||||
|
* @param array $options 参数
|
||||||
|
* @return bool|string
|
||||||
|
*/
|
||||||
|
public function putFile(string $path, \think\File $file, $rule = null, array $options = [])
|
||||||
|
{
|
||||||
|
if (!empty($this->config['filename_generator']) && $this->config['filename_generator'] instanceof Closure) {
|
||||||
|
$rule = $this->config['filename_generator']($file, $rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->putFileAs($path, $file, $file->hashName($rule), $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function url(string $path): string
|
||||||
|
{
|
||||||
|
if (str_starts_with($path, 'http://') || str_starts_with($path, 'https://')) {
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
if (!str_starts_with($path, $this->config['path_prefix'])) {
|
||||||
|
$path = $this->config['path_prefix'] . '/' . $path;
|
||||||
|
}
|
||||||
|
return $this->concatPathToUrl($this->config['base_url'], $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function path(string $path): string
|
||||||
|
{
|
||||||
|
if (!str_starts_with($path, $this->config['path_prefix'])) {
|
||||||
|
$path = $this->config['path_prefix'] . '/' . $path;
|
||||||
|
}
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace uploader;
|
|
||||||
|
|
||||||
use Qiniu\Auth;
|
|
||||||
use Qiniu\Storage\UploadManager;
|
|
||||||
use Qiniu\Storage\BucketManager;
|
|
||||||
|
|
||||||
class QiniuUploader
|
|
||||||
{
|
|
||||||
private $bucket = 'orico-opd';
|
|
||||||
private $accessKey = 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms';
|
|
||||||
private $secretKey = 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q';
|
|
||||||
|
|
||||||
private $rule = [
|
|
||||||
'fileSize' => 1024 * 1024 * 5, // 默认最大上传5M
|
|
||||||
'fileExt' => 'jpeg,jpg,png', // 默认上传文件后缀
|
|
||||||
'fileMime' => 'image/jpeg,image/png,image/gif' // 默认上传文件mime
|
|
||||||
];
|
|
||||||
|
|
||||||
private $dir = true;
|
|
||||||
private $originalName = false;
|
|
||||||
private $pathPrefix = '';
|
|
||||||
private $fileNamePrefix = 'orico';
|
|
||||||
|
|
||||||
static public $domain = 'http://opdfile.f2b211.com/';
|
|
||||||
|
|
||||||
public function __construct($conf = [])
|
|
||||||
{
|
|
||||||
if (!empty($conf['bucket'])) {
|
|
||||||
$this->bucket = $conf['bucket'];
|
|
||||||
}
|
|
||||||
if (!empty($conf['accessKey'])) {
|
|
||||||
$this->accessKey = $conf['accessKey'];
|
|
||||||
}
|
|
||||||
if (!empty($conf['secretKey'])) {
|
|
||||||
$this->secretKey = $conf['secretKey'];
|
|
||||||
}
|
|
||||||
if (!empty($conf['pathPrefix'])) {
|
|
||||||
$this->pathPrefix = trim($conf['pathPrefix'], '/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成随机字符串
|
|
||||||
*/
|
|
||||||
private function random($length, $type = "string", $convert = "0")
|
|
||||||
{
|
|
||||||
$conf = [
|
|
||||||
'number' => '0123456789',
|
|
||||||
'string' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
||||||
'all' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789='
|
|
||||||
];
|
|
||||||
$string = $conf[$type];
|
|
||||||
if (!$string) {
|
|
||||||
$string = $conf['string'];
|
|
||||||
}
|
|
||||||
$strlen = strlen($string) - 1;
|
|
||||||
$char = '';
|
|
||||||
for ($i = 0; $i < $length; $i++) {
|
|
||||||
$char .= $string[mt_rand(0, $strlen)];
|
|
||||||
}
|
|
||||||
if ($convert > 0) {
|
|
||||||
$res = strtoupper($char);
|
|
||||||
} elseif ($convert == 0) {
|
|
||||||
$res = $char;
|
|
||||||
} elseif ($convert < 0) {
|
|
||||||
$res = strtolower($char);
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 组装文件名
|
|
||||||
*/
|
|
||||||
private function buildFileName()
|
|
||||||
{
|
|
||||||
return $this->fileNamePrefix . time() . substr(time(), -5) . substr(microtime(), 2, 3) . $this->random(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传验证规则
|
|
||||||
*/
|
|
||||||
public function validate($rule)
|
|
||||||
{
|
|
||||||
$this->rule = $rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传文件到七牛云
|
|
||||||
*/
|
|
||||||
public function uploadFile($name)
|
|
||||||
{
|
|
||||||
// 构建鉴权对象
|
|
||||||
$auth = new Auth($this->accessKey, $this->secretKey);
|
|
||||||
|
|
||||||
// 生成上传 Token
|
|
||||||
$token = $auth->uploadToken($this->bucket);
|
|
||||||
|
|
||||||
// 初始化 UploadManager 对象并进行文件的上传。
|
|
||||||
$uploadMgr = new UploadManager();
|
|
||||||
|
|
||||||
$file = request()->file($name);
|
|
||||||
|
|
||||||
$aspectRatio = [];
|
|
||||||
if (!empty($this->rule['aspectRatio'])) {
|
|
||||||
$aspectRatio = $this->rule['aspectRatio'];
|
|
||||||
unset($this->rule['aspectRatio']);
|
|
||||||
}
|
|
||||||
$validate = validate([$name => $this->rule]);
|
|
||||||
if (!$validate->check([$name => $file])) {
|
|
||||||
throw new \Exception($validate->getError());
|
|
||||||
}
|
|
||||||
|
|
||||||
$fileName = $file->getOriginalName(); // 文件原名
|
|
||||||
if (!$this->originalName) {
|
|
||||||
$fileName = $this->buildFileName() . '.' . $file->extension();
|
|
||||||
if (!$this->dir && !empty($this->pathPrefix)) {
|
|
||||||
$fileName = $this->pathPrefix . '/' . $fileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($this->dir) {
|
|
||||||
$fileName = date('Y') . '/' . date('m') . '/' . date('d') . '/' . $fileName;
|
|
||||||
if (!empty($this->pathPrefix)) {
|
|
||||||
$fileName = $this->pathPrefix . '/' . $fileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$filePath = $file->getPathname(); // 临时路径
|
|
||||||
if (!empty($aspectRatio)) { // 验证图片宽高
|
|
||||||
list($width, $height, $type, $attr) = getimagesize($file);
|
|
||||||
if ($width != $aspectRatio['width'] || $height != $aspectRatio['height']) {
|
|
||||||
throw new \Exception('图片宽高不符合');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$fileType = $file->getOriginalMime();
|
|
||||||
list($ret, $err) = $uploadMgr->putFile($token, $fileName, $filePath, null, $fileType, false);
|
|
||||||
|
|
||||||
if ($err !== null) {
|
|
||||||
throw new \Exception($err);
|
|
||||||
} else {
|
|
||||||
return ['hash' => $ret['hash'], 'filename' => $ret['key'], 'remote_url' => self::$domain . $ret['key']];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传文件到七牛云
|
|
||||||
*/
|
|
||||||
public function deleteFile($name)
|
|
||||||
{
|
|
||||||
// 构建鉴权对象
|
|
||||||
$auth = new Auth($this->accessKey, $this->secretKey);
|
|
||||||
// 初始化 BucketManager 对象并进行文件的删除。
|
|
||||||
$bucketManager = new BucketManager($auth);
|
|
||||||
$ret = $bucketManager->delete($this->bucket, $name);
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
$secret_key = 'Aa-1221';
|
|
||||||
|
|
||||||
// check for POST request
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
|
|
||||||
throw new \Exception('FAILED - not POST - '. $_SERVER['REQUEST_METHOD']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get content type
|
|
||||||
$content_type = isset($_SERVER['CONTENT_TYPE']) ? strtolower(trim($_SERVER['CONTENT_TYPE'])) : '';
|
|
||||||
|
|
||||||
if ($content_type != 'application/json') {
|
|
||||||
throw new \Exception('FAILED - not application/json - '. $content_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get payload
|
|
||||||
$payload = trim(file_get_contents("php://input"));
|
|
||||||
|
|
||||||
if (empty($payload)) {
|
|
||||||
throw new \Exception('FAILED - no payload');
|
|
||||||
}
|
|
||||||
|
|
||||||
// get header signature
|
|
||||||
$header_signature = isset($_SERVER['HTTP_X_GITEA_SIGNATURE']) ? $_SERVER['HTTP_X_GITEA_SIGNATURE'] : '';
|
|
||||||
|
|
||||||
if (empty($header_signature)) {
|
|
||||||
throw new \Exception('FAILED - header signature missing');
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate payload signature
|
|
||||||
$payload_signature = hash_hmac('sha256', $payload, $secret_key, false);
|
|
||||||
|
|
||||||
// check payload signature against header signature
|
|
||||||
if ($header_signature !== $payload_signature) {
|
|
||||||
throw new \Exception('FAILED - payload signature');
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert json to array
|
|
||||||
$decoded = json_decode($payload, true);
|
|
||||||
|
|
||||||
// check for json decode errors
|
|
||||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
||||||
throw new \Exception('FAILED - json decode - '. json_last_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
exec('git pull origin dev --rebase 2>&1', $result);
|
|
||||||
|
|
||||||
var_export($result);exit;
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
var_export($th->getMessage());
|
|
||||||
}
|
|
||||||
2
public/migrate_temp_images/.gitignore
vendored
2
public/migrate_temp_images/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-top: 50px;
|
padding-top: 46px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.iotb_bgw {
|
.iotb_bgw {
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
.iotbt1 {
|
.iotbt1 {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
padding-top: 40px;
|
padding-top: 40px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
|
|
||||||
.iotbtp1 {
|
.iotbtp1 {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding-bottom: 11px;
|
padding-bottom: 11px;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
.iotbts1 {
|
.iotbts1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
.sfbt1 {
|
.sfbt1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
padding-top: 24px;
|
padding-top: 24px;
|
||||||
@@ -183,7 +183,7 @@
|
|||||||
.cit {
|
.cit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Regular, Montserrat;
|
font-family: HarmonyOS-Regular, HarmonyOS;
|
||||||
color: #000;
|
color: #000;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -237,7 +237,7 @@
|
|||||||
.wcu_s1 {
|
.wcu_s1 {
|
||||||
color: #000;
|
color: #000;
|
||||||
font: 16px;
|
font: 16px;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 20px 24px;
|
padding: 20px 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -598,7 +598,7 @@
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: #707070;
|
color: #707070;
|
||||||
font-family: "Montserrat-Medium";
|
font-family: "HarmonyOS-Medium";
|
||||||
}
|
}
|
||||||
|
|
||||||
.oricoCnLc .gallery-thumbs .swiper-slide-thumb-active {
|
.oricoCnLc .gallery-thumbs .swiper-slide-thumb-active {
|
||||||
@@ -632,14 +632,14 @@
|
|||||||
.oricoCnLc .info h5 {
|
.oricoCnLc .info h5 {
|
||||||
font-size: #000;
|
font-size: #000;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
padding: 2rem 2rem 0 1rem;
|
padding: 2rem 2rem 0 1rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oricoCnLc .info p {
|
.oricoCnLc .info p {
|
||||||
color: #707070;
|
color: #707070;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -651,7 +651,7 @@
|
|||||||
|
|
||||||
.oricoCnLc .m_ach-b .title {
|
.oricoCnLc .m_ach-b .title {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
width: 98%;
|
width: 98%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -660,7 +660,7 @@
|
|||||||
|
|
||||||
.oricoCnLc .m_ach-b .chtitle {
|
.oricoCnLc .m_ach-b .chtitle {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
width: 98%;
|
width: 98%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -677,7 +677,7 @@
|
|||||||
|
|
||||||
.oricoCnLc .m_ch-title {
|
.oricoCnLc .m_ch-title {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
width: 98%;
|
width: 98%;
|
||||||
margin: 1rem auto 0;
|
margin: 1rem auto 0;
|
||||||
padding: 1rem 0 0;
|
padding: 1rem 0 0;
|
||||||
@@ -690,7 +690,7 @@
|
|||||||
font-size: 0.875;
|
font-size: 0.875;
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
color: #707070;
|
color: #707070;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
width: 98%;
|
width: 98%;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -156,7 +156,7 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
font-family: Montserrat-Regular, Montserrat;
|
font-family: HarmonyOS-Regular, HarmonyOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oricoEGapp-articledetail .content .share_box .comment .comment_form>div input {
|
.oricoEGapp-articledetail .content .share_box .comment .comment_form>div input {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
color: #6b6c6e;
|
color: #6b6c6e;
|
||||||
font-family: "Montserrat-Medium";
|
font-family: "HarmonyOS-Medium";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
|||||||
246
public/static/index/mobile/css/category.css
Normal file
246
public/static/index/mobile/css/category.css
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: inherit !important;
|
||||||
|
/* font-size:100% !important; */
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #f5f5f5;
|
||||||
|
font-size: inherit !important;
|
||||||
|
/* font-size:100% !important; */
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 100vw !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-box {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 20px 22px;
|
||||||
|
background: #fff;
|
||||||
|
margin-top: 46px;
|
||||||
|
/* border-bottom: 1px solid #f0f0f0; */
|
||||||
|
box-shadow: 0 2px 8px rgba(217, 217, 217, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 0.82rem;
|
||||||
|
background: #F1F2F5;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back {
|
||||||
|
width: 0.28rem;
|
||||||
|
height: 0.28rem;
|
||||||
|
color: #333;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.back img {
|
||||||
|
width: 0.28rem;
|
||||||
|
height: 0.28rem;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 0.32rem !important;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 主体布局 */
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
height: calc(100% - 46px);
|
||||||
|
margin-top:0.018rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 左侧菜单 #FAFAFA;*/
|
||||||
|
.sidebar {
|
||||||
|
width: 114px;
|
||||||
|
background:#fafafa;
|
||||||
|
overflow-y: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar li {
|
||||||
|
list-style: none;
|
||||||
|
padding: 24px 16px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.28rem !important;
|
||||||
|
color:#686A70; /* #686A70;*/
|
||||||
|
cursor: pointer;
|
||||||
|
background:#fff;
|
||||||
|
/* 分别控制上下圆角的过渡 */
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
transition: border-radius 1s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
.sidebar li.active {
|
||||||
|
color: #004BFA;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sidebar li.active-prev {
|
||||||
|
border-bottom-right-radius: 0.17rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar li.active-next {
|
||||||
|
border-top-right-radius: 0.17rem !important;
|
||||||
|
}
|
||||||
|
/* 右侧内容 */
|
||||||
|
.right-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-left: 12px;
|
||||||
|
background: #fafafa;
|
||||||
|
/* padding-bottom: 100px; */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-left: 12px;
|
||||||
|
background: #fafafa;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 在底部添加占位元素 */
|
||||||
|
.right-content::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: 80px; /* 根据需要调整 */
|
||||||
|
width: 100%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 最后一个元素底部留白 */
|
||||||
|
.sec-box:last-child {
|
||||||
|
margin-bottom: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.sec-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 24px;
|
||||||
|
padding-right: 17px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.sec-title {
|
||||||
|
font-size: 0.28rem !important;
|
||||||
|
color: #686A70;
|
||||||
|
font-weight: 500
|
||||||
|
}
|
||||||
|
|
||||||
|
.sec-arrow {
|
||||||
|
width: 0.28rem;
|
||||||
|
height: 0.28rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #666;
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.sec-arrow img {
|
||||||
|
width: 0.28rem;
|
||||||
|
height: 0.28rem;
|
||||||
|
}
|
||||||
|
/* 横向滚动容器 */
|
||||||
|
.scroll-box {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
overflow-x: auto;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-box::-webkit-scrollbar {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-card {
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding-left: 19px;
|
||||||
|
padding-right: 19px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.card-img {
|
||||||
|
width: 1.52rem;
|
||||||
|
background: #f1f1f1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-img img {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-info {
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-name {
|
||||||
|
font-size: 0.2rem !important;
|
||||||
|
width: 1.52rem;
|
||||||
|
height: auto;
|
||||||
|
color: #1D1D1F;
|
||||||
|
line-height: 1.4;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-model {
|
||||||
|
font-size: 0.16rem !important;
|
||||||
|
color: #686A70;
|
||||||
|
margin-top: 4px
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容区块默认隐藏 */
|
||||||
|
.tab-pane {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 激活时显示 */
|
||||||
|
.tab-pane.active {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #004bfa;
|
color: #004bfa;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
color: #707070;
|
color: #707070;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
|
|
||||||
.itlable {
|
.itlable {
|
||||||
font-size: 12.5px;
|
font-size: 12.5px;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
height: 48px;
|
height: 48px;
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
font-family: Montserrat-Regular, Montserrat;
|
font-family: HarmonyOS-Regular, HarmonyOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
.itselectopen {
|
.itselectopen {
|
||||||
@@ -130,12 +130,12 @@
|
|||||||
padding: 15px;
|
padding: 15px;
|
||||||
background: #f2f2f2;
|
background: #f2f2f2;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-family: Montserrat-Regular, Montserrat;
|
font-family: HarmonyOS-Regular, HarmonyOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bttj {
|
.bttj {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
/* width: 212px; */
|
/* width: 212px; */
|
||||||
/* height: 48px; */
|
/* height: 48px; */
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-top: 50px;
|
padding-top: 46px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.iotb_bgw {
|
.iotb_bgw {
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
|
|
||||||
.iotbt1 {
|
.iotbt1 {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
padding-top: 40px;
|
padding-top: 40px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
@@ -210,7 +210,7 @@
|
|||||||
|
|
||||||
.iotbtp1 {
|
.iotbtp1 {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding-bottom: 11px;
|
padding-bottom: 11px;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
@@ -219,7 +219,7 @@
|
|||||||
.iotbts1 {
|
.iotbts1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
@@ -290,7 +290,7 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
.sfbt1 {
|
.sfbt1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
padding-top: 24px;
|
padding-top: 24px;
|
||||||
@@ -333,7 +333,7 @@
|
|||||||
.cit {
|
.cit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Regular, Montserrat;
|
font-family: HarmonyOS-Regular, HarmonyOS;
|
||||||
color: #000;
|
color: #000;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -388,7 +388,7 @@
|
|||||||
.wcu_s1 {
|
.wcu_s1 {
|
||||||
color: #000;
|
color: #000;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 20px 24px;
|
padding: 20px 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #004bfa;
|
color: #004bfa;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
color: #707070;
|
color: #707070;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
|
|
||||||
.itlable {
|
.itlable {
|
||||||
font-size: 12.5px;
|
font-size: 12.5px;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
height: 48px;
|
height: 48px;
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
font-family: Montserrat-Regular, Montserrat;
|
font-family: HarmonyOS-Regular, HarmonyOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
.itselectopen {
|
.itselectopen {
|
||||||
@@ -130,13 +130,13 @@
|
|||||||
padding: 15px;
|
padding: 15px;
|
||||||
background: #f2f2f2;
|
background: #f2f2f2;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-family: Montserrat-Regular, Montserrat;
|
font-family: HarmonyOS-Regular, HarmonyOS;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bttj {
|
.bttj {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
/* width: 212px; */
|
/* width: 212px; */
|
||||||
padding: 15px 60px;
|
padding: 15px 60px;
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-top: 50px;
|
padding-top: 46px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.iotb_bgw {
|
.iotb_bgw {
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
|
|
||||||
.iotbt1 {
|
.iotbt1 {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
padding-top: 40px;
|
padding-top: 40px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
@@ -210,7 +210,7 @@
|
|||||||
|
|
||||||
.iotbtp1 {
|
.iotbtp1 {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding-bottom: 11px;
|
padding-bottom: 11px;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
@@ -219,7 +219,7 @@
|
|||||||
.iotbts1 {
|
.iotbts1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
@@ -290,7 +290,7 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
.sfbt1 {
|
.sfbt1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-family: Montserrat-Bold, Montserrat;
|
font-family: HarmonyOS-Bold, HarmonyOS;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
padding-top: 24px;
|
padding-top: 24px;
|
||||||
@@ -333,7 +333,7 @@
|
|||||||
.cit {
|
.cit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Montserrat-Regular, Montserrat;
|
font-family: HarmonyOS-Regular, HarmonyOS;
|
||||||
color: #000;
|
color: #000;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -387,7 +387,7 @@
|
|||||||
.wcu_s1 {
|
.wcu_s1 {
|
||||||
color: #000;
|
color: #000;
|
||||||
font: 16px;
|
font: 16px;
|
||||||
font-family: Montserrat-Medium, Montserrat;
|
font-family: HarmonyOS-Medium, HarmonyOS;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 20px 24px;
|
padding: 20px 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
margin-top: 3.3rem;
|
margin-top: 3.3rem;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .banner_title {
|
.oricoEGapp-Contact .banner_title {
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .title {
|
.oricoEGapp-Contact .title {
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .info {
|
.oricoEGapp-Contact .info {
|
||||||
@@ -43,12 +43,12 @@
|
|||||||
height: 3rem;
|
height: 3rem;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .info .right .des {
|
.oricoEGapp-Contact .info .right .des {
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.25rem;
|
line-height: 1.25rem;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .info_title {
|
.oricoEGapp-Contact .info_title {
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.25rem;
|
line-height: 1.25rem;
|
||||||
margin-bottom: 0.22rem;
|
margin-bottom: 0.22rem;
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
}
|
}
|
||||||
.oricoEGapp-Contact .question .title {
|
.oricoEGapp-Contact .question .title {
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.25rem;
|
line-height: 1.25rem;
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
.oricoEGapp-Contact .send {
|
.oricoEGapp-Contact .send {
|
||||||
display: block;
|
display: block;
|
||||||
background-color: #004bfa;
|
background-color: #004bfa;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
padding: 0.75rem 1.5rem;
|
padding: 0.75rem 1.5rem;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
color: #ee2f53;
|
color: #ee2f53;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .contact_b {
|
.oricoEGapp-Contact .contact_b {
|
||||||
font-family: "Montserrat-SemiBold";
|
font-family: "HarmonyOS-SemiBold";
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
padding-top: 1.125rem;
|
padding-top: 1.125rem;
|
||||||
padding-bottom: 1.125rem;
|
padding-bottom: 1.125rem;
|
||||||
@@ -119,42 +119,42 @@
|
|||||||
.oricoEGapp-Contact input::-webkit-input-placeholder {
|
.oricoEGapp-Contact input::-webkit-input-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact input:-moz-placeholder {
|
.oricoEGapp-Contact input:-moz-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact input::-moz-placeholder {
|
.oricoEGapp-Contact input::-moz-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact input:-ms-input-placeholder {
|
.oricoEGapp-Contact input:-ms-input-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact textarea::-webkit-input-placeholder {
|
.oricoEGapp-Contact textarea::-webkit-input-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact textarea:-moz-placeholder {
|
.oricoEGapp-Contact textarea:-moz-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact textarea::-moz-placeholder {
|
.oricoEGapp-Contact textarea::-moz-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact textarea:-ms-input-placeholder {
|
.oricoEGapp-Contact textarea:-ms-input-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .narskfPage {
|
.oricoEGapp-Contact .narskfPage {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
margin-top: 3.3rem;
|
margin-top: 3.3rem;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .banner_title {
|
.oricoEGapp-Contact .banner_title {
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .title {
|
.oricoEGapp-Contact .title {
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .info {
|
.oricoEGapp-Contact .info {
|
||||||
@@ -46,12 +46,12 @@
|
|||||||
width: 88% !important;
|
width: 88% !important;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .info .right .des {
|
.oricoEGapp-Contact .info .right .des {
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.25rem;
|
line-height: 1.25rem;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .info_title {
|
.oricoEGapp-Contact .info_title {
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.25rem;
|
line-height: 1.25rem;
|
||||||
margin-bottom: 0.22rem;
|
margin-bottom: 0.22rem;
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
}
|
}
|
||||||
.oricoEGapp-Contact .question .title {
|
.oricoEGapp-Contact .question .title {
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.25rem;
|
line-height: 1.25rem;
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
.oricoEGapp-Contact .send {
|
.oricoEGapp-Contact .send {
|
||||||
display: block;
|
display: block;
|
||||||
background-color: #004bfa;
|
background-color: #004bfa;
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
padding: 0.75rem 1.5rem;
|
padding: 0.75rem 1.5rem;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
color: #ee2f53;
|
color: #ee2f53;
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact .contact_b {
|
.oricoEGapp-Contact .contact_b {
|
||||||
font-family: "Montserrat-SemiBold";
|
font-family: "HarmonyOS-SemiBold";
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
padding-top: 1.125rem;
|
padding-top: 1.125rem;
|
||||||
padding-bottom: 1.125rem;
|
padding-bottom: 1.125rem;
|
||||||
@@ -122,40 +122,40 @@
|
|||||||
.oricoEGapp-Contact input::-webkit-input-placeholder {
|
.oricoEGapp-Contact input::-webkit-input-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact input:-moz-placeholder {
|
.oricoEGapp-Contact input:-moz-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact input::-moz-placeholder {
|
.oricoEGapp-Contact input::-moz-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact input:-ms-input-placeholder {
|
.oricoEGapp-Contact input:-ms-input-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact textarea::-webkit-input-placeholder {
|
.oricoEGapp-Contact textarea::-webkit-input-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact textarea:-moz-placeholder {
|
.oricoEGapp-Contact textarea:-moz-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact textarea::-moz-placeholder {
|
.oricoEGapp-Contact textarea::-moz-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
.oricoEGapp-Contact textarea:-ms-input-placeholder {
|
.oricoEGapp-Contact textarea:-ms-input-placeholder {
|
||||||
color: #9e9e9f;
|
color: #9e9e9f;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: "Montserrat-Regular";
|
font-family: "HarmonyOS-Regular";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'icomoon';
|
font-family: 'icomoon';
|
||||||
src: url('../fonts/icomoon/icomoon.eot?11cuay');
|
src: url('../fonts/icomoon/icomoon.eot?11cuay');
|
||||||
src: url('../fonts/icomoon/icomoon.eot?11cuay#iefix') format('embedded-opentype'), url('../fonts/icomoon/icomoon.ttf?11cuay') format('truetype'),
|
src: url('../fonts/icomoon/icomoon.eot?11cuay#iefix') format('embedded-opentype'), url('../fonts/icomoon/icomoon.ttf?11cuay') format('opentype'),
|
||||||
url('../fonts/icomoon/icomoon.woff?11cuay') format('woff'), url('../fonts/icomoon/icomoon.svg?11cuay#icomoon') format('svg');
|
url('../fonts/icomoon/icomoon.woff?11cuay') format('woff'), url('../fonts/icomoon/icomoon.svg?11cuay#icomoon') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
font-family: 'colleciton';
|
font-family: 'colleciton';
|
||||||
src: url('../fonts/icomoon/colleciton/icomoon.eot?11cuay');
|
src: url('../fonts/icomoon/colleciton/icomoon.eot?11cuay');
|
||||||
src: url('../fonts/icomoon/colleciton/icomoon.eot?11cuay#iefix') format('embedded-opentype'),
|
src: url('../fonts/icomoon/colleciton/icomoon.eot?11cuay#iefix') format('embedded-opentype'),
|
||||||
url('../fonts/icomoon/colleciton/icomoon.ttf?11cuay') format('truetype'), url('../fonts/icomoon/colleciton/icomoon.woff?11cuay') format('woff'),
|
url('../fonts/icomoon/colleciton/icomoon.ttf?11cuay') format('opentype'), url('../fonts/icomoon/colleciton/icomoon.woff?11cuay') format('woff'),
|
||||||
url('../fonts/icomoon/colleciton/icomoon.svg?11cuay#icomoon') format('svg');
|
url('../fonts/icomoon/colleciton/icomoon.svg?11cuay#icomoon') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'icomoon';
|
font-family: 'icomoon';
|
||||||
src: url('../fonts/icomoon/icomoona.eot?c46hgi');
|
src: url('../fonts/icomoon/icomoona.eot?c46hgi');
|
||||||
src: url('../fonts/icomoon/icomoona.eot?c46hgi#iefix') format('embedded-opentype'), url('../fonts/icomoon/icomoona.ttf?c46hgi') format('truetype'),
|
src: url('../fonts/icomoon/icomoona.eot?c46hgi#iefix') format('embedded-opentype'), url('../fonts/icomoon/icomoona.ttf?c46hgi') format('opentype'),
|
||||||
url('../fonts/icomoon/icomoona.woff?c46hgi') format('woff'), url('../fonts/icomoon/icomoona.svg?c46hgi#icomoon') format('svg');
|
url('../fonts/icomoon/icomoona.woff?c46hgi') format('woff'), url('../fonts/icomoon/icomoona.svg?c46hgi#icomoon') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'icomoon';
|
font-family: 'icomoon';
|
||||||
src: url('../fonts/icomoon/icomoon.eot?ujw7hy');
|
src: url('../fonts/icomoon/icomoon.eot?ujw7hy');
|
||||||
src: url('../fonts/icomoon/icomoon.eot?ujw7hy#iefix') format('embedded-opentype'), url('../fonts/icomoon/icomoon.ttf?ujw7hy') format('truetype'),
|
src: url('../fonts/icomoon/icomoon.eot?ujw7hy#iefix') format('embedded-opentype'), url('../fonts/icomoon/icomoon.ttf?ujw7hy') format('opentype'),
|
||||||
url('../fonts/icomoon/icomoon.woff?ujw7hy') format('woff'), url('../fonts/icomoon/icomoon.svg?ujw7hy#icomoon') format('svg');
|
url('../fonts/icomoon/icomoon.woff?ujw7hy') format('woff'), url('../fonts/icomoon/icomoon.svg?ujw7hy#icomoon') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
font-family: 'icomoon01';
|
font-family: 'icomoon01';
|
||||||
src: url('fonts-20190124/icomoon.eot?ll2528');
|
src: url('fonts-20190124/icomoon.eot?ll2528');
|
||||||
src: url('fonts-20190124/icomoon.eot?ll2528#iefix') format('embedded-opentype'),
|
src: url('fonts-20190124/icomoon.eot?ll2528#iefix') format('embedded-opentype'),
|
||||||
url('fonts-20190124/icomoon.ttf?ll2528') format('truetype'), url('fonts-20190124/icomoon.woff?ll2528') format('woff'),
|
url('fonts-20190124/icomoon.ttf?ll2528') format('opentype'), url('fonts-20190124/icomoon.woff?ll2528') format('woff'),
|
||||||
url('fonts-20190124/icomoon.svg?ll2528#icomoon') format('svg');
|
url('fonts-20190124/icomoon.svg?ll2528#icomoon') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'icomoon02';
|
font-family: 'icomoon02';
|
||||||
src: url('fonts/other/icomoon.eot?ujw7hy');
|
src: url('fonts/other/icomoon.eot?ujw7hy');
|
||||||
src: url('fonts/other/icomoon.eot?ujw7hy#iefix') format('embedded-opentype'), url('fonts/other/icomoon.ttf?ujw7hy') format('truetype'),
|
src: url('fonts/other/icomoon.eot?ujw7hy#iefix') format('embedded-opentype'), url('fonts/other/icomoon.ttf?ujw7hy') format('opentype'),
|
||||||
url('fonts/other/icomoon.woff?ujw7hy') format('woff'), url('fonts/other/icomoon.svg?ujw7hy#icomoon') format('svg');
|
url('fonts/other/icomoon.woff?ujw7hy') format('woff'), url('fonts/other/icomoon.svg?ujw7hy#icomoon') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@@ -189,7 +189,7 @@
|
|||||||
font-family: 'icomoon05';
|
font-family: 'icomoon05';
|
||||||
src: url('fonts-20220322/icomoon.eot?cdcz43');
|
src: url('fonts-20220322/icomoon.eot?cdcz43');
|
||||||
src: url('fonts-20220322/icomoon.eot?cdcz43#iefix') format('embedded-opentype'),
|
src: url('fonts-20220322/icomoon.eot?cdcz43#iefix') format('embedded-opentype'),
|
||||||
url('fonts-20220322/icomoon.ttf?cdcz43') format('truetype'), url('fonts-20220322/icomoon.woff?cdcz43') format('woff'),
|
url('fonts-20220322/icomoon.ttf?cdcz43') format('opentype'), url('fonts-20220322/icomoon.woff?cdcz43') format('woff'),
|
||||||
url('fonts-20220322/icomoon.svg?cdcz43#icomoon') format('svg');
|
url('fonts-20220322/icomoon.svg?cdcz43#icomoon') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.oircoEgapp-head .top-menu .it-ct {
|
.oircoEgapp-head .top-menu .it-ct {
|
||||||
font-family: "Montserrat-SemiBold";
|
font-family: "HarmonyOS-SemiBold";
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.oircoEgapp-head .top-menu .it-ct .it-1 {
|
.oircoEgapp-head .top-menu .it-ct .it-1 {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
.oricoEGapp .oricoEGapp-index .oidx-banner {
|
.oricoEGapp .oricoEGapp-index .oidx-banner {
|
||||||
margin-top: 3.5rem;
|
margin-top: 46px;
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
}
|
}
|
||||||
.oricoEGapp .oricoEGapp-index .oidx-banner .swiper-container {
|
.oricoEGapp .oricoEGapp-index .oidx-banner .swiper-container {
|
||||||
|
|||||||
457
public/static/index/mobile/css/new_header.css
Normal file
457
public/static/index/mobile/css/new_header.css
Normal file
@@ -0,0 +1,457 @@
|
|||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 46px;
|
||||||
|
padding: 0 17px;
|
||||||
|
background: #fff;
|
||||||
|
/* position: relative; */
|
||||||
|
position: fixed;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
z-index: 100;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-img,
|
||||||
|
.nav-search,
|
||||||
|
.nav-lang,
|
||||||
|
.nav-img1,
|
||||||
|
.nav-card {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-log {
|
||||||
|
width: 90px;
|
||||||
|
height: 22px;
|
||||||
|
margin-left: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-lang {
|
||||||
|
margin: 0 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉菜单 */
|
||||||
|
.nav-dropdown-menu {
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 46px;
|
||||||
|
left: 0;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown-menu.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 所有菜单项统一用 div */
|
||||||
|
.menu-item {
|
||||||
|
margin: 0 22px;
|
||||||
|
font-size: 15px !important;
|
||||||
|
color: #333;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item-img {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 有子菜单才显示箭头 */
|
||||||
|
.has-child .menu-item-img {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 无子菜单隐藏箭头 */
|
||||||
|
.no-child .menu-item-img {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 箭头旋转 */
|
||||||
|
.has-child.open .menu-item-img {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-img1 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .sub-menu {
|
||||||
|
display: none;
|
||||||
|
} */
|
||||||
|
.sub-menu {
|
||||||
|
display: none;
|
||||||
|
/* height: 100vh; */
|
||||||
|
/* overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
-webkit-overflow-scrolling: touch; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .sub-menu-overflow {
|
||||||
|
max-height: calc(100vh - 180px);
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
} */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.sub-menu.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-item {
|
||||||
|
padding: 0 16px;
|
||||||
|
font-size: 14px !important;
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-item:nth-child(1) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-item a {
|
||||||
|
color: #686A70;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-item:last-child {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-item-card-img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
aspect-ratio: 358 / 192;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-item-card-title {
|
||||||
|
font-size: 16px !important;
|
||||||
|
color: #1D1D1F;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-item-card-name {
|
||||||
|
font-size: 14px !important;
|
||||||
|
color: #686A70;
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-padding {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ====================== 弹窗样式(不遮盖头部) ====================== */
|
||||||
|
.modal-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 46px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 46px);
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
display: none;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
z-index: 98;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-overlay.show {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
width: 90%;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 66px 24px 8px 24px;
|
||||||
|
margin-top: 20px;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 24px;
|
||||||
|
right: 24px;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 写法2:使用 flex 布局实现一行2个 */
|
||||||
|
.modal-items-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-item {
|
||||||
|
width: calc(50% - 16px);
|
||||||
|
|
||||||
|
font-size: 16px !important;
|
||||||
|
color: #1D1D1F;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-item-img {
|
||||||
|
width: clamp(48px, 17vw, 128px);
|
||||||
|
height: auto;
|
||||||
|
aspect-ratio: 64 / 64;
|
||||||
|
object-fit: contain;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-item-title {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 16px !important;
|
||||||
|
color: #1D1D1F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-item:hover {
|
||||||
|
/* background-color: #f5f5f5; */
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 语言弹窗样式 - 列表布局 */
|
||||||
|
.lang-modal-content {
|
||||||
|
width: 90%;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 68px 24px;
|
||||||
|
margin-top: 20px;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-items-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-item {
|
||||||
|
font-size: 16px !important;
|
||||||
|
color: #1D1D1F;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-item img {
|
||||||
|
width: 29px;
|
||||||
|
height: 20px;
|
||||||
|
margin-right: 16px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-item:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 搜索弹窗样式 */
|
||||||
|
.search-modal-content {
|
||||||
|
width: 90%;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 68px 24px;
|
||||||
|
margin-top: 20px;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
border-radius: 30px;
|
||||||
|
padding-left: 24px;
|
||||||
|
/* padding-right: 13px; */
|
||||||
|
background: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-box input {
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background: transparent;
|
||||||
|
font-size: 14px !important;
|
||||||
|
padding: 10px 0;
|
||||||
|
flex:1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-box input::placeholder {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-box .search-clear-btn {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.6;
|
||||||
|
|
||||||
|
}
|
||||||
|
.search-clear-box {
|
||||||
|
padding-right: 10px;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
/* .search-clear-btn {
|
||||||
|
border-right: 1px solid #eee;
|
||||||
|
} */
|
||||||
|
.search-input-box .search-clear-btn:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-box .search-submit-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.search-submit-box {
|
||||||
|
border-left: 1px solid #d9d9d9;
|
||||||
|
padding-left:10px;
|
||||||
|
padding-right: 13px;
|
||||||
|
max-height: 18px;
|
||||||
|
}
|
||||||
|
.search-history {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-title {
|
||||||
|
font-size: 14px !important;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-clear {
|
||||||
|
font-size: 12px !important;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-clear:hover {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-item:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
margin-left: -8px;
|
||||||
|
margin-right: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-item span {
|
||||||
|
font-size: 14px !important;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-item .delete-icon {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-history-item .delete-icon:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-history {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px 0;
|
||||||
|
font-size: 14px !important;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
.mobile-header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
/* 产品列表的子菜单不需要滚动 */
|
||||||
|
.menu-item:first-child .sub-menu {
|
||||||
|
max-height: none !important;
|
||||||
|
overflow-y: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 其他导航的子菜单使用JS动态设置高度
|
||||||
|
.has-child:not(:first-child) .sub-menu {
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
} */
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-top: 3.4rem;
|
margin-top:46px;
|
||||||
}
|
}
|
||||||
.oricoEGapp-newarrival .ona-topimg {
|
.oricoEGapp-newarrival .ona-topimg {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|||||||
@@ -1,28 +1,45 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Montserrat";
|
font-family: "HarmonyOS";
|
||||||
src: url("../fonts/Montserrat-Regular.ttf") format("truetype");
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Regular.ttf") format("opentype");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Regular";
|
||||||
src: url("../fonts/Montserrat-Bold.ttf") format("truetype");
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Regular.ttf") format("opentype");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Montserrat-Medium";
|
font-family: "HarmonyOS-Bold";
|
||||||
src: url("../fonts/Montserrat-Medium.ttf") format("truetype");
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Bold.ttf") format("opentype");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "HarmonyOS-Medium";
|
||||||
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Medium.ttf") format("opentype");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/* HarmonyOS-SemiBold1 */
|
||||||
|
@font-face {
|
||||||
|
font-family: "HarmonyOS-SemiBold";
|
||||||
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Bold.ttf") format("opentype");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "HarmonyOS-Light";
|
||||||
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Light.ttf") format("opentype");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
/* font-family: 'Montserrat'; */
|
font-family: 'HarmonyOS';
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
/* IE 和 Edge */
|
/* IE 和 Edge */
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
@@ -88,7 +105,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Montserrat-SemiBold';
|
font-family: 'HarmonyOS-SemiBold';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 分页样式 */
|
/* 分页样式 */
|
||||||
@@ -161,7 +178,9 @@ body {
|
|||||||
.ql-editor>* {
|
.ql-editor>* {
|
||||||
cursor: text
|
cursor: text
|
||||||
}
|
}
|
||||||
|
.ql-editor video{
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
.ql-editor p,.ql-editor ol,.ql-editor ul,.ql-editor pre,.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6 {
|
.ql-editor p,.ql-editor ol,.ql-editor ul,.ql-editor pre,.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -1,29 +1,30 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Montserrat";
|
font-family: "HarmonyOS";
|
||||||
src: url("../fonts/Montserrat-Regular.ttf") format("truetype");
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Regular.woff2") format("woff2");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Montserrat-Bold";
|
font-family: "HarmonyOS-Bold";
|
||||||
src: url("../fonts/Montserrat-Bold.ttf") format("truetype");
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Bold.woff2") format("woff2");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Montserrat-Medium";
|
font-family: "HarmonyOS-Medium";
|
||||||
src: url("../fonts/Montserrat-Medium.ttf") format("truetype");
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Medium.woff2") format("woff2");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
/* HarmonyOS-SemiBold1 */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Montserrat-SemiBold";
|
font-family: "HarmonyOS-SemiBold";
|
||||||
src: url("../fonts/Montserrat-SemiBold.ttf") format("truetype");
|
src: url("//ow.static.f2b211.com/static/fonts/HarmonyOS_Sans_SC_Bold.woff2") format("woff2");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
font-family: 'Montserrat-SemiBold';
|
font-family: 'HarmonyOS-SemiBold';
|
||||||
margin: auto;
|
margin: auto;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
max-width: 750px;
|
max-width: 750px;
|
||||||
@@ -591,7 +592,7 @@ button.swiper-pagination-bullet {
|
|||||||
.Innew-text .title {
|
.Innew-text .title {
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
}
|
}
|
||||||
.Inpro-text {
|
.Inpro-text {
|
||||||
padding: 2rem 0 0.8rem;
|
padding: 2rem 0 0.8rem;
|
||||||
@@ -600,7 +601,7 @@ button.swiper-pagination-bullet {
|
|||||||
.Inpro-text .title {
|
.Inpro-text .title {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
}
|
}
|
||||||
|
|
||||||
.Innew-text .more {
|
.Innew-text .more {
|
||||||
@@ -635,7 +636,7 @@ video img {
|
|||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
max-height: 3rem;
|
max-height: 3rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
}
|
}
|
||||||
.inprotext .t-f16 {
|
.inprotext .t-f16 {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
@@ -957,12 +958,12 @@ video img {
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
padding: 0 3rem;
|
padding: 0 3rem;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
}
|
}
|
||||||
.ban-t {
|
.ban-t {
|
||||||
padding: 0.5rem 3rem;
|
padding: 0.5rem 3rem;
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-family: 'Montserrat-Regular';
|
font-family: 'HarmonyOS-Regular';
|
||||||
}
|
}
|
||||||
.btn-more {
|
.btn-more {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@@ -979,7 +980,7 @@ video img {
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
}
|
}
|
||||||
/*类别*/
|
/*类别*/
|
||||||
.category {
|
.category {
|
||||||
@@ -1095,11 +1096,11 @@ video img {
|
|||||||
padding: 0.2rem 0;
|
padding: 0.2rem 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
}
|
}
|
||||||
.num-bg li p {
|
.num-bg li p {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
font-family: 'Montserrat-Regular';
|
font-family: 'HarmonyOS-Regular';
|
||||||
}
|
}
|
||||||
/*标题*/
|
/*标题*/
|
||||||
.Tech-text {
|
.Tech-text {
|
||||||
@@ -1115,7 +1116,7 @@ video img {
|
|||||||
.Tech-text p {
|
.Tech-text p {
|
||||||
padding: 1rem 0;
|
padding: 1rem 0;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
}
|
}
|
||||||
|
|
||||||
.pos-text {
|
.pos-text {
|
||||||
@@ -1125,7 +1126,7 @@ video img {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 0.825rem;
|
font-size: 0.825rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -1157,7 +1158,7 @@ video img {
|
|||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
padding: 1rem 0;
|
padding: 1rem 0;
|
||||||
line-height: 1.3em;
|
line-height: 1.3em;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
.faq span {
|
.faq span {
|
||||||
@@ -1172,7 +1173,7 @@ video img {
|
|||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.75em;
|
line-height: 1.75em;
|
||||||
color: #666;
|
color: #666;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
}
|
}
|
||||||
.faq i {
|
.faq i {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -1209,7 +1210,7 @@ video img {
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
@@ -1217,7 +1218,7 @@ video img {
|
|||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
color: #7f7f7f;
|
color: #7f7f7f;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
/*foot */
|
/*foot */
|
||||||
@@ -1249,7 +1250,7 @@ video img {
|
|||||||
}
|
}
|
||||||
.foot-in h3 {
|
.foot-in h3 {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
}
|
}
|
||||||
.logo-input {
|
.logo-input {
|
||||||
@@ -1278,7 +1279,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;
|
||||||
@@ -1292,7 +1293,7 @@ video img {
|
|||||||
.foot-cate li p {
|
.foot-cate li p {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
line-height: 2.5rem;
|
line-height: 2.5rem;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
.foot-wei {
|
.foot-wei {
|
||||||
@@ -1327,7 +1328,7 @@ video img {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 1.2rem;
|
height: 1.2rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
}
|
}
|
||||||
/*下拉*/
|
/*下拉*/
|
||||||
.m_footer .left {
|
.m_footer .left {
|
||||||
@@ -1375,7 +1376,7 @@ video img {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
}
|
}
|
||||||
/*下拉*/
|
/*下拉*/
|
||||||
.mask-up {
|
.mask-up {
|
||||||
@@ -1985,7 +1986,7 @@ video img {
|
|||||||
}
|
}
|
||||||
.swiper-slide a {
|
.swiper-slide a {
|
||||||
color: #000;
|
color: #000;
|
||||||
font-family: 'Montserrat-SemiBold';
|
font-family: 'HarmonyOS-SemiBold';
|
||||||
}
|
}
|
||||||
.swiper-slide img {
|
.swiper-slide img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@@ -2342,6 +2343,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%;
|
||||||
@@ -2438,7 +2492,7 @@ video img {
|
|||||||
margin-right: 0px;
|
margin-right: 0px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-family: Montserrat !important;
|
font-family: HarmonyOS !important;
|
||||||
color: #666;
|
color: #666;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
@@ -3426,26 +3480,26 @@ video img {
|
|||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
margin: 4rem auto 0;
|
margin: 4rem auto 0;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
}
|
}
|
||||||
.timedesin {
|
.timedesin {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
line-height: 1.3rem;
|
line-height: 1.3rem;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
}
|
}
|
||||||
.timeblue {
|
.timeblue {
|
||||||
color: #004bfa;
|
color: #004bfa;
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
}
|
}
|
||||||
.timeblue img {
|
.timeblue img {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
.timeblue a {
|
.timeblue a {
|
||||||
color: #004bfa;
|
color: #004bfa;
|
||||||
font-family: 'Montserrat-Medium';
|
font-family: 'HarmonyOS-Medium';
|
||||||
}
|
}
|
||||||
/*视频*/
|
/*视频*/
|
||||||
.video-youtu {
|
.video-youtu {
|
||||||
@@ -3505,7 +3559,7 @@ video img {
|
|||||||
}
|
}
|
||||||
.vision-title {
|
.vision-title {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
width: 98%;
|
width: 98%;
|
||||||
margin: 1rem auto 0;
|
margin: 1rem auto 0;
|
||||||
}
|
}
|
||||||
@@ -3513,7 +3567,7 @@ video img {
|
|||||||
font-size: 0.875;
|
font-size: 0.875;
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
color: #707070;
|
color: #707070;
|
||||||
font-family: 'Montserrat-Regular';
|
font-family: 'HarmonyOS-Regular';
|
||||||
width: 98%;
|
width: 98%;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
}
|
}
|
||||||
@@ -3531,7 +3585,7 @@ video img {
|
|||||||
}
|
}
|
||||||
.brand_title {
|
.brand_title {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
width: 98%;
|
width: 98%;
|
||||||
margin: 1rem auto 0;
|
margin: 1rem auto 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -3549,7 +3603,7 @@ video img {
|
|||||||
font-size: 0.875;
|
font-size: 0.875;
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
font-family: 'Montserrat-Regular';
|
font-family: 'HarmonyOS-Regular';
|
||||||
width: 98%;
|
width: 98%;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
}
|
}
|
||||||
@@ -3602,7 +3656,7 @@ video::-webkit-media-controls-current-time-display {
|
|||||||
}
|
}
|
||||||
.m_ach .title {
|
.m_ach .title {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-family: 'Montserrat-Bold';
|
font-family: 'HarmonyOS-Bold';
|
||||||
width: 98%;
|
width: 98%;
|
||||||
margin: 1rem auto 0;
|
margin: 1rem auto 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -3627,7 +3681,7 @@ video::-webkit-media-controls-current-time-display {
|
|||||||
}
|
}
|
||||||
.m_ach .list-num li p {
|
.m_ach .list-num li p {
|
||||||
color: #707070;
|
color: #707070;
|
||||||
font-family: 'Montserrat-Regular';
|
font-family: 'HarmonyOS-Regular';
|
||||||
}
|
}
|
||||||
/*新闻评测*/
|
/*新闻评测*/
|
||||||
.news-vertu {
|
.news-vertu {
|
||||||
@@ -3923,7 +3977,7 @@ video::-webkit-media-controls-current-time-display {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
font-family: Montserrat-Regular, Montserrat;
|
font-family: HarmonyOS-Regular, HarmonyOS;
|
||||||
}
|
}
|
||||||
.comment_area {
|
.comment_area {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user