chore(release): 4.1.0

This commit is contained in:
lukaijie
2025-12-30 09:53:01 +08:00
parent 5a921c849b
commit f3a04f7576
34 changed files with 3044 additions and 118 deletions

8
.env
View File

@@ -1,5 +1,5 @@
VUE_APP_TITLE=Ecshopx pc
VUE_APP_HOST=https://demo-ecshopx.ishopex.cn
VUE_APP_API_BASE_URL=https://demo-ecshopx.ishopex.cn
VUE_APP_COMPANYID=5
VUE_APP_TITLE=
VUE_APP_HOST=
VUE_APP_API_BASE_URL=
VUE_APP_COMPANYID=
VUE_APP_DEFAULT_LANG=en

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.DS_Store
node_modules
openspec
# local env files
.env.local

View File

@@ -2,4 +2,247 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [4.1.1](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v4.1.0...v4.1.1) (2025-12-10)
## [4.0.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.21.0...v4.0.0) (2025-11-19)
### Bug Fixes
* 去除一些非必要文档 ([9ae272f](https://git.ishopex.cn/onex/ecshopx-newpc/commit/9ae272fd384479cfc020f4120cd68bb5e1784aaa))
* **scope:** update package ([d733a9c](https://git.ishopex.cn/onex/ecshopx-newpc/commit/d733a9c64a652b38483f3db16a483296806f3669))
* **scope:** update readme ([958707f](https://git.ishopex.cn/onex/ecshopx-newpc/commit/958707f09f91aa2b6716012aa0d0791cd90b1f28))
## [3.21.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.20.0...v3.21.0) (2025-05-29)
## [3.20.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.4...v3.20.0) (2025-04-27)
### [3.19.4](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.3...v3.19.4) (2025-04-23)
### [3.19.3](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.2...v3.19.3) (2025-04-23)
### [3.19.2](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.1...v3.19.2) (2025-04-16)
### [3.19.2](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.1...v3.19.2) (2025-04-16)
### [3.19.2](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.1...v3.19.2) (2025-04-16)
### [3.19.2](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.3...v3.19.2) (2025-04-16)
### [3.19.2](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.3...v3.19.2) (2025-04-16)
### [3.19.3](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.2...v3.19.3) (2025-04-16)
### [3.19.2](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.1...v3.19.2) (2025-04-09)
### [3.19.1](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.19.0...v3.19.1) (2025-04-09)
## [3.19.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.18.0...v3.19.0) (2025-03-27)
## [3.18.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.17.0...v3.18.0) (2025-03-18)
## [3.17.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.16.0...v3.17.0) (2025-02-14)
## [3.16.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.15.3...v3.16.0) (2024-10-28)
### [3.15.3](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.15.2...v3.15.3) (2024-08-28)
### [3.15.2](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.15.1...v3.15.2) (2024-08-16)
### [3.15.1](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.15.0...v3.15.1) (2024-07-12)
### Bug Fixes
* 添加储值支付 ([c74f28c](https://git.ishopex.cn/onex/ecshopx-newpc/commit/c74f28cd9b5ec1bffed7ed225e737d258ef8440a))
## [3.15.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.14.1...v3.15.0) (2024-07-08)
### [3.14.1](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.14.0...v3.14.1) (2024-04-12)
### Features
* 登录页logo、背景图支持后台配置 ([4ff9b07](https://git.ishopex.cn/onex/ecshopx-newpc/commit/4ff9b07cea9c71e9cbaa29466a250d47d1dbbac5))
## [3.14.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.13.5...v3.14.0) (2024-03-11)
### [3.13.5](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.13.4...v3.13.5) (2024-03-10)
### [3.13.4](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.13.3...v3.13.4) (2023-09-27)
### [3.13.3](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.13.2...v3.13.3) (2023-09-26)
### [3.13.2](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.13.1...v3.13.2) (2023-09-26)
### [3.13.1](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.13.0...v3.13.1) (2023-06-05)
## [3.13.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.12.1...v3.13.0) (2023-06-01)
### [3.12.1](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.12.0...v3.12.1) (2023-05-24)
## 3.12.0 (2023-05-18)
## [3.11.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.10.1...v3.11.0) (2023-04-24)
### [3.10.1](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.10.0...v3.10.1) (2023-03-14)
## [3.10.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.9.0...v3.10.0) (2023-02-09)
## [3.9.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.8.0...v3.9.0) (2023-01-05)
## [3.8.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.7.0...v3.8.0) (2022-12-15)
## [3.7.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.6.1...v3.7.0) (2022-11-24)
## [3.6.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.4.0...v3.6.0) (2022-10-31)
## [3.5.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.4.0...v3.5.0) (2022-09-29)
## [3.4.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.3.0...v3.4.0) (2022-09-16)
## [3.3.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.2.1...v3.3.0) (2022-08-31)
### [3.2.1](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.2.0...v3.2.1) (2022-08-25)
## [3.2.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.1.0...v3.2.0) (2022-08-04)
## [3.1.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v3.0.0...v3.1.0) (2022-07-21)
### Features
* 3.1.0 ([ef0bff5](https://git.ishopex.cn/onex/ecshopx-newpc/commit/ef0bff5862e674cba3e42f7f02d4ebb24efdee4b))
## [2.10.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v2.9.0...v2.10.0) (2022-06-23)
### Features
* 2.10.0 ([0099412](https://git.ishopex.cn/onex/ecshopx-newpc/commit/0099412d996328a8d91e654adfeb0e0cfcdac553))
## [2.9.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v2.8.0...v2.9.0) (2022-06-09)
### Features
* 2.9.0 ([484948c](https://git.ishopex.cn/onex/ecshopx-newpc/commit/484948ca8650d0858909e67fb408d9fcf4cf43c9))
## [2.8.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v2.7.0...v2.8.0) (2022-05-26)
### Features
* 2.8.0 ([9671a24](https://git.ishopex.cn/onex/ecshopx-newpc/commit/9671a24740c3692c534b644da377a96d6c9a693f))
## [2.7.0](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v2.6.3...v2.7.0) (2022-05-12)
### Features
* 2.7.0 ([db36624](https://git.ishopex.cn/onex/ecshopx-newpc/commit/db36624112ce32d8d73183b565d239b3bd390c9c))
### [2.6.3](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v2.6.2...v2.6.3) (2022-05-09)
### [2.6.2](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v2.6.1...v2.6.2) (2022-05-09)
### [1.1.1](https://git.ishopex.cn/onex/ecshopx-newpc/compare/v1.1.0...v1.1.1) (2021-05-13)
### Bug Fixes
* add changelog ([f71d9a0](https://git.ishopex.cn/onex/ecshopx-newpc/commit/f71d9a0230785d59ca9326538756df310197df3e))
## 1.1.0 (2021-05-13)
### Features
* 添加会员价 ([f2ee434](https://git.ishopex.cn/onex/ecshopx-newpc/commit/f2ee434f50739c4d75d123c7b8a631a6a0ee45ac))
### Bug Fixes
* bug修复 ([4ae80aa](https://git.ishopex.cn/onex/ecshopx-newpc/commit/4ae80aa99726076aeac0b9a91952b4bb43ca8bc3))
* merge ([38754a5](https://git.ishopex.cn/onex/ecshopx-newpc/commit/38754a51326cb1fb5b5dfa5ac5e99a921a39e6df))
* merge ([c1c7075](https://git.ishopex.cn/onex/ecshopx-newpc/commit/c1c70751953cdc5e33a732f43492516a2727f311))
* package.json ([389b447](https://git.ishopex.cn/onex/ecshopx-newpc/commit/389b4476bf467ec2b0b5986d0550c9cf4fcff227))
* por ([2e14978](https://git.ishopex.cn/onex/ecshopx-newpc/commit/2e14978d6ee02938d8491590ad7e892be1ffb006))
* port ([81137a0](https://git.ishopex.cn/onex/ecshopx-newpc/commit/81137a08cde3ba5aa7b932681be9ac66d9fafb1f))
* release version ([137e48a](https://git.ishopex.cn/onex/ecshopx-newpc/commit/137e48aa5dfb240d42ee14216f41f8b7931214ed))
* saas 独立域名 ([6aaefd2](https://git.ishopex.cn/onex/ecshopx-newpc/commit/6aaefd2cde30abfaac84f58533163a4b72e6829e))
* saas取消companyid ([9caac88](https://git.ishopex.cn/onex/ecshopx-newpc/commit/9caac881e7b73bbc98cb7a6ff3c883ae79e435cb))
* store commit ([fb04ec8](https://git.ishopex.cn/onex/ecshopx-newpc/commit/fb04ec82b18af6baac363d1dfbfb6566c656b464))
* 优化 ([572b09c](https://git.ishopex.cn/onex/ecshopx-newpc/commit/572b09cb69a4f860c86d247f88298271a1ef70cf))
* 会员价 ([c04ac5e](https://git.ishopex.cn/onex/ecshopx-newpc/commit/c04ac5e6546cdfd7d54dbd1aaa9b8c322af4efa2))
* 修改bug ([27be6e3](https://git.ishopex.cn/onex/ecshopx-newpc/commit/27be6e323fe46f6945dee0c9300f3227e8220165))
* 修改saas env变量 ([21367a5](https://git.ishopex.cn/onex/ecshopx-newpc/commit/21367a59f9532ee7c20b13e458433b57038d98a9))
* 修改UI ([628b85e](https://git.ishopex.cn/onex/ecshopx-newpc/commit/628b85ea4ac6e7c45119ddd835629b320e4e54ee))
* 修改购物车 ([bd158de](https://git.ishopex.cn/onex/ecshopx-newpc/commit/bd158de24e968a21e5d9ca4e8457636c996c023b))
* 注册优化 ([785a8ba](https://git.ishopex.cn/onex/ecshopx-newpc/commit/785a8ba837dfbec1524f10d1b5049d49c3949f65))
* 购物车优惠券选择 ([fdd4261](https://git.ishopex.cn/onex/ecshopx-newpc/commit/fdd42611d6299e367840cf99a4b481ea91cff8b9))
### 1.0.2 (2021-05-13)
### Bug Fixes
* bug修复 ([4ae80aa](https://git.ishopex.cn/onex/ecshopx-newpc/commit/4ae80aa99726076aeac0b9a91952b4bb43ca8bc3))
* merge ([38754a5](https://git.ishopex.cn/onex/ecshopx-newpc/commit/38754a51326cb1fb5b5dfa5ac5e99a921a39e6df))
* merge ([c1c7075](https://git.ishopex.cn/onex/ecshopx-newpc/commit/c1c70751953cdc5e33a732f43492516a2727f311))
* package.json ([389b447](https://git.ishopex.cn/onex/ecshopx-newpc/commit/389b4476bf467ec2b0b5986d0550c9cf4fcff227))
* por ([2e14978](https://git.ishopex.cn/onex/ecshopx-newpc/commit/2e14978d6ee02938d8491590ad7e892be1ffb006))
* port ([81137a0](https://git.ishopex.cn/onex/ecshopx-newpc/commit/81137a08cde3ba5aa7b932681be9ac66d9fafb1f))
* release version ([137e48a](https://git.ishopex.cn/onex/ecshopx-newpc/commit/137e48aa5dfb240d42ee14216f41f8b7931214ed))
* saas 独立域名 ([6aaefd2](https://git.ishopex.cn/onex/ecshopx-newpc/commit/6aaefd2cde30abfaac84f58533163a4b72e6829e))
* saas取消companyid ([9caac88](https://git.ishopex.cn/onex/ecshopx-newpc/commit/9caac881e7b73bbc98cb7a6ff3c883ae79e435cb))
* store commit ([fb04ec8](https://git.ishopex.cn/onex/ecshopx-newpc/commit/fb04ec82b18af6baac363d1dfbfb6566c656b464))
* 优化 ([572b09c](https://git.ishopex.cn/onex/ecshopx-newpc/commit/572b09cb69a4f860c86d247f88298271a1ef70cf))
* 修改bug ([27be6e3](https://git.ishopex.cn/onex/ecshopx-newpc/commit/27be6e323fe46f6945dee0c9300f3227e8220165))
* 修改saas env变量 ([21367a5](https://git.ishopex.cn/onex/ecshopx-newpc/commit/21367a59f9532ee7c20b13e458433b57038d98a9))
* 修改UI ([628b85e](https://git.ishopex.cn/onex/ecshopx-newpc/commit/628b85ea4ac6e7c45119ddd835629b320e4e54ee))
* 修改购物车 ([bd158de](https://git.ishopex.cn/onex/ecshopx-newpc/commit/bd158de24e968a21e5d9ca4e8457636c996c023b))
* 注册优化 ([785a8ba](https://git.ishopex.cn/onex/ecshopx-newpc/commit/785a8ba837dfbec1524f10d1b5049d49c3949f65))
### 1.0.1 (2021-05-13)
### Bug Fixes
* bug修复 ([4ae80aa](https://git.ishopex.cn/onex/ecshopx-newpc/commit/4ae80aa99726076aeac0b9a91952b4bb43ca8bc3))
* merge ([38754a5](https://git.ishopex.cn/onex/ecshopx-newpc/commit/38754a51326cb1fb5b5dfa5ac5e99a921a39e6df))
* merge ([c1c7075](https://git.ishopex.cn/onex/ecshopx-newpc/commit/c1c70751953cdc5e33a732f43492516a2727f311))
* package.json ([389b447](https://git.ishopex.cn/onex/ecshopx-newpc/commit/389b4476bf467ec2b0b5986d0550c9cf4fcff227))
* por ([2e14978](https://git.ishopex.cn/onex/ecshopx-newpc/commit/2e14978d6ee02938d8491590ad7e892be1ffb006))
* port ([81137a0](https://git.ishopex.cn/onex/ecshopx-newpc/commit/81137a08cde3ba5aa7b932681be9ac66d9fafb1f))
* release version ([137e48a](https://git.ishopex.cn/onex/ecshopx-newpc/commit/137e48aa5dfb240d42ee14216f41f8b7931214ed))
* saas 独立域名 ([6aaefd2](https://git.ishopex.cn/onex/ecshopx-newpc/commit/6aaefd2cde30abfaac84f58533163a4b72e6829e))
* saas取消companyid ([9caac88](https://git.ishopex.cn/onex/ecshopx-newpc/commit/9caac881e7b73bbc98cb7a6ff3c883ae79e435cb))
* store commit ([fb04ec8](https://git.ishopex.cn/onex/ecshopx-newpc/commit/fb04ec82b18af6baac363d1dfbfb6566c656b464))
* 优化 ([572b09c](https://git.ishopex.cn/onex/ecshopx-newpc/commit/572b09cb69a4f860c86d247f88298271a1ef70cf))
* 修改bug ([27be6e3](https://git.ishopex.cn/onex/ecshopx-newpc/commit/27be6e323fe46f6945dee0c9300f3227e8220165))
* 修改saas env变量 ([21367a5](https://git.ishopex.cn/onex/ecshopx-newpc/commit/21367a59f9532ee7c20b13e458433b57038d98a9))
* 修改UI ([628b85e](https://git.ishopex.cn/onex/ecshopx-newpc/commit/628b85ea4ac6e7c45119ddd835629b320e4e54ee))
* 修改购物车 ([bd158de](https://git.ishopex.cn/onex/ecshopx-newpc/commit/bd158de24e968a21e5d9ca4e8457636c996c023b))
* 注册优化 ([785a8ba](https://git.ishopex.cn/onex/ecshopx-newpc/commit/785a8ba837dfbec1524f10d1b5049d49c3949f65))
### 0.1.1 (2021-05-13)
### Bug Fixes
* bug修复 ([4ae80aa](https://git.ishopex.cn/onex/ecshopx-newpc/commit/4ae80aa99726076aeac0b9a91952b4bb43ca8bc3))
* merge ([38754a5](https://git.ishopex.cn/onex/ecshopx-newpc/commit/38754a51326cb1fb5b5dfa5ac5e99a921a39e6df))
* merge ([c1c7075](https://git.ishopex.cn/onex/ecshopx-newpc/commit/c1c70751953cdc5e33a732f43492516a2727f311))
* package.json ([389b447](https://git.ishopex.cn/onex/ecshopx-newpc/commit/389b4476bf467ec2b0b5986d0550c9cf4fcff227))
* por ([2e14978](https://git.ishopex.cn/onex/ecshopx-newpc/commit/2e14978d6ee02938d8491590ad7e892be1ffb006))
* port ([81137a0](https://git.ishopex.cn/onex/ecshopx-newpc/commit/81137a08cde3ba5aa7b932681be9ac66d9fafb1f))
* saas 独立域名 ([6aaefd2](https://git.ishopex.cn/onex/ecshopx-newpc/commit/6aaefd2cde30abfaac84f58533163a4b72e6829e))
* saas取消companyid ([9caac88](https://git.ishopex.cn/onex/ecshopx-newpc/commit/9caac881e7b73bbc98cb7a6ff3c883ae79e435cb))
* store commit ([fb04ec8](https://git.ishopex.cn/onex/ecshopx-newpc/commit/fb04ec82b18af6baac363d1dfbfb6566c656b464))
* 优化 ([572b09c](https://git.ishopex.cn/onex/ecshopx-newpc/commit/572b09cb69a4f860c86d247f88298271a1ef70cf))
* 修改bug ([27be6e3](https://git.ishopex.cn/onex/ecshopx-newpc/commit/27be6e323fe46f6945dee0c9300f3227e8220165))
* 修改saas env变量 ([21367a5](https://git.ishopex.cn/onex/ecshopx-newpc/commit/21367a59f9532ee7c20b13e458433b57038d98a9))
* 修改UI ([628b85e](https://git.ishopex.cn/onex/ecshopx-newpc/commit/628b85ea4ac6e7c45119ddd835629b320e4e54ee))
* 修改购物车 ([bd158de](https://git.ishopex.cn/onex/ecshopx-newpc/commit/bd158de24e968a21e5d9ca4e8457636c996c023b))
* 注册优化 ([785a8ba](https://git.ishopex.cn/onex/ecshopx-newpc/commit/785a8ba837dfbec1524f10d1b5049d49c3949f65))

View File

@@ -1,4 +1,4 @@
<p align="center"><img width="500" height="auto" alt="logo1" src="https://github.com/user-attachments/assets/097cbde6-cedd-42d0-a2d8-a0a0430289b5" /></p>
<p align="center"><img width="600" height="416" alt="logo2" src="https://github.com/user-attachments/assets/abf6c4c7-8cb1-477e-aea4-9e526cd8225a" /></p>
### <p align="center">Desktop Frontend</p>
@@ -7,7 +7,7 @@ Node.js (current LTS) and npm are required to run the project. To be sure about
### Installation
```
cd ecshopx-pc
cd ECShopX_desktop-frontend
npm i
```
@@ -21,6 +21,9 @@ VUE_APP_HOST=
# Backend API Base URL
VUE_APP_API_BASE_URL=
# Default Language VersionChinese:zhcn/English:en)
VUE_APP_DEFAULT_LANG=en
```
### Run project
@@ -32,3 +35,12 @@ npm run dev
```
npm run build
```
## License
Each ECShopX source file included in this distribution is licensed under the Apache License 2.0, together with the additional terms imposed by ShopeX.
Open Software License (Apache 2.0) Please see LICENSE.txt for the full text of the Apache 2.0 license.
每个包含在本发行版中的 ECShopX 源文件,均依据 Apache 2.0 开源许可证与ShopeX商派附加条款进行授权。
开源软件许可协议Apache 2.0 —— 请参阅 LICENSE.txt 文件以获取 Apache 2.0 协议的完整文本。

73
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ecshopx-pc",
"version": "4.0.0",
"version": "4.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ecshopx-pc",
"version": "4.0.0",
"version": "4.1.1",
"dependencies": {
"@nuxtjs/component-cache": "^1.1.5",
"@nuxtjs/device": "^1.2.4",
@@ -61,7 +61,7 @@
"qn-webpack": "^2.0.3",
"sass": "1.77.6",
"sass-loader": "10.5.2",
"standard-version": "^9.3.0",
"standard-version": "^9.5.0",
"webpack-merge": "^4.2.1"
}
},
@@ -10331,13 +10331,29 @@
}
},
"node_modules/buffer": {
"version": "4.9.2",
"resolved": "https://registry.npmmirror.com/buffer/-/buffer-4.9.2.tgz",
"integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
"version": "6.0.3",
"resolved": "https://packages.aliyun.com/664eb139ced1b9e566e182d4/npm/businesstech-apac/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/buffer-from": {
@@ -20028,6 +20044,17 @@
"vm-browserify": "^1.0.1"
}
},
"node_modules/node-libs-browser/node_modules/buffer": {
"version": "4.9.2",
"resolved": "https://packages.aliyun.com/664eb139ced1b9e566e182d4/npm/businesstech-apac/buffer/-/buffer-4.9.2.tgz",
"integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
"license": "MIT",
"dependencies": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
}
},
"node_modules/node-libs-browser/node_modules/punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/punycode/-/punycode-1.4.1.tgz",
@@ -25407,9 +25434,10 @@
},
"node_modules/standard-version": {
"version": "9.5.0",
"resolved": "https://registry.npmmirror.com/standard-version/-/standard-version-9.5.0.tgz",
"resolved": "https://packages.aliyun.com/664eb139ced1b9e566e182d4/npm/businesstech-apac/standard-version/-/standard-version-9.5.0.tgz",
"integrity": "sha512-3zWJ/mmZQsOaO+fOlsa0+QK90pwhNd042qEcw6hKFNoLFs7peGyvPffpEBbK/DSGPbyOvli0mUIFv5A4qTjh2Q==",
"dev": true,
"license": "ISC",
"dependencies": {
"chalk": "^2.4.2",
"conventional-changelog": "3.1.25",
@@ -36440,13 +36468,14 @@
}
},
"buffer": {
"version": "4.9.2",
"resolved": "https://registry.npmmirror.com/buffer/-/buffer-4.9.2.tgz",
"integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
"version": "6.0.3",
"resolved": "https://packages.aliyun.com/664eb139ced1b9e566e182d4/npm/businesstech-apac/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"optional": true,
"peer": true,
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"buffer-from": {
@@ -43862,6 +43891,16 @@
"vm-browserify": "^1.0.1"
},
"dependencies": {
"buffer": {
"version": "4.9.2",
"resolved": "https://packages.aliyun.com/664eb139ced1b9e566e182d4/npm/businesstech-apac/buffer/-/buffer-4.9.2.tgz",
"integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
}
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/punycode/-/punycode-1.4.1.tgz",
@@ -48029,7 +48068,7 @@
},
"standard-version": {
"version": "9.5.0",
"resolved": "https://registry.npmmirror.com/standard-version/-/standard-version-9.5.0.tgz",
"resolved": "https://packages.aliyun.com/664eb139ced1b9e566e182d4/npm/businesstech-apac/standard-version/-/standard-version-9.5.0.tgz",
"integrity": "sha512-3zWJ/mmZQsOaO+fOlsa0+QK90pwhNd042qEcw6hKFNoLFs7peGyvPffpEBbK/DSGPbyOvli0mUIFv5A4qTjh2Q==",
"dev": true,
"requires": {

View File

@@ -1,6 +1,6 @@
{
"name": "ecshopx-pc",
"version": "4.0.0",
"version": "4.1.1",
"private": true,
"repository": "https://git.ishopex.cn/onex/ecshopx-newpc.git",
"scripts": {
@@ -19,10 +19,8 @@
"upload": "node build/upload.js"
},
"dependencies": {
"nuxt": "^2.15.8",
"nuxt-i18n": "^6.28.1",
"@nuxtjs/device": "^1.2.4",
"@nuxtjs/component-cache": "^1.1.5",
"@nuxtjs/device": "^1.2.4",
"@nuxtjs/proxy": "^1.3.3",
"axios": "^0.26.0",
"cache-manager": "^2.10.0",
@@ -32,6 +30,8 @@
"lodash-es": "^4.17.11",
"md5": "^2.2.1",
"moment": "^2.24.0",
"nuxt": "^2.15.8",
"nuxt-i18n": "^6.28.1",
"qrcode": "^1.4.4",
"social-share.js": "^1.0.16",
"ssr-window": "^1.0.1",
@@ -45,8 +45,8 @@
"vue-hotzone": "^1.1.0",
"vue-infinite-scroll": "^2.0.2",
"vue-lazyload": "^1.2.6",
"vuex-persistedstate": "3.0.0",
"vue-template-compiler": "^2.7.10"
"vue-template-compiler": "^2.7.10",
"vuex-persistedstate": "3.0.0"
},
"devDependencies": {
"@vue/babel-preset-app": "^3.7.0",
@@ -66,13 +66,13 @@
"glob": "^7.1.4",
"husky": "^4.3.0",
"lint-staged": "^10.5.4",
"postcss-html": "^1.5.0",
"prettier-eslint-cli": "^5.0.0",
"process-argv-parser": "0.0.1",
"qn-webpack": "^2.0.3",
"sass": "1.77.6",
"sass-loader": "10.5.2",
"postcss-html": "^1.5.0",
"standard-version": "^9.3.0",
"standard-version": "^9.5.0",
"webpack-merge": "^4.2.1"
},
"postcss": {

View File

@@ -8,3 +8,7 @@ import req from './req'
export function getGlobalTdk(params) {
return req.get('/api/h5app/wxapp/pagestemplate/gettdk', params)
}
export function getPrivacySetting(params = {}) {
return req.get('/api/h5app/wxapp/company/privacy_setting_ck', params)
}

View File

@@ -47,6 +47,8 @@ const setCountryCode = (config) => {
// 根据语言设置 country_code
if (locale === 'en') {
country_code = 'en-CN'
} else if (locale === 'ar') {
country_code = 'ar-SA'
} else {
country_code = 'zh-CN'
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

1752
src/assets/lang/ar.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1748,5 +1748,8 @@
"W0010.index.258451-1": "A total of {0} products, total",
"W0010.index.258451-2": "enter the shopping cart",
"W0010.index.258451-3": "shopping cart",
"W0008.index.695137-0": "search"
"W0008.index.695137-0": "search",
"cookieConsent.description": "We Use Cookies\nIn addition to the cookies that are strictly necessary for the operation of this website, we use cookies and other tracking tools to remember your preference, to measure our website performance, to improve our understanding of your interests, and to send you cart notifications. Our partners use trackers to deliver personalised advertising based on your browsing habits and your profile, including by using profiling, or to allow you to share our content on your social networks.\n\nYou can click on \"Accept all cookies\" to consent to the above mentioned uses, click on \"Cookie Settings\" to configure your choices, or click on \"Continue without accepting\" button to refuse all the optional cookies. You may change your preferences, and in particular withdraw your consent, on our website at any moment.\n\nFor more information about these technologies and their use on this website, please consult our Cookie Policy.",
"cookieConsent.accept": "ACCEPT ALL",
"cookieConsent.reject": "REJECT ALL"
}

View File

@@ -5,6 +5,7 @@
import commonEn from './en.json'
import commonZh from './zh.json'
import commonAr from './ar.json'
export default {
'en': {
@@ -12,5 +13,8 @@ export default {
},
'zh': {
...commonZh
},
'ar': {
...commonAr
}
}

View File

@@ -1748,5 +1748,8 @@
"W0010.index.258451-1": "共{0}件商品,合计",
"W0010.index.258451-2": "进入购物车",
"W0010.index.258451-3": "购物车",
"W0008.index.695137-0": "搜索"
"W0008.index.695137-0": "搜索",
"cookieConsent.description": "我们使用 Cookie\n除了网站运行所必需的 Cookie 之外,我们还使用 Cookie 和其他跟踪工具来记住您的偏好、衡量网站性能、更好地了解您的兴趣,并向您发送购物车通知。我们的合作伙伴使用跟踪器根据您的浏览习惯和个人资料提供个性化广告(包括使用用户画像),或允许您在社交网络上分享我们的内容。\n\n您可以点击\"接受全部 Cookie\"来同意上述用途,点击\"Cookie 设置\"来配置您的选择,或点击\"继续而不接受\"按钮来拒绝所有可选 Cookie。您可以随时在我们的网站上更改您的偏好特别是撤回您的同意。\n\n有关这些技术及其在本网站上的使用的更多信息请查阅我们的 Cookie 政策。",
"cookieConsent.accept": "接受全部",
"cookieConsent.reject": "拒绝全部"
}

View File

@@ -195,7 +195,9 @@
.category-list {
position: absolute;
top: 42px;
left: 0;
width: 1000px;
direction: ltr;
// display: none;
height: 0;
overflow: hidden;

View File

@@ -0,0 +1,9 @@
/**
* Copyright © ShopeX http://www.shopex.cn. All rights reserved.
* See LICENSE file for license details.
*/
import CookieConsent from './index.vue'
export default CookieConsent

View File

@@ -0,0 +1,301 @@
/**
* Copyright © ShopeX http://www.shopex.cn. All rights reserved.
* See LICENSE file for license details.
*/
<template>
<transition name="cookie-consent-fade">
<div v-if="visible" class="cookie-consent">
<div class="cookie-consent__mask" @click="handleMaskClick"></div>
<div class="cookie-consent__content">
<div class="cookie-consent__body">
<div class="cookie-consent__text">
<div
class="cookie-consent__description"
v-if="privacyContent"
v-html="privacyContent"
></div>
<!-- <p class="cookie-consent__description" v-else>{{ $t('cookieConsent.description') }}</p> -->
</div>
<div class="cookie-consent__actions">
<button
@click="handleReject"
class="cookie-consent__btn cookie-consent__btn--reject"
>
{{ $t('cookieConsent.reject') }}
</button>
<button
@click="handleAccept"
class="cookie-consent__btn cookie-consent__btn--accept"
>
{{ $t('cookieConsent.accept') }}
</button>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
import cookie from '@/utils/cookie'
import { getPrivacySetting } from '@/api/global'
export default {
name: 'CookieConsent',
data() {
return {
visible: false,
privacyContent: ''
}
},
mounted() {
this.fetchPrivacyContent()
this.checkAndShow()
},
methods: {
/**
* 获取隐私协议内容
*/
async fetchPrivacyContent() {
try {
const res = await getPrivacySetting()
if (res && res.pc_privacy_content) {
this.privacyContent = res.pc_privacy_content
}
} catch (error) {
console.warn('Failed to fetch privacy content:', error)
// 如果接口失败,使用 i18n 翻译作为后备
}
},
/**
* 检查授权状态并显示弹框
*/
checkAndShow() {
// 仅在客户端执行
if (process.client) {
const consent = cookie.getCookieConsent()
// 如果未授权,显示弹框
if (consent === null) {
this.show()
}
}
},
/**
* 显示弹框
*/
show() {
this.visible = true
},
/**
* 隐藏弹框
*/
hide() {
this.visible = false
},
/**
* 处理同意操作
*/
handleAccept() {
cookie.setCookieConsent(true)
this.hide()
this.$emit('consent', true)
},
/**
* 处理拒绝操作
*/
handleReject() {
cookie.setCookieConsent(false)
this.hide()
this.$emit('reject', false)
},
/**
* 处理遮罩层点击(不允许点击关闭)
*/
handleMaskClick() {
// 根据设计需求,可能不允许点击遮罩关闭
// 如果需要允许,可以取消下面的注释
// this.handleReject()
}
}
}
</script>
<style lang="scss">
@import '@/style/variables';
@import '@/style/mixins';
@import '@/style/mixins/rtl';
.cookie-consent {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: $z-index-level-12;
display: flex;
align-items: center;
justify-content: center;
&__mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1;
}
&__content {
position: relative;
z-index: 2;
width: 80%;
max-width: 815px;
min-width: 320px;
background-color: #fff;
box-shadow: 0px 0px 10.7px 7px rgba(0, 0, 0, 0.17);
border-radius: 0;
}
&__body {
padding: 55px 44px;
display: flex;
flex-direction: column;
gap: 40px;
}
&__text {
width: 100%;
}
&__description {
font-family: 'Noto Sans SC', -apple-system, PingFang SC, Microsoft YaHei, "微软雅黑", Hiragino Sans GB, sans-serif;
font-size: 16px;
font-weight: 500;
line-height: 24px;
color: #000;
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
// HTML 内容样式
:deep(div) {
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
}
:deep(p) {
margin: 0 0 12px 0;
&:last-child {
margin-bottom: 0;
}
}
}
&__actions {
display: flex;
@include justify-content-end;
gap: 20px;
flex-shrink: 0;
}
&__btn {
font-family: 'Noto Sans SC', -apple-system, PingFang SC, Microsoft YaHei, "微软雅黑", Hiragino Sans GB, sans-serif;
font-size: 16px;
font-weight: 500;
line-height: normal;
text-align: center;
text-transform: uppercase;
white-space: nowrap;
cursor: pointer;
border: none;
outline: none;
transition: all 0.3s ease;
min-width: 140px;
padding: 12px 24px;
border-radius: 2px;
&--reject {
background-color: #fff;
color: #666666;
border: 1px solid #e5e5e5;
&:hover {
background-color: #f6f6f6;
border-color: #d9d9d9;
}
}
&--accept {
background-color: #000;
color: #fff;
border: 1px solid #000;
&:hover {
background-color: #333;
border-color: #333;
}
}
}
}
// 响应式设计
@include respond(sm) {
.cookie-consent {
&__content {
width: 90%;
max-width: 100%;
}
&__body {
padding: 40px 30px;
gap: 30px;
}
&__description {
font-size: 14px;
line-height: 20px;
}
&__actions {
flex-direction: column;
width: 100%;
}
&__btn {
width: 100%;
min-width: auto;
}
}
}
// 淡入淡出动画
.cookie-consent-fade {
&-enter-active,
&-leave-active {
transition: opacity 0.3s ease;
}
&-enter,
&-leave-to {
opacity: 0;
}
&-enter-active .cookie-consent__content,
&-leave-active .cookie-consent__content {
transition: transform 0.3s ease, opacity 0.3s ease;
}
&-enter .cookie-consent__content,
&-leave-to .cookie-consent__content {
transform: scale(0.95);
opacity: 0;
}
}
</style>

View File

@@ -4,19 +4,30 @@
*/
<template>
<div>
<div :dir="direction">
<slot />
</div>
</template>
<script>
import { getCurrentDirection } from '@/utils/rtl'
export default {
name: 'LayoutHoc',
computed: {
direction() {
return getCurrentDirection(this)
}
},
mounted() {
const getlanguageByPath = (path) => {
const zhKey = 'zh'
const enKey = 'en'
return path.includes(zhKey) ? 'zh' : path.includes(enKey) ? 'en' : null
const arKey = 'ar'
if (path.includes(zhKey)) return 'zh'
if (path.includes(enKey)) return 'en'
if (path.includes(arKey)) return 'ar'
return null
}
const language = getlanguageByPath(this.$route.path)
if (language && this.$store.state.locale != language) {

View File

@@ -10,7 +10,7 @@
.topbar-login {
a,
.name {
margin-right: 10px;
@include margin-inline-end(10px);
font-size: 13px;
color: #666;
}
@@ -22,17 +22,104 @@
.member-phone {
font-size: 13px;
color: $color-brand-primary;
margin-right: 10px;
@include margin-inline-end(10px);
}
.exit-btn {
font-size: 13px;
cursor: pointer;
}
.language-selector {
position: relative;
display: inline-block;
@include margin-inline-start(10px);
z-index: 1001;
pointer-events: auto;
&__current {
font-size: 13px;
color: #666;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 4px;
user-select: none;
pointer-events: auto;
position: relative;
z-index: 1002;
.ec-icon {
font-size: 12px;
transition: transform 0.2s ease;
color: #999;
&.active {
transform: rotate(180deg);
}
}
&:hover {
color: $color-brand-primary;
}
}
&__dropdown {
@include text-align-start;
position: fixed !important;
background: #fff;
border: 1px solid #dcdcdc;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
min-width: 120px;
z-index: 10000 !important;
list-style: none;
padding: 4px 0;
margin: 0;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
li {
padding: 8px 16px;
font-size: 13px;
color: #666;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
background: #f5f5f5;
color: $color-brand-primary;
}
&.active {
background: #f0f0f0;
color: $color-brand-primary;
font-weight: 500;
}
}
}
}
// 过渡动画
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-to,
.fade-leave {
opacity: 1;
}
}
.topbar-member {
a {
color: #666;
margin-right: 10px;
@include margin-inline-end(10px);
font-size: 13px;
}
}
@@ -44,7 +131,7 @@
}
.logo-con {
width: 25%;
float: left;
@include float-start;
img {
display: block;
cursor: pointer;
@@ -52,14 +139,14 @@
}
.search-con {
width: 50%;
float: left;
@include float-start;
margin-top: 7px;
}
.cart-con {
width: 25%;
float: left;
@include float-start;
margin-top: 7px;
text-align: right;
@include text-align-end;
.cart-link {
background: $color-brand-primary;
color: $color-primary-text;
@@ -70,10 +157,10 @@
display: inline-block;
border-radius: 5px;
position: relative;
.cart-icon {
.cart-icon {
display: inline-block;
position: relative;
margin-right: 5px;
@include margin-inline-end(5px);
height: 100%;
vertical-align: top;
.ec-icon-cart {
@@ -83,7 +170,7 @@
.count {
position: absolute;
top: 0;
right: 10px;
@include right(10px);
transform: translateY(-35%) translateX(100%);
border: 1px solid $color-brand-primary;
background: #fff;
@@ -121,7 +208,7 @@
}
}
&__btn {
float: left;
@include float-start;
height: 40px;
line-height: 40px;
width: 200px;
@@ -133,7 +220,9 @@
.category-list {
position: absolute;
top: 42px;
left: 0;
width: 1000px;
direction: ltr;
// display: none;
height: 0;
overflow: hidden;
@@ -206,11 +295,11 @@
}
}
.navs-con {
float: left;
margin-left: 60px;
@include float-start;
@include margin-inline-start(60px);
.nav-item {
float: left;
margin-right: 60px;
@include float-start;
@include margin-inline-end(60px);
a {
height: 40px;
line-height: 40px;

View File

@@ -15,7 +15,7 @@
<template>
<div class="header-bar">
<div class="header-bar__topbar">
<div class="container clearfix">
<div class="container ">
<div class="topbar-login fl">
<div class="no-login active">
<NuxtLink to="/" class="index-link">{{ $t('sp-header.index.663900-0') }}</NuxtLink>
@@ -32,9 +32,30 @@
<span class="member-phone">{{ userInfo.memberInfo.mobile }}</span>
<span class="exit-btn" @click="handleLogout()">{{ $t('sp-header.index.663900-4') }}</span>
</template>
<span @click="handleChangeLanguage">
{{ $t('sp-header.index.061123-0') }}{{ $i18n.locale == 'zh' ? $t('sp-header.index.061123-1') : $t('sp-header.index.061123-2') }}
</span>
<div class="language-selector" v-on-clickaway="closeLanguageDropdown">
<span
class="language-selector__current"
@click="toggleLanguageDropdown"
style="cursor: pointer;"
>
{{ getCurrentLanguageName() }}
<i class="ec-icon ec-icon-unfold" :class="{ 'active': showLanguageDropdown }"></i>
</span>
<ul
class="language-selector__dropdown"
v-if="showLanguageDropdown"
v-show="showLanguageDropdown"
>
<li
v-for="lang in availableLanguages"
:key="lang.code"
:class="{ 'active': lang.code === $i18n.locale }"
@click="handleChangeLanguage(lang.code)"
>
{{ lang.name }}
</li>
</ul>
</div>
</div>
</div>
<div class="topbar-member fr">
@@ -76,13 +97,36 @@ import S from '@/spx'
export default {
name: 'SpHeader',
mixins: [clickaway],
mounted() {
// 验证指令是否注册
console.log('SpHeader mounted')
console.log('Available directives:', Object.keys(this.$options.directives || {}))
console.log('onClickaway directive:', this.$options.directives?.onClickaway)
console.log('closeLanguageDropdown method:', typeof this.closeLanguageDropdown)
// 检查元素是否存在
this.$nextTick(() => {
const selector = this.$el.querySelector('.language-selector')
const current = this.$el.querySelector('.language-selector__current')
console.log('Language selector element:', selector)
console.log('Language selector current element:', current)
if (current) {
// 添加原生事件监听器测试
current.addEventListener('click', (e) => {
console.log('Native click event on language selector!', e)
this.toggleLanguageDropdown(e)
}, true) // 使用捕获阶段
}
})
},
data() {
return {
message: '',
basefile: 'newwapmall/block/header.html',
fixed: false,
showSubNav: null,
message: ''
showLanguageDropdown: false
}
},
watch: {
@@ -100,12 +144,77 @@ export default {
pageConfig: (state) => {
return state.pageConfig
}
})
}),
availableLanguages() {
return [
{ code: 'zh', name: '中文' },
{ code: 'en', name: 'English' },
{ code: 'ar', name: 'العربية' }
]
}
},
methods: {
handleChangeLanguage() {
this.$store.commit('SET_LANG', this.$i18n.locale == 'zh' ? 'en' : 'zh')
this.$i18n.setLocale(this.$i18n.locale == 'zh' ? 'en' : 'zh')
getCurrentLanguageName() {
if (!this.$i18n || !this.$i18n.locale) {
return '中文'
}
const currentLocale = this.$i18n.locale
const lang = this.availableLanguages.find(l => l.code === currentLocale)
return lang ? lang.name : '中文'
},
toggleLanguageDropdown(e) {
if (e) {
e.preventDefault()
e.stopPropagation()
}
this.showLanguageDropdown = !this.showLanguageDropdown
// 计算下拉菜单位置
if (this.showLanguageDropdown) {
this.$nextTick(() => {
const current = this.$el.querySelector('.language-selector__current')
const dropdown = this.$el.querySelector('.language-selector__dropdown')
if (current && dropdown) {
const rect = current.getBoundingClientRect()
dropdown.style.top = `${rect.bottom + 5}px`
dropdown.style.left = `${rect.left}px`
}
})
}
},
closeLanguageDropdown() {
this.showLanguageDropdown = false
},
handleChangeLanguage(locale) {
if (locale === this.$i18n.locale) {
this.closeLanguageDropdown()
return
}
this.$store.commit('SET_LANG', locale)
this.$i18n.setLocale(locale)
// 更新路由路径
const currentPath = this.$route.path
const pathLang = this.getlanguageByPath(currentPath)
let newPath = currentPath
if (pathLang) {
// 替换路径中的语言代码
newPath = currentPath.replace(`/${pathLang}`, `/${locale}`)
} else {
// 如果路径中没有语言代码,添加语言前缀
newPath = `/${locale}${currentPath === '/' ? '' : currentPath}`
}
this.closeLanguageDropdown()
this.$router.push({ path: newPath, query: this.$route.query })
},
getlanguageByPath(path) {
if (path.includes('/zh')) return 'zh'
if (path.includes('/en')) return 'en'
if (path.includes('/ar')) return 'ar'
return ''
},
handleLogout() {
this.$cookies.remove('ECSHOPX_TOKEN')

View File

@@ -31,6 +31,8 @@
.category-list {
position: absolute;
top: 40px;
left: 0;
direction: ltr;
font-size: 16px;
// width: 1000px;
// display: none;

View File

@@ -15,7 +15,7 @@
<template>
<LayoutHoc>
<div class="system-auth">
<div class="system-auth" :dir="direction">
<auth-header :logo="logo" />
<div class="page-body" :style="{ backgroundImage: `url(${bg})` }">
<Nuxt />
@@ -31,6 +31,7 @@ import "@/main";
import { mapActions, mapState } from "vuex";
import { Tracker } from "@/service";
import { isNativeBrower } from "@/utils";
import { getCurrentDirection } from '@/utils/rtl'
import backgroundImage from '@/assets/imgs/login_background.png'
import logoImage from '@/assets/imgs/login_yundian.jpg'
@@ -57,7 +58,10 @@ export default {
return res.params ? JSON.parse(res.params) : [];
}
})
}),
direction() {
return getCurrentDirection(this)
}
},
created() {
this.getPic()

View File

@@ -7,12 +7,13 @@
<template>
<LayoutHoc>
<div class="system-container">
<div class="system-container" :dir="direction">
<SpHeader />
<div class="page-body">
<Nuxt />
</div>
<SpFooter />
<CookieConsent />
</div>
</LayoutHoc>
</template>
@@ -24,9 +25,20 @@ import { mapActions, mapState } from 'vuex'
import { Tracker } from '@/service'
import { isNativeBrower } from '@/utils'
import { mixin } from '@/mixins'
import { getCurrentDirection } from '@/utils/rtl'
export default {
mixins: [mixin],
computed: {
...mapState({
pageSeo: (state) => {
return state.pageSeo
}
}),
direction() {
return getCurrentDirection(this)
}
},
head() {
return {
// title: this.pageSeo.title,
@@ -37,13 +49,6 @@ export default {
]
}
},
computed: {
...mapState({
pageSeo: (state) => {
return state.pageSeo
}
})
},
data() {
return {
pageOptions: {}

View File

@@ -15,12 +15,13 @@
<template>
<LayoutHoc>
<div class="shop-auth">
<div class="shop-auth" :dir="direction">
<shop-header v-if="show" />
<div class="page-body">
<Nuxt />
</div>
<sp-footer />
<CookieConsent />
</div>
</LayoutHoc>
</template>
@@ -30,6 +31,7 @@ import '@/main'
import { mapActions, mapState } from 'vuex'
import { Tracker } from '@/service'
import { isNativeBrower } from '@/utils'
import { getCurrentDirection } from '@/utils/rtl'
export default {
data () {
@@ -55,7 +57,10 @@ export default {
return res.params ? JSON.parse(res.params) : []
}
})
}),
direction() {
return getCurrentDirection(this)
}
},
created() {},
mounted() {

View File

@@ -3,26 +3,6 @@
* See LICENSE file for license details.
*/
// 开源标注信息
const licenseInfo = `
╔══════════════════════════════════════════════════════════════╗
║ ECShopX open source E-commerce ║
║ ECShopX 开源商城系统 ║
╠══════════════════════════════════════════════════════════════╣
║ Copyright (c) 2003-2025 ShopeX,Inc.All rights reserved. ║
║ Corporate Website: https://www.shopex.cn ║
║ Licensed under the Apache License, Version 2.0 ║
║ http://www.apache.org/licenses/LICENSE-2.0 ║
╠══════════════════════════════════════════════════════════════╣
║ The removal of shopeX copyright information without ║
║ authorization is prohibited. ║
║ 未经授权不可去除shopeX商派相关版权 ║
╠══════════════════════════════════════════════════════════════╣
║ Author: shopeX Team <mkt@shopex.cn> ║
║ Contact: 400-821-3106 ║
╚══════════════════════════════════════════════════════════════╝
`
import Vue from 'vue'
import VueLazyload from 'vue-lazyload'
// import ElementUI from 'element-ui';
@@ -73,6 +53,7 @@ import Widgets from "./espier-widgets";
import * as Filters from '@/filters'
import { TrackerPlugin } from '@/service'
import store from 'store'
import { directive as onClickawayDirective } from '@/plugins/clickaway'
// import 'swiper/css/swiper.css'
import plugin from './components/sp-modal/src/plugin'
@@ -187,6 +168,9 @@ const install = function(Vue, opts = {}) {
Vue.directive(name, directive)
})
// 全局注册 clickaway 指令(支持 v-on-clickaway 和 v-onClickaway
Vue.directive('onClickaway', onClickawayDirective)
Object.keys(Filters).forEach((key) => {
const { name, filter } = Filters[key]
if (key == 'formatPrice' || key == 'formatPriceToHundred' || key == 'parseTime') {
@@ -235,8 +219,3 @@ Vue.use(VueLazyload)
// }
Vue.prototype.$EventBus = new Vue()
// 在应用启动时打印开源标注信息(仅客户端)
if (process.client) {
console.log('%c' + licenseInfo, 'color: #3e76f6; font-family: monospace; line-height: 1.4;')
}

View File

@@ -11,6 +11,7 @@ export default function (context) {
const enPath = `en`
const zhPath = 'zh'
const arPath = 'ar'
const pathLang = getlanguageByPath(route.path)
let lang = pathLang || app.i18n.locale || defaultLocale
@@ -22,18 +23,17 @@ export default function (context) {
routePath.indexOf(`${lang}`) === -1 &&
defaultLocale !== lang
) {
const trans = routePath.indexOf(zhPath) !== -1
? {
c: zhPath,
r: enPath
}
: routePath.indexOf(enPath) !== -1
? {
c: enPath,
r: zhPath
}
: null;
const path = trans ? routePath.replace(trans.c, trans.r) : `/${`${lang}`}${routePath}`
// 支持三种语言之间的路径转换
let trans = null
if (routePath.indexOf(zhPath) !== -1) {
trans = { c: zhPath, r: lang }
} else if (routePath.indexOf(enPath) !== -1) {
trans = { c: enPath, r: lang }
} else if (routePath.indexOf(arPath) !== -1) {
trans = { c: arPath, r: lang }
}
const path = trans ? routePath.replace(trans.c, trans.r) : `/${lang}${routePath}`
return redirect({ path: path, query: route.query })
}
}

View File

@@ -6,8 +6,13 @@
.page-auth-login {
// margin: 50px auto 100px;
background: transparent;
height: 590px;
min-height: 590px;
display: flex;
align-items: center;
@include justify-content-end;
position: relative;
@include padding-inline-end(100px);
@include padding-inline-start(100px);
.login-logo{
left: auto;
// top: 100px;
@@ -19,10 +24,10 @@
background-color: rgba(255, 255, 255, 0.9);
width: 350px;
// height: 372px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
top: 82px;;
left: 844px;
position: relative;
padding: 5px;
.login-title {

View File

@@ -3,6 +3,8 @@
* See LICENSE file for license details.
*/
@import 'mixins/rtl';
@import "variables";
@function strip-unit($number) {

View File

@@ -56,11 +56,11 @@ ul {
}
.fl {
float: left;
@include float-start;
}
.fr {
float: right;
@include float-end;
}
.txt-center {

211
src/style/mixins/_rtl.scss Normal file
View File

@@ -0,0 +1,211 @@
/**
* Copyright © ShopeX http://www.shopex.cn. All rights reserved.
* See LICENSE file for license details.
*/
/**
* RTL (Right-to-Left) Mixin
* 用于支持从右到左的语言布局
*/
/**
* RTL 模式下的样式
* 用法: @include rtl { ... }
*/
@mixin rtl {
[dir="rtl"] & {
@content;
}
}
/**
* LTR 模式下的样式
* 用法: @include ltr { ... }
*/
@mixin ltr {
[dir="ltr"] &,
&:not([dir]) {
@content;
}
}
/**
* 方向感知的 margin-inline-start
* 在 LTR 中为 margin-left在 RTL 中为 margin-right
*/
@mixin margin-inline-start($value) {
margin-left: $value;
@include rtl {
margin-left: 0;
margin-right: $value;
}
}
/**
* 方向感知的 margin-inline-end
* 在 LTR 中为 margin-right在 RTL 中为 margin-left
*/
@mixin margin-inline-end($value) {
margin-right: $value;
@include rtl {
margin-right: 0;
margin-left: $value;
}
}
/**
* 方向感知的 padding-inline-start
* 在 LTR 中为 padding-left在 RTL 中为 padding-right
*/
@mixin padding-inline-start($value) {
padding-left: $value;
@include rtl {
padding-left: 0;
padding-right: $value;
}
}
/**
* 方向感知的 padding-inline-end
* 在 LTR 中为 padding-right在 RTL 中为 padding-left
*/
@mixin padding-inline-end($value) {
padding-right: $value;
@include rtl {
padding-right: 0;
padding-left: $value;
}
}
/**
* 方向感知的 border-inline-start
*/
@mixin border-inline-start($value) {
border-left: $value;
@include rtl {
border-left: none;
border-right: $value;
}
}
/**
* 方向感知的 border-inline-end
*/
@mixin border-inline-end($value) {
border-right: $value;
@include rtl {
border-right: none;
border-left: $value;
}
}
/**
* Float 到开始位置LTR 中为 leftRTL 中为 right
*/
@mixin float-start {
float: left;
@include rtl {
float: right;
}
}
/**
* Float 到结束位置LTR 中为 rightRTL 中为 left
*/
@mixin float-end {
float: right;
@include rtl {
float: left;
}
}
/**
* 文本对齐到开始位置LTR 中为 leftRTL 中为 right
*/
@mixin text-align-start {
text-align: left;
@include rtl {
text-align: right;
}
}
/**
* 文本对齐到结束位置LTR 中为 rightRTL 中为 left
*/
@mixin text-align-end {
text-align: right;
@include rtl {
text-align: left;
}
}
/**
* 方向感知的 left 定位
* 在 RTL 模式下转换为 right
*/
@mixin left($value) {
left: $value;
@include rtl {
left: auto;
right: $value;
}
}
/**
* 方向感知的 right 定位
* 在 RTL 模式下转换为 left
*/
@mixin right($value) {
right: $value;
@include rtl {
right: auto;
left: $value;
}
}
/**
* Flexbox 方向感知
* 在 RTL 模式下反转 flex-direction
*/
@mixin flex-direction-row {
flex-direction: row;
@include rtl {
flex-direction: row-reverse;
}
}
/**
* Justify-content 到开始位置
*/
@mixin justify-content-start {
justify-content: flex-start;
@include rtl {
justify-content: flex-end;
}
}
/**
* Justify-content 到结束位置
*/
@mixin justify-content-end {
justify-content: flex-end;
@include rtl {
justify-content: flex-start;
}
}

View File

@@ -152,19 +152,19 @@ textarea {
}
.f-l {
float: left;
@include float-start;
}
.f-r {
float: right;
@include float-end;
}
.t-r {
text-align: right !important;
@include text-align-end;
}
.t-l {
text-align: left !important;
@include text-align-start;
}
.t-c {

View File

@@ -33,6 +33,37 @@ class Cookie {
if (cval != null)
document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
}
/**
* 获取 Cookie 授权状态
* @returns {string|null} 'true' | 'false' | null
*/
getCookieConsent() {
if (typeof window === 'undefined' || !window.localStorage) {
return null
}
return window.localStorage.getItem('cookie_consent_authorized')
}
/**
* 设置 Cookie 授权状态
* @param {boolean} value - 授权状态
*/
setCookieConsent(value) {
if (typeof window === 'undefined' || !window.localStorage) {
return
}
window.localStorage.setItem('cookie_consent_authorized', String(value))
}
/**
* 检查是否已授权 Cookie
* @returns {boolean}
*/
hasCookieConsent() {
const consent = this.getCookieConsent()
return consent === 'true'
}
}
const cookie = new Cookie()

View File

@@ -11,6 +11,10 @@ export const getLanguage = () => {
export const getlanguageByPath = (path) => {
const zhKey = 'zh'
const enKey = 'en'
return path.includes(zhKey) ? 'zh' : path.includes(enKey) ? 'en' : ''
const arKey = 'ar'
if (path.includes(zhKey)) return 'zh'
if (path.includes(enKey)) return 'en'
if (path.includes(arKey)) return 'ar'
return ''
}

View File

@@ -15,6 +15,12 @@ export const locales = [
name: '中文',
iso: 'zh-CN',
language: 'zh-CN'
},
{
code: 'ar',
name: 'العربية',
iso: 'ar-SA',
language: 'ar-SA'
}
]

88
src/utils/rtl.js Normal file
View File

@@ -0,0 +1,88 @@
/**
* Copyright © ShopeX http://www.shopex.cn. All rights reserved.
* See LICENSE file for license details.
*/
/**
* RTL (Right-to-Left) 工具函数
* 用于检测和处理从右到左的语言布局
*/
/**
* RTL 语言列表
*/
const RTL_LOCALES = ['ar', 'he', 'fa', 'ur']
/**
* 检测指定语言是否为 RTL 语言
* @param {string} locale - 语言代码,如 'ar', 'zh', 'en'
* @returns {boolean} 是否为 RTL 语言
*/
export function isRTL(locale) {
if (!locale) {
return false
}
return RTL_LOCALES.includes(locale.toLowerCase())
}
/**
* 获取指定语言的文本方向
* @param {string} locale - 语言代码
* @returns {string} 'rtl' 或 'ltr'
*/
export function getDirection(locale) {
return isRTL(locale) ? 'rtl' : 'ltr'
}
/**
* 从 Vue 实例或上下文获取当前语言
* @param {Object} context - Vue 实例或包含 $i18n 的对象
* @returns {string} 当前语言代码
*/
export function getCurrentLocale(context = null) {
// 如果在 Vue 组件中,尝试从 $i18n 获取
if (context && context.$i18n) {
return context.$i18n.locale || 'en'
}
// 如果在 Nuxt 上下文中
if (process.client && window.$nuxt && window.$nuxt.$i18n) {
return window.$nuxt.$i18n.locale || 'en'
}
// 从 localStorage 获取
if (process.client) {
const stored = localStorage.getItem('i18n_redirected')
if (stored) {
try {
return JSON.parse(stored) || 'en'
} catch {
return stored || 'en'
}
}
}
// 默认返回英文
return process.env.VUE_APP_DEFAULT_LANG || 'en'
}
/**
* 检测当前语言是否为 RTL
* @param {Object} context - Vue 实例或上下文
* @returns {boolean} 是否为 RTL 语言
*/
export function isCurrentRTL(context = null) {
const locale = getCurrentLocale(context)
return isRTL(locale)
}
/**
* 获取当前语言的文本方向
* @param {Object} context - Vue 实例或上下文
* @returns {string} 'rtl' 或 'ltr'
*/
export function getCurrentDirection(context = null) {
const locale = getCurrentLocale(context)
return getDirection(locale)
}