From 19c5d158432693f4c452bf52b00601badb1ac740 Mon Sep 17 00:00:00 2001 From: guofei Date: Mon, 3 Jun 2024 15:11:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.css | 129 +++--- src/App.js | 538 ++++++++++++++------------ src/Components/settingsFrame/index.js | 191 ++++----- src/images/language.png | Bin 0 -> 6376 bytes 4 files changed, 468 insertions(+), 390 deletions(-) create mode 100644 src/images/language.png diff --git a/src/App.css b/src/App.css index c424f10..ab91dee 100644 --- a/src/App.css +++ b/src/App.css @@ -1,100 +1,117 @@ .App { - text-align: center; - display: flex; - align-items: stretch; + text-align: center; + display: flex; + align-items: stretch; } .App-logo { - height: 40vmin; - pointer-events: none; + height: 40vmin; + pointer-events: none; } @media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } + .App-logo { + animation: App-logo-spin infinite 20s linear; + } } .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; } .App-link { - color: #61dafb; + color: #61dafb; } @keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } .MuiFormControlLabel-label { - font-size: 13px !important; + font-size: 13px !important; } .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; + border-radius: 4px; + border: 0; + display: inline-block; + height: 30px; + line-height: 30px; + width: 150px; + cursor: pointer; + outline: none; + font-weight: bold; } .pane-btn.checked { - background-color: #02b564; - color: white; + background-color: #02b564; + color: white; } .pane-btn + .pane-btn { - margin-left: 10px; + 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; + 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; + 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; + margin-left: 10px; + width: 135px; + height: 35px; + background-color: #eef1f6; + color: #333333; + font-size: 14px; + display: flex; + align-items: center; +} + +.language-select-warpper { + position: relative; +} + +.language-select-warpper .language-icon { + position: absolute; + left: 18px; + top: 8px; + z-index: 2000; } .language-select-container .language-select fieldset { - display: none; + display: none; } diff --git a/src/App.js b/src/App.js index a4e0050..abce3ce 100644 --- a/src/App.js +++ b/src/App.js @@ -8,7 +8,12 @@ import waterMarkPng from "./images/water-mark.png"; import React from "react"; import SettingFrame from "./Components/settingsFrame"; import QrCode from "qrcode"; -import { getLoginInfo, getProjectSettingValue, setLoginInfo, setProjectSetting } from "./storage"; +import { + getLoginInfo, + getProjectSettingValue, + setLoginInfo, + setProjectSetting, +} from "./storage"; import Select from "@mui/material/Select"; import MenuItem from "@mui/material/MenuItem"; import Button from "@mui/material/Button"; @@ -22,270 +27,311 @@ import FormControlLabel from "@mui/material/FormControlLabel"; import queryString from "query-string"; import { withTranslation } from "react-i18next"; import i18n from "i18next"; +import languageImg from "./images/language.png"; class App extends React.Component { - constructor(props) { - super(); - this.state = { - mode: "normal", - projects: [], - selectedProject: {}, - selectedProjectName: "", - device: "android-h", - htmlUrl: "", - dataUrl: "", - loading: false, - loginOpen: false, - loginErrorMessage: "", - hideLogo: false, - loginForm: { - account: "", - password: "", - keepLogin: false, - }, - language: localStorage.getItem("lang") ?? "zh", - }; - this.t = props.t; - } - componentDidMount() { - const loginInfo = getLoginInfo(); - var tenant = utils.getTenant(); - const hideLogo = queryString.parseUrl(window.location.href)?.query?.hideLogo; - this.setState({ hideLogo: !!hideLogo }); - if (loginInfo && loginInfo.permissionPages.includes(tenant)) { - this.fetchData(); - this.refreshQrCode(); - } else { - this.setState({ loginOpen: true }); - loginInfo && this.setState({ loginErrorMessage: "noAuth" }); - } - } + constructor(props) { + super(); + this.state = { + mode: "normal", + projects: [], + selectedProject: {}, + selectedProjectName: "", + device: "android-h", + htmlUrl: "", + dataUrl: "", + loading: false, + loginOpen: false, + loginErrorMessage: "", + hideLogo: false, + loginForm: { + account: "", + password: "", + keepLogin: false, + }, + language: localStorage.getItem("lang") ?? "zh", + }; + this.t = props.t; + } + componentDidMount() { + const loginInfo = getLoginInfo(); + var tenant = utils.getTenant(); + const hideLogo = queryString.parseUrl(window.location.href)?.query + ?.hideLogo; + this.setState({ hideLogo: !!hideLogo }); + if (loginInfo && loginInfo.permissionPages.includes(tenant)) { + this.fetchData(); + this.refreshQrCode(); + } else { + this.setState({ loginOpen: true }); + loginInfo && this.setState({ loginErrorMessage: "noAuth" }); + } + } - login = async () => { - var { account, password, keepLogin } = this.state.loginForm; - var user = await LoginApi.UserLogin({ account, password }); - var tenant = utils.getTenant(); + login = async () => { + var { account, password, keepLogin } = this.state.loginForm; + var user = await LoginApi.UserLogin({ account, password }); + var tenant = utils.getTenant(); - if (user && user.permissionPages.includes(tenant)) { - this.setState({ - loginOpen: false, - }); - if (keepLogin) { - setLoginInfo(user); - } - this.fetchData(); - this.refreshQrCode(); - } else { - this.setState({ - loginErrorMessage: user ? "noAuth" : "loginError", - }); - } - }; + if (user && user.permissionPages.includes(tenant)) { + this.setState({ + loginOpen: false, + }); + if (keepLogin) { + setLoginInfo(user); + } + this.fetchData(); + this.refreshQrCode(); + } else { + this.setState({ + loginErrorMessage: user ? "noAuth" : "loginError", + }); + } + }; - refreshQrCode() { - var { selectedProject } = this.state; - selectedProject.HtmlUrl && - QrCode.toDataURL([{ data: this.selectedProjectUrl, mode: "byte" }], { - width: 120, - }).then((dataUrl) => { - this.setState({ - dataUrl: dataUrl, - }); - }); - } + refreshQrCode() { + var { selectedProject } = this.state; + selectedProject.HtmlUrl && + QrCode.toDataURL([{ data: this.selectedProjectUrl, mode: "byte" }], { + width: 120, + }).then((dataUrl) => { + this.setState({ + dataUrl: dataUrl, + }); + }); + } - get selectedProjectUrl() { - var { selectedProject } = this.state; - var settingValue = getProjectSettingValue(selectedProject?.Name) || [1, 1, 1]; - var rawUrl = selectedProject?.HtmlUrl ? encodeURI(selectedProject?.HtmlUrl) : ""; - rawUrl = rawUrl.replace("http:", () => "https:") - if (rawUrl) { - rawUrl += `?datanumber=${settingValue[0]}&datanumber1=${settingValue[1]}&datanumber2=${settingValue[2]}&lunaOrHtml=false`; - } + get selectedProjectUrl() { + var { selectedProject } = this.state; + var settingValue = getProjectSettingValue(selectedProject?.Name) || [ + 1, 1, 1, + ]; + var rawUrl = selectedProject?.HtmlUrl + ? encodeURI(selectedProject?.HtmlUrl) + : ""; + rawUrl = rawUrl.replace("http:", () => "https:"); + if (rawUrl) { + rawUrl += `?datanumber=${settingValue[0]}&datanumber1=${settingValue[1]}&datanumber2=${settingValue[2]}&lunaOrHtml=false`; + } - return rawUrl; - } + return rawUrl; + } - async setSelectedProject(selectedProjectName) { - this.setState({ - selectedProjectName: selectedProjectName, - }); - console.log("selected:", selectedProjectName); - await this.updateSelectedProject(selectedProjectName); - } + async setSelectedProject(selectedProjectName) { + this.setState({ + selectedProjectName: selectedProjectName, + }); + console.log("selected:", selectedProjectName); + await this.updateSelectedProject(selectedProjectName); + } - async updateSelectedProject(projectName) { - var projectSetting = await ProjectApi.getProjectSetting(projectName); - if (projectSetting.TextObjStr) { - 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, - }); - } + async updateSelectedProject(projectName) { + var projectSetting = await ProjectApi.getProjectSetting(projectName); + if (projectSetting.TextObjStr) { + 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) { - this.setState({ - device: selected, - }); - } + setDevice(selected) { + this.setState({ + device: selected, + }); + } - setMode(mode) { - this.setState({ - mode: mode, - }); - } + setMode(mode) { + this.setState({ + mode: mode, + }); + } - setLoginForm(form) { - this.setState({ - loginForm: { - ...this.state.loginForm, - ...form, - }, - }); - } + setLoginForm(form) { + this.setState({ + loginForm: { + ...this.state.loginForm, + ...form, + }, + }); + } - async fetchData() { - this.setState({ - loading: true, - }); + async fetchData() { + this.setState({ + loading: true, + }); - var projectNames = (await this.fetchProjects()) || ["无项目"]; - this.setState({ - projects: projectNames, - selectedProjectName: projectNames[0], - loading: false, - }); - await this.updateSelectedProject(projectNames[0]); - this.refreshQrCode(); - } + var projectNames = (await this.fetchProjects()) || ["无项目"]; + this.setState({ + projects: projectNames, + selectedProjectName: projectNames[0], + loading: false, + }); + await this.updateSelectedProject(projectNames[0]); + this.refreshQrCode(); + } - async fetchProjects() { - return await ProjectApi.getProjects(); - } + async fetchProjects() { + return await ProjectApi.getProjects(); + } - get projectSettingValue() { - return getProjectSettingValue(this.state.selectedProjectName); - } + get projectSettingValue() { + return getProjectSettingValue(this.state.selectedProjectName); + } - UpdateSetting(obj) { - setProjectSetting(this.state.selectedProject.Name, [+obj.topType, +obj.centreType, +obj.middleType]); - } + UpdateSetting(obj) { + setProjectSetting(this.state.selectedProject.Name, [ + +obj.topType, + +obj.centreType, + +obj.middleType, + ]); + } - render() { - var { mode, device, projects, selectedProject, dataUrl, loading, loginOpen, loginForm, hideLogo, language } = this.state; - const { t } = this.props; + render() { + var { + mode, + device, + projects, + selectedProject, + dataUrl, + loading, + loginOpen, + loginForm, + hideLogo, + language, + } = this.state; + const { t } = this.props; - return ( -
- - {t("login")} - - this.setLoginForm({ account: e.target.value })} - onKeyDown={(e) => e.keyCode === 13 && this.login()} - /> - this.setLoginForm({ password: e.target.value })} - onKeyDown={(e) => e.keyCode === 13 && this.login()} - /> - - - {this.state.loginErrorMessage && ( - - {t(this.state.loginErrorMessage)} - - )} - this.setLoginForm({ keepLogin: checked })} />} - label={t("keepLoginStatus")} - /> - - - - this.setMode(_mode)} - projects={projects} - device={device} - loading={loading} - hideLogo={hideLogo} - onProjectSelect={(project) => { - this.setSelectedProject(project); - }} - onDeviceChange={(_device) => this.setDevice(_device)} - /> -
-
{t("language")}:
- -
-
- {mode === "normal" ? ( - this.refreshQrCode()} /> - ) : ( - this.UpdateSetting(value)} /> - )} -
-
- ); - } + return ( +
+ + {t("login")} + + this.setLoginForm({ account: e.target.value })} + onKeyDown={(e) => e.keyCode === 13 && this.login()} + /> + this.setLoginForm({ password: e.target.value })} + onKeyDown={(e) => e.keyCode === 13 && this.login()} + /> + + + {this.state.loginErrorMessage && ( + + {t(this.state.loginErrorMessage)} + + )} + + this.setLoginForm({ keepLogin: checked }) + } + /> + } + label={t("keepLoginStatus")} + /> + + + + this.setMode(_mode)} + projects={projects} + device={device} + loading={loading} + hideLogo={hideLogo} + onProjectSelect={(project) => { + this.setSelectedProject(project); + }} + onDeviceChange={(_device) => this.setDevice(_device)} + /> +
+
+ + +
+
+
+ {mode === "normal" ? ( + this.refreshQrCode()} + /> + ) : ( + this.UpdateSetting(value)} + /> + )} +
+
+ ); + } } export default withTranslation()(App); diff --git a/src/Components/settingsFrame/index.js b/src/Components/settingsFrame/index.js index e298d1c..3614509 100644 --- a/src/Components/settingsFrame/index.js +++ b/src/Components/settingsFrame/index.js @@ -2,102 +2,117 @@ import { Alert, Grid, List, ListItem, Snackbar } from "@mui/material"; import { useEffect, useState } from "react"; import "./index.css"; import checkPng from "../../images/check.png"; -import generateButtonPng from "../../images/generate-button.png"; import { useTranslation } from "react-i18next"; var rows = ["TopText", "CentText", "MiddText"]; var rowTitles = ["start", "middle", "end"]; function SettingFrame(props) { - var [settingArr, setSettingArr] = useState([1, 2, 3]); - var [openPopup, setOpenPopup] = useState(false); - const { t } = useTranslation(); + var [settingArr, setSettingArr] = useState([1, 2, 3]); + var [openPopup, setOpenPopup] = useState(false); + const { t } = useTranslation(); - useEffect(() => { - setSettingArr(props.settingValue); - }, [props.settingValue]); + useEffect(() => { + setSettingArr(props.settingValue); + }, [props.settingValue]); - return ( -
- setOpenPopup(false)} - autoHideDuration={3000} - anchorOrigin={{ - vertical: "top", - horizontal: "right", - }}> - - {t("saveSuccess")} - - - - {rows.map((rowKey, rowIndex) => ( - - {t(rowTitles[rowIndex])} - - {(props.setting && props.setting[rowKey] ? Array.from(t(props.setting[rowKey]).split("|")) : [t("none"), t("none"), t("none")]).map((text, index) => ( - -
{ - var newSetting = settingArr.slice(); - newSetting[rowIndex] = index + 1; - setSettingArr(newSetting); - }}> - {text} - check -
-
- ))} -
-
- ))} -
-
- {props.setting && ( - - )} -
-
- ); + setOpenPopup(true); + }} + > + {t("generate")} + + )} + + + ); } export default SettingFrame; diff --git a/src/images/language.png b/src/images/language.png new file mode 100644 index 0000000000000000000000000000000000000000..3a4945653c8b9fce6f60fef711fa366a40b4b0da GIT binary patch literal 6376 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