提交 9b48aae7 编写于 作者: nengyuangzhang's avatar nengyuangzhang

Merge branch 'PR' into develop

......@@ -20,7 +20,18 @@ app.controller('LoginController', function (
$scope.fullScreenTitle = "FULLSCREEN";
$scope.cur_user = JSON.parse($window.localStorage.getItem("myems_admin_ui_current_user"));
// login section start
$scope.login = function (user) {
$scope.login = function (user, captcha, captchaText, refreshCaptcha) {
if(captcha.toLowerCase() !== captchaText.toLowerCase()){
$scope.captcha = '';
refreshCaptcha();
toaster.pop({
type: "error",
title: $translate.instant('TOASTER.CAPTCHA_ERROR'),
body: '',
showCloseButton: true,
});
return false;
}
$scope.dataLoading = true;
LoginService.login(user, function (response) {
if (angular.isDefined(response.status) && response.status === 200) {
......@@ -44,6 +55,7 @@ app.controller('LoginController', function (
showCloseButton: true,
});
}
refreshCaptcha();
$scope.dataLoading = false;
});
};
......
......@@ -563,6 +563,56 @@ function markdownEditor() {
}
};
// 创建一个名为 captcha 的指令
function captcha() {
return {
restrict: 'AE',
replace: true,
name: 'captcha',
scope: {
captchaText: '=captchaText',
refreshCaptcha: '=refresh'
},
template: '<canvas height="34" ng-click="refreshCaptcha()" width="86" class="cell-captcha-canvas" ng-model="text"></canvas>',
link: function(scope, elem, attrs) {
// 生成随机字符串作为验证码
function generateCode() {
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
var codeLength = 5;
var code = '';
for (var i = 0; i < codeLength; i++) {
var randomIndex = Math.floor(Math.random() * chars.length);
code += chars.substring(randomIndex, randomIndex + 1);
scope.captchaText = code;
}
return code;
}
// 绘制验证码
function draw(canvas, code) {
var context = canvas.getContext('2d');
context.fillStyle = '#EEE';
context.fillRect(0, 0, canvas.width, canvas.height);
context.font = '24px Arial';
context.fillStyle = 'black';
context.textAlign = 'center';
context.fillText(code, canvas.width / 2, canvas.height / 2 + 10);
}
// 初始化生成验证码
var canvas = elem[0];
var code = generateCode();
draw(canvas, code);
// 刷新验证码
scope.refreshCaptcha = function() {
code = generateCode();
draw(canvas, code);
};
}};
};
/**
*
* Pass all functions into module
......@@ -590,3 +640,4 @@ app
.directive('truncate', truncate)
.directive('touchSpin', touchSpin)
.directive('markdownEditor', markdownEditor)
.directive('captcha', captcha)
......@@ -135,6 +135,7 @@ function config($translateProvider) {
PASSWORD: 'Password',
LOGIN: 'Login',
TITLE: 'Energy Management System',
CAPTCHA: 'Captcha',
},
SETTING: {
KNOWLEDGEFILE: 'Knowledge File',
......@@ -645,6 +646,8 @@ function config($translateProvider) {
UNBIND_WORKING_CALENDAR_SUCCESS: 'Unbind Working Calendar Success',
BIND_NON_WORKING_DAY_SUCCESS: 'Bind Non Working Day Success',
UNBIND_NON_WORKING_DAY_SUCCESS: 'Unbind Non Working Day Success',
CAPTCHA_ERROR: 'Captcha Error'
},
SWEET: {
TITLE: 'Please confirm to delete?',
......@@ -1206,6 +1209,7 @@ function config($translateProvider) {
PASSWORD: '密 码',
LOGIN: '登 录',
TITLE: '能 源 管 理 系 统',
CAPTCHA: '验证码',
},
SETTING: {
KNOWLEDGEFILE: '知识文件',
......@@ -1724,6 +1728,8 @@ function config($translateProvider) {
UNBIND_WORKING_CALENDAR_SUCCESS: '解绑工作日历成功',
BIND_NON_WORKING_DAY_SUCCESS: '绑定非工作日成功',
UNBIND_NON_WORKING_DAY_SUCCESS: '解绑非工作日成功',
CAPTCHA_ERROR: '验证码错误',
},
SWEET: {
TITLE: '请确认是否删除?',
......@@ -2285,6 +2291,7 @@ function config($translateProvider) {
PASSWORD: 'Passwort',
LOGIN: 'Einloggen',
TITLE: 'Energiemanagementsystem',
CAPTCHA: 'Captcha',
},
SETTING: {
KNOWLEDGEFILE: 'Wissensdatei',
......@@ -2778,6 +2785,8 @@ function config($translateProvider) {
UNBIND_WORKING_CALENDAR_SUCCESS: 'Unverbindlicher Arbeitstag gelungen',
BIND_NON_WORKING_DAY_SUCCESS: 'Den Erfolg des Arbeitstages binden',
UNBIND_NON_WORKING_DAY_SUCCESS: 'Unverbindlicher Arbeitstag gelungen',
CAPTCHA_ERROR: 'Captcha-Fehler',
},
SWEET: {
TITLE: 'Bitte bestätigen, um zu löschen?',
......
......@@ -710,3 +710,22 @@ li span.divider{
.dashboard .panel-body{
padding: 1px;
}
.table-parent{
width: 100%;
height: 100%;
display: flex;
}
.cell-span{
display: table-cell;
width: 34%;
height: 34px;
text-align: center;
vertical-align: middle;
}
.cell-input{
display: table-cell;
width: 60% !important;
height: 34px !important;
vertical-align: middle;
}
......@@ -16,6 +16,11 @@
<span class="input-group-addon"> {{'LOGIN.PASSWORD' | translate}}</span>
<input ng-keypress="onKeypress($event)" ng-model="user.password" type="password" placeholder="Password" class="form-control" required="">
</div>
<div class="input-group m-b table-parent">
<span class="input-group-addon cell-span"> {{'LOGIN.CAPTCHA' | translate}}</span>
<input ng-keypress="onKeypress($event)" ng-model="captcha" type="text" placeholder="Captcha" class="form-control cell-input" required="">
<captcha refresh="refreshCaptcha" captcha-text="captchaText"></captcha>
</div>
<div class="input-group m-x">
<span class="input-group-addon"> {{'LANGUAGE' | translate}}</span>
<select ng-change="changeLanguage(language)" ng-model="language" class="form-control" >
......@@ -25,7 +30,7 @@
</select>
</div>
<div>
<button ng-click="login(user)" type="submit" class="btn btn-block " >{{'LOGIN' | translate}}</button>
<button ng-click="login(user, captcha, captchaText, refreshCaptcha)" type="submit" class="btn btn-block " >{{'LOGIN' | translate}}</button>
</div>
......
......@@ -55,6 +55,7 @@
"react-beautiful-dnd": "^13.0.0",
"react-bootstrap-table-next": "^4.0.3",
"react-bootstrap-table2-paginator": "^2.1.2",
"react-captcha-code": "^1.0.7",
"react-chartjs-2": "^4.3.1",
"react-countup": "^6.1.0",
"react-datetime": "^2.16.3",
......@@ -64,6 +65,7 @@
"react-flatpickr": "^3.10.6",
"react-hook-form": "^4.10.2",
"react-i18next": "^11.7.0",
"react-icons": "^4.8.0",
"react-image-lightbox": "^5.1.1",
"react-image-video-lightbox": "^3.0.0",
"react-leaflet": "^2.7.0",
......@@ -2444,6 +2446,19 @@
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
},
"node_modules/@emotion/is-prop-valid": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz",
"integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==",
"dependencies": {
"@emotion/memoize": "^0.8.0"
}
},
"node_modules/@emotion/is-prop-valid/node_modules/@emotion/memoize": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz",
"integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA=="
},
"node_modules/@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
......@@ -5992,6 +6007,21 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/babel-plugin-styled-components": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.1.tgz",
"integrity": "sha512-c8lJlszObVQPguHkI+akXv8+Jgb9Ccujx0EetL7oIvwU100LxO6XAGe45qry37wUL40a5U9f23SYrivro2XKhA==",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.16.0",
"@babel/helper-module-imports": "^7.16.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"lodash": "^4.17.21",
"picomatch": "^2.3.0"
},
"peerDependencies": {
"styled-components": ">= 2"
}
},
"node_modules/babel-plugin-syntax-jsx": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
......@@ -6740,6 +6770,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/camelize": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/caniuse-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
......@@ -7588,6 +7626,14 @@
"tiny-invariant": "^1.0.6"
}
},
"node_modules/css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
"integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
"engines": {
"node": ">=4"
}
},
"node_modules/css-declaration-sorter": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz",
......@@ -7780,6 +7826,16 @@
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
},
"node_modules/css-to-react-native": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
"integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
"dependencies": {
"camelize": "^1.0.0",
"css-color-keywords": "^1.0.0",
"postcss-value-parser": "^4.0.2"
}
},
"node_modules/css-tree": {
"version": "1.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
......@@ -19171,6 +19227,20 @@
"react-dom": "^16.3.0"
}
},
"node_modules/react-captcha-code": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/react-captcha-code/-/react-captcha-code-1.0.7.tgz",
"integrity": "sha512-dCjig+V1Fh89uiMNeNeV/Nrc+lIqhMkUguv4OXZquelZ1v9+DDWs+YOWyhTXBbxpi453AO4f3EQoEwUWiciyLw==",
"dependencies": {
"classnames": "^2.2.6",
"lodash": "^4.17.15",
"styled-components": "^5.1.0"
},
"peerDependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
}
},
"node_modules/react-chartjs-2": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.3.1.tgz",
......@@ -19361,6 +19431,14 @@
}
}
},
"node_modules/react-icons": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.8.0.tgz",
"integrity": "sha512-N6+kOLcihDiAnj5Czu637waJqSnwlMNROzVZMhfX68V/9bu9qHaMIJC4UdozWoOk57gahFCNHwVvWzm0MTzRjg==",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-image-lightbox": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/react-image-lightbox/-/react-image-lightbox-5.1.4.tgz",
......@@ -21413,6 +21491,11 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
......@@ -22522,6 +22605,54 @@
"webpack": "^5.0.0"
}
},
"node_modules/styled-components": {
"version": "5.3.10",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.10.tgz",
"integrity": "sha512-3kSzSBN0TiCnGJM04UwO1HklIQQSXW7rCARUk+VyMR7clz8XVlA3jijtf5ypqoDIdNMKx3la4VvaPFR855SFcg==",
"dependencies": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/traverse": "^7.4.5",
"@emotion/is-prop-valid": "^1.1.0",
"@emotion/stylis": "^0.8.4",
"@emotion/unitless": "^0.7.4",
"babel-plugin-styled-components": ">= 1.12.0",
"css-to-react-native": "^3.0.0",
"hoist-non-react-statics": "^3.0.0",
"shallowequal": "^1.1.0",
"supports-color": "^5.5.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/styled-components"
},
"peerDependencies": {
"react": ">= 16.8.0",
"react-dom": ">= 16.8.0",
"react-is": ">= 16.8.0"
}
},
"node_modules/styled-components/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"engines": {
"node": ">=4"
}
},
"node_modules/styled-components/node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/stylehacks": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
......
......@@ -50,6 +50,7 @@
"react-beautiful-dnd": "^13.0.0",
"react-bootstrap-table-next": "^4.0.3",
"react-bootstrap-table2-paginator": "^2.1.2",
"react-captcha-code": "^1.0.7",
"react-chartjs-2": "^4.3.1",
"react-countup": "^6.1.0",
"react-datetime": "^2.16.3",
......@@ -59,6 +60,7 @@
"react-flatpickr": "^3.10.6",
"react-hook-form": "^4.10.2",
"react-i18next": "^11.7.0",
"react-icons": "^4.8.0",
"react-image-lightbox": "^5.1.1",
"react-image-video-lightbox": "^3.0.0",
"react-leaflet": "^2.7.0",
......@@ -82,8 +84,8 @@
"uuid": "^9.0.0"
},
"scripts": {
"start": "react-scripts --openssl-legacy-provider start",
"build": "react-scripts --openssl-legacy-provider build",
"start": "react-scripts start",
"build": "react-scripts build",
"eject": "react-scripts eject",
"scss": "gulp",
"analyze": "npx source-map-explorer 'build/static/js/*.js'"
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -189,4 +189,26 @@
.rs-picker-toggle:focus,
.rs-picker-toggle:hover {border-color: $white !important;}
.password-input {
padding-right: 40px;
}
.password-input + .input-group-append {
position: absolute;
right: 0;
top: 0;
bottom: 0;
z-index: 3;
}
.password-input + .input-group-append .btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
margin-left: -1px;
background: transparent;
border: 0;
}
.password-input + .input-group-append .btn:active {
background: transparent;
}
\ No newline at end of file
import React, { useState, useEffect, useContext } from 'react';
import React, { useState, useEffect, useContext, useRef } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { toast } from 'react-toastify';
import AppContext from '../../../context/Context';
import { Button, Form, Row, Col, FormGroup, Input, CustomInput, Label } from 'reactstrap';
import { createCookie, getItemFromStore, setItemToStore } from '../../../helpers/utils';
import { Button, Form, Row, Col, FormGroup, Input, CustomInput, Label, InputGroup, InputGroupAddon } from 'reactstrap';
import { createCookie, getItemFromStore, setItemToStore, themeColors } from '../../../helpers/utils';
import withRedirect from '../../../hoc/withRedirect';
import { withTranslation } from 'react-i18next';
import { APIBaseURL } from '../../../config';
import {FaEye, FaEyeSlash} from 'react-icons/fa'
import Captcha from 'react-captcha-code';
const LoginForm = ({ setRedirect, hasLabel, layout, t }) => {
// State
const [email, setEmail] = useState(getItemFromStore('email', ''));
const [password, setPassword] = useState('');
const [code, setCode] = useState('');
const [captchaCode, setCaptchaCode] = useState('');
const [remember, setRemember] = useState(true);
const [isDisabled, setIsDisabled] = useState(true);
const [inputType, setInputType] = useState('password');
const captchaRef = useRef(null);
// Context
const { language, setLanguage } = useContext(AppContext);
const { language, setLanguage, isDark } = useContext(AppContext);
// Handler
const handleSubmit = e => {
e.preventDefault();
let isResponseOK = false;
if (captchaCode.toLowerCase() !== code.toLowerCase()) {
toast.error(t('Captcha Error'));
handleRefreshCaptcha();
return false;
}
fetch(APIBaseURL + '/users/login', {
method: 'PUT',
body: JSON.stringify({ "data": { "email": email, "password": password } }),
......@@ -31,6 +42,7 @@ const LoginForm = ({ setRedirect, hasLabel, layout, t }) => {
console.log(response);
if (response.ok) {
isResponseOK = true;
handleRefreshCaptcha();
}
return response.json();
}).then(json => {
......@@ -51,17 +63,34 @@ const LoginForm = ({ setRedirect, hasLabel, layout, t }) => {
}
setRedirect(true);
} else {
handleRefreshCaptcha();
toast.error(t(json.description));
}
}).catch(err => {
console.log(err);
});
};
useEffect(() => {
setIsDisabled(!email || !password || !code);
}, [email, password, code]);
useEffect(() => {
setIsDisabled(!email || !password);
}, [email, password]);
const interval = setInterval(() => {
handleRefreshCaptcha();
}, 1000 * 60);
return () => clearInterval(interval);
}, []);
const toggleVisibility = () => {
setInputType(inputType === 'password' ? 'text' : 'password');
};
const handleRefreshCaptcha = () => {
setCode('');
captchaRef.current.refresh()
};
return (
<Form onSubmit={handleSubmit}>
......@@ -77,12 +106,47 @@ const LoginForm = ({ setRedirect, hasLabel, layout, t }) => {
</FormGroup>
<FormGroup>
{hasLabel && <Label>{t('Password')}</Label>}
<Input
placeholder={!hasLabel ? t('Password') : ''}
value={password}
onChange={({ target }) => setPassword(target.value)}
type="password"
/>
<InputGroup>
<Input
placeholder={!hasLabel ? t('Password') : ''}
value={password}
className="password-input"
onChange={({ target }) => setPassword(target.value)}
type={inputType}
/>
<InputGroupAddon addonType="append">
<Button color="secondary" onClick={toggleVisibility}>
{inputType === 'password' ? <FaEyeSlash /> : <FaEye />}
</Button>
</InputGroupAddon>
</InputGroup>
</FormGroup>
<FormGroup>
<Row className="justify-content-between align-items-center">
<Col xs="6" className='pr-0'>
{hasLabel && <Label>{t('CaptchaCode')}</Label>}
<Input
placeholder={!hasLabel ? t('CaptchaCode') : ''}
value={code}
onChange={({ target }) => setCode(target.value)}
type="text"
/>
</Col>
<Col xs="3" className='d-flex pr-0 pl-0'>
<Captcha
codeType={2}
charNum={5}
width={100}
height={36}
bgColor={!isDark ? themeColors.light : themeColors.dark}
onChange={(value) => setCaptchaCode(value)}
ref={captchaRef}
/>
</Col>
<Col xs="auto" className='d-flex justify-items-right pl-0'>
<Button onClick={handleRefreshCaptcha}>{t('Refresh')}</Button>
</Col>
</Row>
</FormGroup>
<Row className="justify-content-between align-items-center">
<Col xs="auto">
......
......@@ -314,6 +314,8 @@ const resources = {
'Log in': 'Log in',
'Email address': 'Email address',
'Password': 'Password',
'CaptchaCode': 'Captcha',
'Refresh': 'Refresh',
'Remember me': 'Remember me',
'Logged in as ': 'Logged in as ',
'Forget Password?': 'Forget Password?',
......@@ -386,6 +388,7 @@ const resources = {
'Try refreshing the page, or going back and attempting the action again. ':
'Try refreshing the page, or going back and attempting the action again. ',
'If this problem persists,': 'If this problem persists,',
'Captcha Error': 'Captcha Error',
//Tenant Bill
'Lease Contract Number': 'Lease Contract Number',
'Download': 'Download',
......@@ -1161,6 +1164,8 @@ const resources = {
'Log in': 'Anmeldung',
'Email address': 'E-Mail-Addresse',
'Password': 'Passwort',
'CaptchaCode': 'Captcha',
'Refresh': 'Auffrischen',
'Remember me': 'Behalte mich in Erinnerung',
'Logged in as ': 'Angemeldet als ',
'Forget Password?': 'Passwort vergessen?',
......@@ -1238,6 +1243,7 @@ const resources = {
'Try refreshing the page, or going back and attempting the action again. ':
'Versuchen Sie, die Seite zu aktualisieren, oder gehen Sie zurück und versuchen Sie die Aktion erneut. ',
'If this problem persists,': 'Wenn dieses Problem weiterhin besteht,',
'Captcha Error': 'Captcha-Fehler',
//Tenant Bill
'Lease Contract Number': 'Mietvertragsnummer',
'Download': 'Herunterladen',
......@@ -1991,6 +1997,8 @@ const resources = {
'Log in': '登录',
'Email address': '电子邮件地址',
'Password': '密码',
'CaptchaCode': '验证码',
'Refresh': '刷新',
'Remember me': '记住我',
'Logged in as ': '已登录 ',
'Forget Password?': '忘记密码?',
......@@ -2064,6 +2072,7 @@ const resources = {
'Try refreshing the page, or going back and attempting the action again':
'请尝试刷新页面, 或回退并再次尝试执行这个操作',
'If this problem persists,': '如果问题依然存在,',
'Captcha Error': '验证码错误',
//Tenant Bill
'Lease Contract Number': '租赁合同号码',
'Download': '下载',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册