feat: 国际化
parent
f0d66aff65
commit
e87316cc50
|
@ -5,6 +5,7 @@
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
|
"name": "playable-preview",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.10.4",
|
"@emotion/react": "^11.10.4",
|
||||||
|
@ -15,15 +16,21 @@
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"ali-oss": "^6.17.1",
|
"ali-oss": "^6.17.1",
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
|
"i18next": "^23.11.5",
|
||||||
|
"i18next-browser-languagedetector": "^8.0.0",
|
||||||
"localstorage-slim": "^2.2.0",
|
"localstorage-slim": "^2.2.0",
|
||||||
"qrcode": "^1.5.0",
|
"qrcode": "^1.5.0",
|
||||||
"query-string": "^7.1.1",
|
"query-string": "^7.1.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-copy-to-clipboard": "^5.0.4",
|
"react-copy-to-clipboard": "^5.0.4",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
"react-i18next": "^14.1.2",
|
||||||
"react-modal-login": "^2.0.7",
|
"react-modal-login": "^2.0.7",
|
||||||
"react-scripts": "5.0.0",
|
"react-scripts": "5.0.0",
|
||||||
"web-vitals": "^2.1.2"
|
"web-vitals": "^2.1.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"http-proxy-middleware": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@apideck/better-ajv-errors": {
|
"node_modules/@apideck/better-ajv-errors": {
|
||||||
|
@ -1531,11 +1538,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.18.9",
|
"version": "7.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz",
|
||||||
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
|
"integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
|
@ -1553,6 +1560,11 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@babel/runtime/node_modules/regenerator-runtime": {
|
||||||
|
"version": "0.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||||
|
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||||
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.16.0",
|
"version": "7.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz",
|
||||||
|
@ -3344,9 +3356,9 @@
|
||||||
"integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="
|
"integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/http-proxy": {
|
"node_modules/@types/http-proxy": {
|
||||||
"version": "1.17.8",
|
"version": "1.17.14",
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz",
|
||||||
"integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==",
|
"integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
|
@ -4696,11 +4708,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
@ -5606,14 +5618,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.3",
|
"version": "4.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
||||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0"
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/decamelize": {
|
"node_modules/decamelize": {
|
||||||
|
@ -7206,9 +7223,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
},
|
},
|
||||||
|
@ -7952,6 +7969,14 @@
|
||||||
"node": ">= 12"
|
"node": ">= 12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html-parse-stringify": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||||
|
"dependencies": {
|
||||||
|
"void-elements": "3.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/html-webpack-plugin": {
|
"node_modules/html-webpack-plugin": {
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
|
||||||
|
@ -8055,18 +8080,20 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/http-proxy-middleware": {
|
"node_modules/http-proxy-middleware": {
|
||||||
"version": "2.0.1",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz",
|
||||||
"integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==",
|
"integrity": "sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/http-proxy": "^1.17.5",
|
"@types/http-proxy": "^1.17.10",
|
||||||
|
"debug": "^4.3.4",
|
||||||
"http-proxy": "^1.18.1",
|
"http-proxy": "^1.18.1",
|
||||||
"is-glob": "^4.0.1",
|
"is-glob": "^4.0.1",
|
||||||
"is-plain-obj": "^3.0.0",
|
"is-plain-obj": "^3.0.0",
|
||||||
"micromatch": "^4.0.2"
|
"micromatch": "^4.0.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0.0"
|
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/https-proxy-agent": {
|
"node_modules/https-proxy-agent": {
|
||||||
|
@ -8097,6 +8124,36 @@
|
||||||
"ms": "^2.0.0"
|
"ms": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/i18next": {
|
||||||
|
"version": "23.11.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.5.tgz",
|
||||||
|
"integrity": "sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://locize.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://locize.com/i18next.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.23.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/i18next-browser-languagedetector": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.23.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
@ -10668,12 +10725,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
||||||
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
|
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"braces": "^3.0.1",
|
"braces": "^3.0.3",
|
||||||
"picomatch": "^2.2.3"
|
"picomatch": "^2.3.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
|
@ -11410,11 +11467,14 @@
|
||||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pirates": {
|
"node_modules/pirates": {
|
||||||
|
@ -13058,6 +13118,27 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
||||||
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/react-i18next": {
|
||||||
|
"version": "14.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.2.tgz",
|
||||||
|
"integrity": "sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.23.9",
|
||||||
|
"html-parse-stringify": "^3.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"i18next": ">= 23.2.3",
|
||||||
|
"react": ">= 16.8.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-native": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
@ -15137,6 +15218,14 @@
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/void-elements": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/w3c-hr-time": {
|
"node_modules/w3c-hr-time": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
||||||
|
@ -15357,6 +15446,29 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webpack-dev-server/node_modules/http-proxy-middleware": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/http-proxy": "^1.17.8",
|
||||||
|
"http-proxy": "^1.18.1",
|
||||||
|
"is-glob": "^4.0.1",
|
||||||
|
"is-plain-obj": "^3.0.0",
|
||||||
|
"micromatch": "^4.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/express": "^4.17.13"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/express": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/webpack-dev-server/node_modules/json-schema-traverse": {
|
"node_modules/webpack-dev-server/node_modules/json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
@ -17185,11 +17297,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
"version": "7.18.9",
|
"version": "7.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz",
|
||||||
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
|
"integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.14.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"regenerator-runtime": {
|
||||||
|
"version": "0.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||||
|
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/runtime-corejs3": {
|
"@babel/runtime-corejs3": {
|
||||||
|
@ -18570,9 +18689,9 @@
|
||||||
"integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="
|
"integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="
|
||||||
},
|
},
|
||||||
"@types/http-proxy": {
|
"@types/http-proxy": {
|
||||||
"version": "1.17.8",
|
"version": "1.17.14",
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz",
|
||||||
"integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==",
|
"integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
|
@ -19747,11 +19866,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"braces": {
|
"braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"browser-process-hrtime": {
|
"browser-process-hrtime": {
|
||||||
|
@ -20496,9 +20615,9 @@
|
||||||
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
|
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "4.3.3",
|
"version": "4.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
||||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
}
|
}
|
||||||
|
@ -21794,9 +21913,9 @@
|
||||||
"integrity": "sha512-sHvRqTiwdmcuzqet7iVwsbwF6UrV3wIgDf2SHNdY1Hgl8PC45HZg/0xtdw6U2izIV4lccnrY9ftl6wZFNdjYMg=="
|
"integrity": "sha512-sHvRqTiwdmcuzqet7iVwsbwF6UrV3wIgDf2SHNdY1Hgl8PC45HZg/0xtdw6U2izIV4lccnrY9ftl6wZFNdjYMg=="
|
||||||
},
|
},
|
||||||
"fill-range": {
|
"fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
}
|
}
|
||||||
|
@ -22395,6 +22514,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"html-parse-stringify": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||||
|
"requires": {
|
||||||
|
"void-elements": "3.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"html-webpack-plugin": {
|
"html-webpack-plugin": {
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
|
||||||
|
@ -22488,15 +22615,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"http-proxy-middleware": {
|
"http-proxy-middleware": {
|
||||||
"version": "2.0.1",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz",
|
||||||
"integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==",
|
"integrity": "sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/http-proxy": "^1.17.5",
|
"@types/http-proxy": "^1.17.10",
|
||||||
|
"debug": "^4.3.4",
|
||||||
"http-proxy": "^1.18.1",
|
"http-proxy": "^1.18.1",
|
||||||
"is-glob": "^4.0.1",
|
"is-glob": "^4.0.1",
|
||||||
"is-plain-obj": "^3.0.0",
|
"is-plain-obj": "^3.0.0",
|
||||||
"micromatch": "^4.0.2"
|
"micromatch": "^4.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"https-proxy-agent": {
|
"https-proxy-agent": {
|
||||||
|
@ -22521,6 +22650,22 @@
|
||||||
"ms": "^2.0.0"
|
"ms": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"i18next": {
|
||||||
|
"version": "23.11.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.5.tgz",
|
||||||
|
"integrity": "sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.23.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"i18next-browser-languagedetector": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.23.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
@ -24547,12 +24692,12 @@
|
||||||
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
|
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
|
||||||
},
|
},
|
||||||
"micromatch": {
|
"micromatch": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
||||||
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
|
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"braces": "^3.0.1",
|
"braces": "^3.0.3",
|
||||||
"picomatch": "^2.2.3"
|
"picomatch": "^2.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mime": {
|
"mime": {
|
||||||
|
@ -25134,9 +25279,9 @@
|
||||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
||||||
},
|
},
|
||||||
"picomatch": {
|
"picomatch": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
|
||||||
},
|
},
|
||||||
"pirates": {
|
"pirates": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
|
@ -26387,6 +26532,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
||||||
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
||||||
},
|
},
|
||||||
|
"react-i18next": {
|
||||||
|
"version": "14.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.2.tgz",
|
||||||
|
"integrity": "sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.23.9",
|
||||||
|
"html-parse-stringify": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
@ -26431,6 +26585,7 @@
|
||||||
"postcss-preset-env": "^7.0.1",
|
"postcss-preset-env": "^7.0.1",
|
||||||
"prompts": "^2.4.2",
|
"prompts": "^2.4.2",
|
||||||
"prop-types": "^15.8.0",
|
"prop-types": "^15.8.0",
|
||||||
|
"react": "^17.0.2",
|
||||||
"react-app-polyfill": "^3.0.0",
|
"react-app-polyfill": "^3.0.0",
|
||||||
"react-dev-utils": "^12.0.0",
|
"react-dev-utils": "^12.0.0",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
@ -28103,6 +28258,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"void-elements": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="
|
||||||
|
},
|
||||||
"w3c-hr-time": {
|
"w3c-hr-time": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
||||||
|
@ -28311,6 +28471,18 @@
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="
|
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="
|
||||||
},
|
},
|
||||||
|
"http-proxy-middleware": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/http-proxy": "^1.17.8",
|
||||||
|
"http-proxy": "^1.18.1",
|
||||||
|
"is-glob": "^4.0.1",
|
||||||
|
"is-plain-obj": "^3.0.0",
|
||||||
|
"micromatch": "^4.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
|
|
@ -12,12 +12,15 @@
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"ali-oss": "^6.17.1",
|
"ali-oss": "^6.17.1",
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
|
"i18next": "^23.11.5",
|
||||||
|
"i18next-browser-languagedetector": "^8.0.0",
|
||||||
"localstorage-slim": "^2.2.0",
|
"localstorage-slim": "^2.2.0",
|
||||||
"qrcode": "^1.5.0",
|
"qrcode": "^1.5.0",
|
||||||
"query-string": "^7.1.1",
|
"query-string": "^7.1.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-copy-to-clipboard": "^5.0.4",
|
"react-copy-to-clipboard": "^5.0.4",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
"react-i18next": "^14.1.2",
|
||||||
"react-modal-login": "^2.0.7",
|
"react-modal-login": "^2.0.7",
|
||||||
"react-scripts": "5.0.0",
|
"react-scripts": "5.0.0",
|
||||||
"web-vitals": "^2.1.2"
|
"web-vitals": "^2.1.2"
|
||||||
|
@ -45,5 +48,8 @@
|
||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"http-proxy-middleware": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
102
src/App.css
102
src/App.css
|
@ -1,48 +1,100 @@
|
||||||
.App {
|
.App {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-logo {
|
.App-logo {
|
||||||
height: 40vmin;
|
height: 40vmin;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
.App-logo {
|
.App-logo {
|
||||||
animation: App-logo-spin infinite 20s linear;
|
animation: App-logo-spin infinite 20s linear;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-header {
|
.App-header {
|
||||||
background-color: #282c34;
|
background-color: #282c34;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: calc(10px + 2vmin);
|
font-size: calc(10px + 2vmin);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-link {
|
.App-link {
|
||||||
color: #61dafb;
|
color: #61dafb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes App-logo-spin {
|
@keyframes App-logo-spin {
|
||||||
from {
|
from {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.MuiFormControlLabel-label {
|
.MuiFormControlLabel-label {
|
||||||
font-size: 13px !important;
|
font-size: 13px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.MuiDialog-root {
|
.MuiDialog-root {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane-btn {
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 0;
|
||||||
|
display: inline-block;
|
||||||
|
height: 30px;
|
||||||
|
width: 150px;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane-btn.checked {
|
||||||
|
background-color: #02b564;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane-btn + .pane-btn {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.generate-btn {
|
||||||
|
border-radius: 4px;
|
||||||
|
display: inline-block;
|
||||||
|
height: 40px;
|
||||||
|
width: 150px;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 22px;
|
||||||
|
background-color: rgb(82, 146, 242);
|
||||||
|
border: 1px #367fed solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-select-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
right: 40px;
|
||||||
|
top: 30px;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-select-container .language-select {
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 120px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-select-container .language-select fieldset {
|
||||||
|
display: none;
|
||||||
}
|
}
|
503
src/App.js
503
src/App.js
|
@ -8,12 +8,9 @@ import waterMarkPng from "./images/water-mark.png";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import SettingFrame from "./Components/settingsFrame";
|
import SettingFrame from "./Components/settingsFrame";
|
||||||
import QrCode from "qrcode";
|
import QrCode from "qrcode";
|
||||||
import {
|
import { getLoginInfo, getProjectSettingValue, setLoginInfo, setProjectSetting } from "./storage";
|
||||||
getLoginInfo,
|
import Select from "@mui/material/Select";
|
||||||
getProjectSettingValue,
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
setLoginInfo,
|
|
||||||
setProjectSetting,
|
|
||||||
} from "./storage";
|
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import Dialog from "@mui/material/Dialog";
|
import Dialog from "@mui/material/Dialog";
|
||||||
|
@ -23,271 +20,271 @@ import DialogTitle from "@mui/material/DialogTitle";
|
||||||
import Checkbox from "@mui/material/Checkbox";
|
import Checkbox from "@mui/material/Checkbox";
|
||||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
|
import { withTranslation } from "react-i18next";
|
||||||
|
import i18n from "i18next";
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
constructor() {
|
constructor(props) {
|
||||||
super();
|
super();
|
||||||
this.state = {
|
this.state = {
|
||||||
mode: "normal",
|
mode: "normal",
|
||||||
projects: [],
|
projects: [],
|
||||||
selectedProject: {},
|
selectedProject: {},
|
||||||
selectedProjectName: "",
|
selectedProjectName: "",
|
||||||
device: "android-h",
|
device: "android-h",
|
||||||
htmlUrl: "",
|
htmlUrl: "",
|
||||||
dataUrl: "",
|
dataUrl: "",
|
||||||
loading: false,
|
loading: false,
|
||||||
loginOpen: false,
|
loginOpen: false,
|
||||||
loginErrorMessage: "",
|
loginErrorMessage: "",
|
||||||
hideLogo: false,
|
hideLogo: false,
|
||||||
loginForm: {
|
loginForm: {
|
||||||
account: "",
|
account: "",
|
||||||
password: "",
|
password: "",
|
||||||
keepLogin: false,
|
keepLogin: false,
|
||||||
},
|
},
|
||||||
};
|
language: localStorage.getItem("lang") ?? "zh",
|
||||||
}
|
};
|
||||||
componentDidMount() {
|
this.t = props.t;
|
||||||
const loginInfo = getLoginInfo();
|
}
|
||||||
var tenant = utils.getTenant();
|
componentDidMount() {
|
||||||
const hideLogo = queryString.parseUrl(window.location.href)?.query
|
const loginInfo = getLoginInfo();
|
||||||
?.hideLogo;
|
var tenant = utils.getTenant();
|
||||||
this.setState({ hideLogo: !!hideLogo });
|
const hideLogo = queryString.parseUrl(window.location.href)?.query?.hideLogo;
|
||||||
if (loginInfo && loginInfo.permissionPages.includes(tenant)) {
|
this.setState({ hideLogo: !!hideLogo });
|
||||||
this.fetchData();
|
if (loginInfo && loginInfo.permissionPages.includes(tenant)) {
|
||||||
this.refreshQrCode();
|
this.fetchData();
|
||||||
} else {
|
this.refreshQrCode();
|
||||||
this.setState({ loginOpen: true });
|
} else {
|
||||||
loginInfo &&
|
this.setState({ loginOpen: true });
|
||||||
this.setState({ loginErrorMessage: "无权限访问,请切换账号" });
|
loginInfo && this.setState({ loginErrorMessage: "noAuth" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
login = async () => {
|
login = async () => {
|
||||||
var { account, password, keepLogin } = this.state.loginForm;
|
var { account, password, keepLogin } = this.state.loginForm;
|
||||||
var user = await LoginApi.UserLogin({ account, password });
|
var user = await LoginApi.UserLogin({ account, password });
|
||||||
var tenant = utils.getTenant();
|
var tenant = utils.getTenant();
|
||||||
|
|
||||||
if (user && user.permissionPages.includes(tenant)) {
|
if (user && user.permissionPages.includes(tenant)) {
|
||||||
this.setState({
|
this.setState({
|
||||||
loginOpen: false,
|
loginOpen: false,
|
||||||
});
|
});
|
||||||
if (keepLogin) {
|
if (keepLogin) {
|
||||||
setLoginInfo(user);
|
setLoginInfo(user);
|
||||||
}
|
}
|
||||||
this.fetchData();
|
this.fetchData();
|
||||||
this.refreshQrCode();
|
this.refreshQrCode();
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
loginErrorMessage: user
|
loginErrorMessage: user ? "noAuth" : "loginError",
|
||||||
? `无权限访问${tenant},请切换账号`
|
});
|
||||||
: "账号或密码错误",
|
}
|
||||||
});
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
refreshQrCode() {
|
refreshQrCode() {
|
||||||
var { selectedProject } = this.state;
|
var { selectedProject } = this.state;
|
||||||
selectedProject.HtmlUrl &&
|
selectedProject.HtmlUrl &&
|
||||||
QrCode.toDataURL([{ data: this.selectedProjectUrl, mode: "byte" }], {
|
QrCode.toDataURL([{ data: this.selectedProjectUrl, mode: "byte" }], {
|
||||||
width: 120,
|
width: 120,
|
||||||
}).then((dataUrl) => {
|
}).then((dataUrl) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
dataUrl: dataUrl,
|
dataUrl: dataUrl,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedProjectUrl() {
|
get selectedProjectUrl() {
|
||||||
var { selectedProject } = this.state;
|
var { selectedProject } = this.state;
|
||||||
var settingValue = getProjectSettingValue(selectedProject?.Name) || [
|
var settingValue = getProjectSettingValue(selectedProject?.Name) || [1, 1, 1];
|
||||||
1, 1, 1,
|
var rawUrl = selectedProject?.HtmlUrl ? encodeURI(selectedProject?.HtmlUrl) : "";
|
||||||
];
|
if (rawUrl) {
|
||||||
var rawUrl = selectedProject?.HtmlUrl
|
rawUrl += `?datanumber=${settingValue[0]}&datanumber1=${settingValue[1]}&datanumber2=${settingValue[2]}&lunaOrHtml=false`;
|
||||||
? encodeURI(selectedProject?.HtmlUrl)
|
}
|
||||||
: "";
|
|
||||||
if (rawUrl) {
|
|
||||||
rawUrl += `?datanumber=${settingValue[0]}&datanumber1=${settingValue[1]}&datanumber2=${settingValue[2]}&lunaOrHtml=false`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rawUrl;
|
return rawUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
async setSelectedProject(selectedProjectName) {
|
async setSelectedProject(selectedProjectName) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedProjectName: selectedProjectName,
|
selectedProjectName: selectedProjectName,
|
||||||
});
|
});
|
||||||
console.log("selected:", selectedProjectName);
|
console.log("selected:", selectedProjectName);
|
||||||
await this.updateSelectedProject(selectedProjectName);
|
await this.updateSelectedProject(selectedProjectName);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateSelectedProject(projectName) {
|
async updateSelectedProject(projectName) {
|
||||||
var projectSetting = await ProjectApi.getProjectSetting(projectName);
|
var projectSetting = await ProjectApi.getProjectSetting(projectName);
|
||||||
this.setState({
|
if (projectSetting.TextObjStr) {
|
||||||
selectedProject: projectSetting,
|
const none = `${this.t("none")}|${this.t("none")}|${this.t("none")}`;
|
||||||
});
|
if (projectSetting.TextObjStr.CentText === "无|无|无") {
|
||||||
}
|
projectSetting.TextObjStr.CentText = none;
|
||||||
|
}
|
||||||
|
if (projectSetting.TextObjStr.MiddText === "无|无|无") {
|
||||||
|
projectSetting.TextObjStr.MiddText = none;
|
||||||
|
}
|
||||||
|
if (projectSetting.TextObjStr.TopText === "无|无|无") {
|
||||||
|
projectSetting.TextObjStr.TopText = none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
selectedProject: projectSetting,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setDevice(selected) {
|
setDevice(selected) {
|
||||||
this.setState({
|
this.setState({
|
||||||
device: selected,
|
device: selected,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setMode(mode) {
|
setMode(mode) {
|
||||||
this.setState({
|
this.setState({
|
||||||
mode: mode,
|
mode: mode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoginForm(form) {
|
setLoginForm(form) {
|
||||||
this.setState({
|
this.setState({
|
||||||
loginForm: {
|
loginForm: {
|
||||||
...this.state.loginForm,
|
...this.state.loginForm,
|
||||||
...form,
|
...form,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchData() {
|
async fetchData() {
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: true,
|
loading: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
var projectNames = (await this.fetchProjects()) || ["无项目"];
|
var projectNames = (await this.fetchProjects()) || ["无项目"];
|
||||||
this.setState({
|
this.setState({
|
||||||
projects: projectNames,
|
projects: projectNames,
|
||||||
selectedProjectName: projectNames[0],
|
selectedProjectName: projectNames[0],
|
||||||
loading: false,
|
loading: false,
|
||||||
});
|
});
|
||||||
await this.updateSelectedProject(projectNames[0]);
|
await this.updateSelectedProject(projectNames[0]);
|
||||||
this.refreshQrCode();
|
this.refreshQrCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchProjects() {
|
async fetchProjects() {
|
||||||
return await ProjectApi.getProjects();
|
return await ProjectApi.getProjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
get projectSettingValue() {
|
get projectSettingValue() {
|
||||||
return getProjectSettingValue(this.state.selectedProjectName);
|
return getProjectSettingValue(this.state.selectedProjectName);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateSetting(obj) {
|
UpdateSetting(obj) {
|
||||||
setProjectSetting(this.state.selectedProject.Name, [
|
setProjectSetting(this.state.selectedProject.Name, [+obj.topType, +obj.centreType, +obj.middleType]);
|
||||||
+obj.topType,
|
}
|
||||||
+obj.centreType,
|
|
||||||
+obj.middleType,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var {
|
var { mode, device, projects, selectedProject, dataUrl, loading, loginOpen, loginForm, hideLogo, language } = this.state;
|
||||||
mode,
|
const { t } = this.props;
|
||||||
device,
|
|
||||||
projects,
|
|
||||||
selectedProject,
|
|
||||||
dataUrl,
|
|
||||||
loading,
|
|
||||||
loginOpen,
|
|
||||||
loginForm,
|
|
||||||
hideLogo,
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<Dialog open={loginOpen}>
|
<Dialog open={loginOpen}>
|
||||||
<DialogTitle>登录</DialogTitle>
|
<DialogTitle>{t("login")}</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<TextField
|
<TextField
|
||||||
autoFocus
|
autoFocus
|
||||||
margin="dense"
|
margin="dense"
|
||||||
id="name"
|
id="name"
|
||||||
label="账号"
|
label={t("account")}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={loginForm.account}
|
value={loginForm.account}
|
||||||
variant="standard"
|
variant="standard"
|
||||||
onChange={(e) => this.setLoginForm({ account: e.target.value })}
|
onChange={(e) => this.setLoginForm({ account: e.target.value })}
|
||||||
onKeyDown={(e) => e.keyCode === 13 && this.login()}
|
onKeyDown={(e) => e.keyCode === 13 && this.login()}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
autoFocus
|
autoFocus
|
||||||
margin="dense"
|
margin="dense"
|
||||||
id="name"
|
id="name"
|
||||||
label="密码"
|
label={t("password")}
|
||||||
type={"password"}
|
type={"password"}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={loginForm.password}
|
value={loginForm.password}
|
||||||
variant="standard"
|
variant="standard"
|
||||||
onChange={(e) => this.setLoginForm({ password: e.target.value })}
|
onChange={(e) => this.setLoginForm({ password: e.target.value })}
|
||||||
onKeyDown={(e) => e.keyCode === 13 && this.login()}
|
onKeyDown={(e) => e.keyCode === 13 && this.login()}
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
{this.state.loginErrorMessage && (
|
{this.state.loginErrorMessage && (
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: "red",
|
color: "red",
|
||||||
fontSize: "12px",
|
fontSize: "12px",
|
||||||
margin: "0 auto 0 10px",
|
margin: "0 auto 0 10px",
|
||||||
}}
|
}}>
|
||||||
>
|
{t(this.state.loginErrorMessage)}
|
||||||
{this.state.loginErrorMessage}
|
</span>
|
||||||
</span>
|
)}
|
||||||
)}
|
<FormControlLabel
|
||||||
<FormControlLabel
|
control={<Checkbox checked={loginForm.keepLogin} onChange={(_, checked) => this.setLoginForm({ keepLogin: checked })} />}
|
||||||
control={
|
label={t("keepLoginStatus")}
|
||||||
<Checkbox
|
/>
|
||||||
checked={loginForm.keepLogin}
|
<Button onClick={() => this.login()}>{t("submit")}</Button>
|
||||||
onChange={(_, checked) =>
|
</DialogActions>
|
||||||
this.setLoginForm({ keepLogin: checked })
|
</Dialog>
|
||||||
}
|
<Pane
|
||||||
/>
|
mode={mode}
|
||||||
}
|
onModeChange={(_mode) => this.setMode(_mode)}
|
||||||
label="保持登录状态7天"
|
projects={projects}
|
||||||
/>
|
device={device}
|
||||||
<Button onClick={() => this.login()}>提交</Button>
|
loading={loading}
|
||||||
</DialogActions>
|
hideLogo={hideLogo}
|
||||||
</Dialog>
|
onProjectSelect={(project) => {
|
||||||
<Pane
|
this.setSelectedProject(project);
|
||||||
mode={mode}
|
}}
|
||||||
onModeChange={(_mode) => this.setMode(_mode)}
|
onDeviceChange={(_device) => this.setDevice(_device)}
|
||||||
projects={projects}
|
/>
|
||||||
device={device}
|
<div className="language-select-container">
|
||||||
loading={loading}
|
<div>{t("language")}:</div>
|
||||||
hideLogo={hideLogo}
|
<Select
|
||||||
onProjectSelect={(project) => {
|
className="language-select"
|
||||||
this.setSelectedProject(project);
|
value={language}
|
||||||
}}
|
label={t("language")}
|
||||||
onDeviceChange={(_device) => this.setDevice(_device)}
|
sx={{
|
||||||
/>
|
background: "rgb(115, 158, 211)",
|
||||||
<div
|
width: "80%",
|
||||||
style={{
|
color: "white",
|
||||||
display: "flex",
|
}}
|
||||||
flex: 1,
|
onChange={(e) => {
|
||||||
alignItems: "center",
|
let lang = e.target.value;
|
||||||
backgroundImage: hideLogo ? "" : `url(${waterMarkPng})`,
|
this.setState({
|
||||||
backgroundPositionX: "right",
|
language: lang,
|
||||||
backgroundPositionY: "bottom",
|
});
|
||||||
backgroundRepeat: "no-repeat",
|
i18n.changeLanguage(lang);
|
||||||
}}
|
localStorage.setItem("lang", lang);
|
||||||
>
|
}}>
|
||||||
{mode === "normal" ? (
|
<MenuItem value="en">English</MenuItem>
|
||||||
<DeviceFrame
|
<MenuItem value="zh">Chinese</MenuItem>
|
||||||
htmlUrl={this.selectedProjectUrl}
|
</Select>
|
||||||
device={device}
|
</div>
|
||||||
qrDataUrl={dataUrl}
|
<div
|
||||||
refreshQrCode={() => this.refreshQrCode()}
|
style={{
|
||||||
/>
|
display: "flex",
|
||||||
) : (
|
flex: 1,
|
||||||
<SettingFrame
|
alignItems: "center",
|
||||||
setting={selectedProject?.TextObjStr}
|
backgroundImage: hideLogo ? "" : `url(${waterMarkPng})`,
|
||||||
settingValue={this.projectSettingValue}
|
backgroundPositionX: "right",
|
||||||
generate={(value) => this.UpdateSetting(value)}
|
backgroundPositionY: "bottom",
|
||||||
/>
|
backgroundRepeat: "no-repeat",
|
||||||
)}
|
}}>
|
||||||
</div>
|
{mode === "normal" ? (
|
||||||
</div>
|
<DeviceFrame htmlUrl={this.selectedProjectUrl} device={device} qrDataUrl={dataUrl} refreshQrCode={() => this.refreshQrCode()} />
|
||||||
);
|
) : (
|
||||||
}
|
<SettingFrame setting={selectedProject?.TextObjStr} settingValue={this.projectSettingValue} generate={(value) => this.UpdateSetting(value)} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default withTranslation()(App);
|
||||||
|
|
|
@ -18,6 +18,6 @@
|
||||||
|
|
||||||
.qrCode {
|
.qrCode {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 30px;
|
right: 40px;
|
||||||
top: 30px;
|
top: 100px;
|
||||||
}
|
}
|
|
@ -1,117 +1,124 @@
|
||||||
import './index.css'
|
import "./index.css";
|
||||||
import androidHPng from '../../images/android-h.png'
|
import androidHPng from "../../images/android-h.png";
|
||||||
import androidVPng from '../../images/android-v.png'
|
import androidVPng from "../../images/android-v.png";
|
||||||
import iphoneHPng from '../../images/iphone-h.png'
|
import iphoneHPng from "../../images/iphone-h.png";
|
||||||
import iphoneVPng from '../../images/iphone-v.png'
|
import iphoneVPng from "../../images/iphone-v.png";
|
||||||
import ipadHPng from '../../images/iPad-h.png'
|
import ipadHPng from "../../images/iPad-h.png";
|
||||||
import ipadVPng from '../../images/iPad-v.png'
|
import ipadVPng from "../../images/iPad-v.png";
|
||||||
import copyPng from '../../images/copy.png'
|
import copyPng from "../../images/copy.png";
|
||||||
import refreshButtonPng from '../../images/refresh-button.png'
|
import refreshButtonPng from "../../images/refresh-button.png";
|
||||||
import {CopyToClipboard} from 'react-copy-to-clipboard';
|
import { CopyToClipboard } from "react-copy-to-clipboard";
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from "react";
|
||||||
import { BaseUrl } from '../../constants'
|
import { BaseUrl } from "../../constants";
|
||||||
import { Alert, Snackbar } from '@mui/material'
|
import { Alert, Snackbar } from "@mui/material";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
var configMap = {
|
var configMap = {
|
||||||
"android-h": {
|
"android-h": {
|
||||||
bkg: androidHPng,
|
bkg: androidHPng,
|
||||||
width: '512px',
|
width: "512px",
|
||||||
height: '286px',
|
height: "286px",
|
||||||
offsetv: '5px',
|
offsetv: "5px",
|
||||||
},
|
},
|
||||||
"android-v": {
|
"android-v": {
|
||||||
bkg: androidVPng,
|
bkg: androidVPng,
|
||||||
width: '286px',
|
width: "286px",
|
||||||
height: '512px',
|
height: "512px",
|
||||||
offsetv: '5px',
|
offsetv: "5px",
|
||||||
},
|
},
|
||||||
"iphone-h": {
|
"iphone-h": {
|
||||||
bkg: iphoneHPng,
|
bkg: iphoneHPng,
|
||||||
width: '628px',
|
width: "628px",
|
||||||
height: '322px'
|
height: "322px",
|
||||||
},
|
},
|
||||||
"iphone-v": {
|
"iphone-v": {
|
||||||
bkg: iphoneVPng,
|
bkg: iphoneVPng,
|
||||||
width: '322px',
|
width: "322px",
|
||||||
height: '628px'
|
height: "628px",
|
||||||
},
|
},
|
||||||
"ipad-h": {
|
"ipad-h": {
|
||||||
bkg: ipadHPng,
|
bkg: ipadHPng,
|
||||||
width: '433px',
|
width: "433px",
|
||||||
height: '326px',
|
height: "326px",
|
||||||
offsetv: '5px',
|
offsetv: "5px",
|
||||||
},
|
},
|
||||||
"ipad-v": {
|
"ipad-v": {
|
||||||
bkg: ipadVPng,
|
bkg: ipadVPng,
|
||||||
width: '324px',
|
width: "324px",
|
||||||
height: '433px',
|
height: "433px",
|
||||||
offsetv: '5px',
|
offsetv: "5px",
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
function DeviceFrame(props) {
|
function DeviceFrame(props) {
|
||||||
var [config, setConfig] = useState({})
|
var [config, setConfig] = useState({});
|
||||||
var [cacheKey, setCacheKey] = useState(new Date().getTime());
|
var [cacheKey, setCacheKey] = useState(new Date().getTime());
|
||||||
var [openPopup, setOpenPopup] = useState(false);
|
var [openPopup, setOpenPopup] = useState(false);
|
||||||
var [absoluteUrl, setAbsoluteUrl] = useState('');
|
var [absoluteUrl, setAbsoluteUrl] = useState("");
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setConfig(configMap[props.device])
|
setConfig(configMap[props.device]);
|
||||||
}, [props.device, config])
|
}, [props.device, config]);
|
||||||
|
|
||||||
var refresh = () => setCacheKey(new Date().getTime());
|
var refresh = () => setCacheKey(new Date().getTime());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('触发更新', props.htmlUrl);
|
console.log("触发更新", props.htmlUrl);
|
||||||
props.htmlUrl && setAbsoluteUrl(!props.htmlUrl.startsWith("http") ? BaseUrl + props.htmlUrl : props.htmlUrl);
|
props.htmlUrl && setAbsoluteUrl(!props.htmlUrl.startsWith("http") ? BaseUrl + props.htmlUrl : props.htmlUrl);
|
||||||
refresh()
|
refresh();
|
||||||
props.refreshQrCode()
|
props.refreshQrCode();
|
||||||
}, [props.htmlUrl])
|
}, [props.htmlUrl]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='deviceFrameContainer'>
|
<div className="deviceFrameContainer">
|
||||||
<img src={refreshButtonPng} alt='refresh' onClick={() => refresh()} className='refreshButton'/>
|
<img src={refreshButtonPng} alt="refresh" onClick={() => refresh()} className="refreshButton" />
|
||||||
{ props.qrDataUrl &&
|
{props.qrDataUrl && (
|
||||||
<div className='qrCode'>
|
<div className="qrCode">
|
||||||
<p style={{ margin: '0' }}>扫一扫,手机预览
|
<p style={{ margin: "0" }}>
|
||||||
<CopyToClipboard text={absoluteUrl} onCopy={() => setOpenPopup(true)}>
|
{t("scan")}
|
||||||
<img style={{ cursor: 'pointer', width: '20px', height: '20px' }} src={copyPng} alt='复制链接'/>
|
<CopyToClipboard text={absoluteUrl} onCopy={() => setOpenPopup(true)}>
|
||||||
</CopyToClipboard>
|
<img style={{ cursor: "pointer", width: "20px", height: "20px" }} src={copyPng} alt="复制链接" />
|
||||||
</p>
|
</CopyToClipboard>
|
||||||
<img src={props.qrDataUrl} alt='qr code'/>
|
</p>
|
||||||
</div>
|
<img src={props.qrDataUrl} alt="qr code" />
|
||||||
}
|
</div>
|
||||||
<Snackbar open={openPopup} onClose={() => setOpenPopup(false)} autoHideDuration={500} anchorOrigin={{
|
)}
|
||||||
vertical: 'top',
|
<Snackbar
|
||||||
horizontal: 'right'
|
open={openPopup}
|
||||||
}}>
|
onClose={() => setOpenPopup(false)}
|
||||||
<Alert severity="success" sx={{ width: '100%' }}>
|
autoHideDuration={500}
|
||||||
链接复制成功
|
anchorOrigin={{
|
||||||
</Alert>
|
vertical: "top",
|
||||||
</Snackbar>
|
horizontal: "right",
|
||||||
<div>
|
}}>
|
||||||
<img src={config.bkg} alt='background'/>
|
<Alert severity="success" sx={{ width: "100%" }}>
|
||||||
{
|
{t("copySuccess")}
|
||||||
props.htmlUrl
|
</Alert>
|
||||||
&& <iframe
|
</Snackbar>
|
||||||
id='deviceFrame'
|
<div>
|
||||||
style={{
|
<img src={config.bkg} alt="background" />
|
||||||
position: 'absolute',
|
{props.htmlUrl && (
|
||||||
top: '50%',
|
<iframe
|
||||||
left: '50%',
|
id="deviceFrame"
|
||||||
transform: 'translate(-50%, -50%)',
|
style={{
|
||||||
paddingBottom: config.offsetv
|
position: "absolute",
|
||||||
}}
|
top: "50%",
|
||||||
allow="clipboard-read; clipboard-write *"
|
left: "50%",
|
||||||
title='preview'
|
transform: "translate(-50%, -50%)",
|
||||||
src={absoluteUrl + '&cacheKey=' + cacheKey}
|
paddingBottom: config.offsetv,
|
||||||
width={config.width}
|
}}
|
||||||
height={config.height}
|
allow="clipboard-read; clipboard-write *"
|
||||||
frameBorder={'0'}/>
|
title="preview"
|
||||||
}
|
src={absoluteUrl + "&cacheKey=" + cacheKey}
|
||||||
</div>
|
width={config.width}
|
||||||
</div>
|
height={config.height}
|
||||||
)
|
frameBorder={"0"}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DeviceFrame;
|
export default DeviceFrame;
|
|
@ -12,161 +12,136 @@ import horizentalButton from "../../images/horizental-button.png";
|
||||||
import verticalChecked from "../../images/vertical-button-checked.png";
|
import verticalChecked from "../../images/vertical-button-checked.png";
|
||||||
import verticalButton from "../../images/vertical-button.png";
|
import verticalButton from "../../images/vertical-button.png";
|
||||||
import modeSelectPng from "../../images/mode-select.png";
|
import modeSelectPng from "../../images/mode-select.png";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
var deviceConfigs = [
|
var deviceConfigs = [
|
||||||
{
|
{
|
||||||
name: "iPhone",
|
name: "iPhone",
|
||||||
icon: iphonePng,
|
icon: iphonePng,
|
||||||
vertical: "iphone-v",
|
vertical: "iphone-v",
|
||||||
horizental: "iphone-h",
|
horizental: "iphone-h",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Android Phone",
|
name: "Android Phone",
|
||||||
icon: androidPng,
|
icon: androidPng,
|
||||||
vertical: "android-v",
|
vertical: "android-v",
|
||||||
horizental: "android-h",
|
horizental: "android-h",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "iPad",
|
name: "iPad",
|
||||||
icon: ipadPng,
|
icon: ipadPng,
|
||||||
vertical: "ipad-v",
|
vertical: "ipad-v",
|
||||||
horizental: "ipad-h",
|
horizental: "ipad-h",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function Pane(props) {
|
function Pane(props) {
|
||||||
var [mode, setMode] = useState(props.mode);
|
var [mode, setMode] = useState(props.mode);
|
||||||
var [device, setDevice] = useState(props.device);
|
var [device, setDevice] = useState(props.device);
|
||||||
var [project, setProject] = useState(props.project);
|
var [project, setProject] = useState(props.project);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
var modeChange = (e) => {
|
var modeChange = (e) => {
|
||||||
var _mode = e.target.value;
|
var _mode = e.target.value;
|
||||||
setMode(_mode);
|
setMode(_mode);
|
||||||
props.onModeChange(e.target.value);
|
props.onModeChange(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
var deviceChange = (_device) => {
|
var deviceChange = (_device) => {
|
||||||
setDevice(_device);
|
setDevice(_device);
|
||||||
props.onDeviceChange(_device);
|
props.onDeviceChange(_device);
|
||||||
};
|
};
|
||||||
|
|
||||||
var projectSelect = (e) => {
|
var projectSelect = (e) => {
|
||||||
var projectName = e.target.value;
|
var projectName = e.target.value;
|
||||||
setProject(projectName);
|
setProject(projectName);
|
||||||
props.onProjectSelect(projectName);
|
props.onProjectSelect(projectName);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
props.projects.length && !project && setProject(props.projects[0]);
|
props.projects.length && !project && setProject(props.projects[0]);
|
||||||
}, [props.projects]);
|
}, [props.projects]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Pane">
|
<div className="Pane">
|
||||||
<Select
|
<Select
|
||||||
id="mode-select"
|
id="mode-select"
|
||||||
value={mode}
|
value={mode}
|
||||||
onChange={(e) => modeChange(e)}
|
onChange={(e) => modeChange(e)}
|
||||||
startAdornment={
|
startAdornment={<img src={modeSelectPng} height={"30px"} alt="selected" />}
|
||||||
<img src={modeSelectPng} height={"30px"} alt="selected" />
|
sx={{
|
||||||
}
|
width: "100%",
|
||||||
sx={{
|
border: "none",
|
||||||
width: "100%",
|
background: "rgb(69, 115, 191)",
|
||||||
border: "none",
|
color: "white",
|
||||||
background: "rgb(69, 115, 191)",
|
fontWeight: "bold",
|
||||||
color: "white",
|
}}
|
||||||
fontWeight: "bold",
|
MenuProps={{
|
||||||
}}
|
classes: {
|
||||||
MenuProps={{
|
paper: "selectPager",
|
||||||
classes: {
|
},
|
||||||
paper: "selectPager",
|
}}>
|
||||||
},
|
<MenuItem value={"normal"}>Normal Preview</MenuItem>
|
||||||
}}
|
<MenuItem value={"dynamic"}>Dynamic Preview</MenuItem>
|
||||||
>
|
</Select>
|
||||||
<MenuItem value={"normal"}>Normal Preview</MenuItem>
|
<List>
|
||||||
<MenuItem value={"dynamic"}>Dynamic Preview</MenuItem>
|
{deviceConfigs.map((_device) => (
|
||||||
</Select>
|
<ListItem
|
||||||
<List>
|
key={_device.name}
|
||||||
{deviceConfigs.map((_device) => (
|
sx={{
|
||||||
<ListItem
|
display: "flex",
|
||||||
key={_device.name}
|
textAlign: "center",
|
||||||
sx={{
|
}}>
|
||||||
display: "flex",
|
<div style={{ width: "120px", alignItems: "center" }}>
|
||||||
textAlign: "center",
|
<img className="deviceIcon" src={_device.icon} alt={_device.name} />
|
||||||
}}
|
</div>
|
||||||
>
|
<div className="deviceContent">
|
||||||
<div style={{ width: "120px", alignItems: "center" }}>
|
<p style={{ margin: "14px 0" }}>{_device.name}</p>
|
||||||
<img
|
<div className="deviceButtons">
|
||||||
className="deviceIcon"
|
<button className={`pane-btn ${device === _device.horizental ? "checked" : ""}`} onClick={() => deviceChange(_device.horizental)}>
|
||||||
src={_device.icon}
|
{t("horizontal")}
|
||||||
alt={_device.name}
|
</button>
|
||||||
/>
|
<button className={`pane-btn ${device === _device.vertical ? "checked" : ""}`} onClick={() => deviceChange(_device.vertical)}>
|
||||||
</div>
|
{t("vertical")}
|
||||||
<div className="deviceContent">
|
</button>
|
||||||
<p style={{ margin: "14px 0" }}>{_device.name}</p>
|
{/* <img src={device === _device.horizental ? horizentalChecked : horizentalButton} alt="horizental" onClick={() => deviceChange(_device.horizental)} />
|
||||||
<div className="deviceButtons">
|
<img src={device === _device.vertical ? verticalChecked : verticalButton} alt="vertical" onClick={() => deviceChange(_device.vertical)} /> */}
|
||||||
<img
|
</div>
|
||||||
src={
|
</div>
|
||||||
device === _device.horizental
|
</ListItem>
|
||||||
? horizentalChecked
|
))}
|
||||||
: horizentalButton
|
</List>
|
||||||
}
|
<div
|
||||||
alt="horizental"
|
style={{
|
||||||
onClick={() => deviceChange(_device.horizental)}
|
marginTop: "50px",
|
||||||
/>
|
color: "white",
|
||||||
<img
|
}}>
|
||||||
src={
|
{props.loading ? (
|
||||||
device === _device.vertical
|
<CircularProgress color="inherit" />
|
||||||
? verticalChecked
|
) : (
|
||||||
: verticalButton
|
project && (
|
||||||
}
|
<Select
|
||||||
alt="vertical"
|
id="project-select"
|
||||||
onClick={() => deviceChange(_device.vertical)}
|
value={project}
|
||||||
/>
|
onChange={(e) => projectSelect(e)}
|
||||||
</div>
|
placeholder="选择项目"
|
||||||
</div>
|
sx={{
|
||||||
</ListItem>
|
background: "rgb(115, 158, 211)",
|
||||||
))}
|
width: "80%",
|
||||||
</List>
|
color: "white",
|
||||||
<div
|
}}>
|
||||||
style={{
|
{props.projects.map((pName, i) => (
|
||||||
marginTop: "50px",
|
<MenuItem key={i} value={pName}>
|
||||||
color: "white",
|
{pName}
|
||||||
}}
|
</MenuItem>
|
||||||
>
|
))}
|
||||||
{props.loading ? (
|
</Select>
|
||||||
<CircularProgress color="inherit" />
|
)
|
||||||
) : (
|
)}
|
||||||
project && (
|
</div>
|
||||||
<Select
|
{!props.hideLogo && <img src={logoPanePng} alt="logo" width={"100%"} className="bottomLogo" />}
|
||||||
id="project-select"
|
</div>
|
||||||
value={project}
|
);
|
||||||
onChange={(e) => projectSelect(e)}
|
|
||||||
placeholder="选择项目"
|
|
||||||
sx={{
|
|
||||||
background: "rgb(115, 158, 211)",
|
|
||||||
width: "80%",
|
|
||||||
color: "white",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.projects.map((pName, i) => (
|
|
||||||
<MenuItem key={i} value={pName}>
|
|
||||||
{pName}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{!props.hideLogo && (
|
|
||||||
<img
|
|
||||||
src={logoPanePng}
|
|
||||||
alt="logo"
|
|
||||||
width={"100%"}
|
|
||||||
className="bottomLogo"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Pane;
|
export default Pane;
|
||||||
|
|
|
@ -1,96 +1,103 @@
|
||||||
import { Alert, Grid, List, ListItem, Snackbar } from '@mui/material';
|
import { Alert, Grid, List, ListItem, Snackbar } from "@mui/material";
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from "react";
|
||||||
import './index.css'
|
import "./index.css";
|
||||||
import checkPng from '../../images/check.png';
|
import checkPng from "../../images/check.png";
|
||||||
import generateButtonPng from '../../images/generate-button.png';
|
import generateButtonPng from "../../images/generate-button.png";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
var rows = ['TopText', 'CentText', 'MiddText']
|
var rows = ["TopText", "CentText", "MiddText"];
|
||||||
var rowTitles = ['开头', '中间', '结尾']
|
var rowTitles = ["start", "middle", "end"];
|
||||||
function SettingFrame(props) {
|
function SettingFrame(props) {
|
||||||
var [settingArr, setSettingArr] = useState([1, 2, 3])
|
var [settingArr, setSettingArr] = useState([1, 2, 3]);
|
||||||
var [openPopup, setOpenPopup] = useState(false);
|
var [openPopup, setOpenPopup] = useState(false);
|
||||||
console.log(props.settingValue)
|
const { t } = useTranslation();
|
||||||
useEffect(() => {
|
|
||||||
setSettingArr(props.settingValue)
|
|
||||||
}, [props.settingValue])
|
|
||||||
|
|
||||||
return (
|
useEffect(() => {
|
||||||
<div style={{
|
setSettingArr(props.settingValue);
|
||||||
flex: 1
|
}, [props.settingValue]);
|
||||||
}}>
|
|
||||||
<Snackbar open={openPopup} onClose={() => setOpenPopup(false)} autoHideDuration={3000} anchorOrigin={{
|
|
||||||
vertical: 'top',
|
|
||||||
horizontal: 'right'
|
|
||||||
}}>
|
|
||||||
<Alert severity="success" sx={{ width: '100%' }}>
|
|
||||||
保存成功
|
|
||||||
</Alert>
|
|
||||||
</Snackbar>
|
|
||||||
<List>
|
|
||||||
{
|
|
||||||
rows.map((rowKey, rowIndex) => (
|
|
||||||
<ListItem key={rowIndex}>
|
|
||||||
<span>{rowTitles[rowIndex]}</span>
|
|
||||||
<Grid container spacing={{ xs: 2, md: 3 }} columns={{ xs: 4, sm: 8, md: 12 }}>
|
|
||||||
{(props.setting && props.setting[rowKey]
|
|
||||||
? Array.from(props.setting[rowKey].split('|'))
|
|
||||||
: ['无', '无', '无'])
|
|
||||||
.map((text, index) => (
|
|
||||||
<Grid item xs={2} sm={4} md={4} key={index}>
|
|
||||||
<div className='setting-card' style={{
|
|
||||||
position: 'relative',
|
|
||||||
height: '120px',
|
|
||||||
textAlign: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
cursor: 'pointer'
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
var newSetting = settingArr.slice()
|
|
||||||
newSetting[rowIndex] = index + 1;
|
|
||||||
setSettingArr(newSetting);
|
|
||||||
}}>
|
|
||||||
{text}
|
|
||||||
<img src={checkPng} alt='check' style={{
|
|
||||||
position: 'absolute',
|
|
||||||
right: '10px',
|
|
||||||
top: '10px',
|
|
||||||
display: (index + 1) === settingArr[rowIndex] ? 'block' : 'none'
|
|
||||||
}}/>
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</ListItem>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</List>
|
|
||||||
<div style={{
|
|
||||||
alignItems: 'center',
|
|
||||||
cursor: 'pointer',
|
|
||||||
marginTop: '30px'
|
|
||||||
}}>
|
|
||||||
{
|
|
||||||
props.setting && <img
|
|
||||||
src={generateButtonPng}
|
|
||||||
alt='generate'
|
|
||||||
style={{
|
|
||||||
cursor: 'pointer'
|
|
||||||
}}
|
|
||||||
onClick={async () => {
|
|
||||||
await props.generate({
|
|
||||||
topType: settingArr[0]+'',
|
|
||||||
centreType: settingArr[1]+'',
|
|
||||||
middleType: settingArr[2]+''
|
|
||||||
})
|
|
||||||
|
|
||||||
setOpenPopup(true);
|
return (
|
||||||
}}/>
|
<div
|
||||||
}
|
style={{
|
||||||
</div>
|
flex: 1,
|
||||||
</div>
|
}}>
|
||||||
)
|
<Snackbar
|
||||||
|
open={openPopup}
|
||||||
|
onClose={() => setOpenPopup(false)}
|
||||||
|
autoHideDuration={3000}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: "top",
|
||||||
|
horizontal: "right",
|
||||||
|
}}>
|
||||||
|
<Alert severity="success" sx={{ width: "100%" }}>
|
||||||
|
{t("saveSuccess")}
|
||||||
|
</Alert>
|
||||||
|
</Snackbar>
|
||||||
|
<List>
|
||||||
|
{rows.map((rowKey, rowIndex) => (
|
||||||
|
<ListItem key={rowIndex}>
|
||||||
|
<span>{t(rowTitles[rowIndex])}</span>
|
||||||
|
<Grid container spacing={{ xs: 2, md: 3 }} columns={{ xs: 4, sm: 8, md: 12 }}>
|
||||||
|
{(props.setting && props.setting[rowKey] ? Array.from(t(props.setting[rowKey]).split("|")) : [t("none"), t("none"), t("none")]).map((text, index) => (
|
||||||
|
<Grid item xs={2} sm={4} md={4} key={index}>
|
||||||
|
<div
|
||||||
|
className="setting-card"
|
||||||
|
style={{
|
||||||
|
position: "relative",
|
||||||
|
height: "120px",
|
||||||
|
textAlign: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
var newSetting = settingArr.slice();
|
||||||
|
newSetting[rowIndex] = index + 1;
|
||||||
|
setSettingArr(newSetting);
|
||||||
|
}}>
|
||||||
|
{text}
|
||||||
|
<img
|
||||||
|
src={checkPng}
|
||||||
|
alt="check"
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
right: "10px",
|
||||||
|
top: "10px",
|
||||||
|
display: index + 1 === settingArr[rowIndex] ? "block" : "none",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
alignItems: "center",
|
||||||
|
cursor: "pointer",
|
||||||
|
marginTop: "30px",
|
||||||
|
}}>
|
||||||
|
{props.setting && (
|
||||||
|
<button
|
||||||
|
className="generate-btn"
|
||||||
|
onClick={async () => {
|
||||||
|
await props.generate({
|
||||||
|
topType: settingArr[0] + "",
|
||||||
|
centreType: settingArr[1] + "",
|
||||||
|
middleType: settingArr[2] + "",
|
||||||
|
});
|
||||||
|
|
||||||
|
setOpenPopup(true);
|
||||||
|
}}>
|
||||||
|
{t("generate")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SettingFrame;
|
export default SettingFrame;
|
|
@ -1,23 +1,21 @@
|
||||||
var BaseUrl = "http://api.soyootech.com/";
|
var BaseUrl = "/api/";
|
||||||
export async function UserLogin(loginForm) {
|
export async function UserLogin(loginForm) {
|
||||||
try {
|
try {
|
||||||
var response = await fetch(BaseUrl + "SoyooUser/previewlogin", {
|
var response = await fetch(BaseUrl + "SoyooUser/previewlogin", {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
account: loginForm.account,
|
account: loginForm.account,
|
||||||
password: loginForm.password,
|
password: loginForm.password,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
});
|
});
|
||||||
var result = await response.json();
|
var result = await response.json();
|
||||||
result.permissionPages = result.permissionPages.map((permission) =>
|
result.permissionPages = result.permissionPages.map((permission) => permission.toLowerCase());
|
||||||
permission.toLowerCase()
|
return result;
|
||||||
);
|
} catch (error) {
|
||||||
return result;
|
console.log(error);
|
||||||
} catch (error) {
|
return null;
|
||||||
console.log(error);
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import i18n from "i18next";
|
||||||
|
import { initReactI18next } from "react-i18next";
|
||||||
|
|
||||||
|
import LanguageDetector from "i18next-browser-languagedetector";
|
||||||
|
|
||||||
|
import en from "./locales/en.json";
|
||||||
|
import zh from "./locales/zh.json";
|
||||||
|
|
||||||
|
const resources = {
|
||||||
|
en: {
|
||||||
|
translation: en,
|
||||||
|
},
|
||||||
|
zh: {
|
||||||
|
translation: zh,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const lang = localStorage.getItem("lang") ?? "zh";
|
||||||
|
|
||||||
|
i18n
|
||||||
|
.use(LanguageDetector)
|
||||||
|
.use(initReactI18next)
|
||||||
|
.init({
|
||||||
|
fallbackLng: lang,
|
||||||
|
lng: lang,
|
||||||
|
debug: true,
|
||||||
|
resources: resources,
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false, // not needed for react as it escapes by default
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default i18n;
|
23
src/index.js
23
src/index.js
|
@ -1,14 +1,19 @@
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from "react-dom";
|
||||||
import './index.css';
|
import "./index.css";
|
||||||
import App from './App';
|
import App from "./App";
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from "./reportWebVitals";
|
||||||
|
import "./i18n";
|
||||||
|
import { I18nextProvider } from "react-i18next";
|
||||||
|
import i18n from "./i18n";
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<I18nextProvider i18n={i18n}>
|
||||||
</React.StrictMode>,
|
<App />
|
||||||
document.getElementById('root')
|
</I18nextProvider>
|
||||||
|
</React.StrictMode>,
|
||||||
|
document.getElementById("root")
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
// If you want to start measuring performance in your app, pass a function
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"login": "Login",
|
||||||
|
"account": "Account",
|
||||||
|
"password": "Password",
|
||||||
|
"keepLoginStatus": "Keep the login status for 7 days",
|
||||||
|
"submit": "Submit",
|
||||||
|
"noAuth": "No permission",
|
||||||
|
"loginError": "Account or password is incorrect",
|
||||||
|
"horizontal": "Horizontal",
|
||||||
|
"vertical": "Vertical",
|
||||||
|
"scan": "Mobile preview",
|
||||||
|
"none": "None",
|
||||||
|
"start": "Start",
|
||||||
|
"middle": "Mid",
|
||||||
|
"end": "End",
|
||||||
|
"generate": "Generate",
|
||||||
|
"copySuccess": "link copy success",
|
||||||
|
"saveSuccess": "save success",
|
||||||
|
"language": "language"
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"login": "登录",
|
||||||
|
"account": "账号",
|
||||||
|
"password": "密码",
|
||||||
|
"keepLoginStatus": "保持登录状态7天",
|
||||||
|
"submit": "提交",
|
||||||
|
"loginError": "账号或密码错误",
|
||||||
|
"noAuth": "无权限访问,请切换账号",
|
||||||
|
"horizontal": "横屏",
|
||||||
|
"vertical": "竖屏",
|
||||||
|
"scan": "扫一扫,手机预览",
|
||||||
|
"none": "无",
|
||||||
|
"start": "开头",
|
||||||
|
"middle": "中间",
|
||||||
|
"end": "结尾",
|
||||||
|
"generate": "一键生成",
|
||||||
|
"copySuccess": "链接复制成功",
|
||||||
|
"saveSuccess": "保存成功",
|
||||||
|
"language": "语言"
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
const { createProxyMiddleware } = require("http-proxy-middleware");
|
||||||
|
|
||||||
|
module.exports = function (app) {
|
||||||
|
app.use(
|
||||||
|
"/api", // 这是路径模式
|
||||||
|
createProxyMiddleware({
|
||||||
|
target: "https://api.soyootech.com/", // 目标服务器地址
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: { "^/api": "" },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue