Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Moecube Accounts Web
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Moecube Accounts Web
Commits
4481f62d
Commit
4481f62d
authored
Jul 08, 2024
by
nanahira
Browse files
Options
Browse Files
Download
Plain Diff
add vaptcha
parents
2c3bc432
cd0209ef
Pipeline
#28198
passed with stages
in 1 minute and 54 seconds
Changes
13
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
411 additions
and
188 deletions
+411
-188
i18n.json
i18n.json
+92
-85
public/index.html
public/index.html
+1
-1
src/components/EmailForm.js
src/components/EmailForm.js
+78
-26
src/components/PasswordForm.js
src/components/PasswordForm.js
+88
-30
src/components/UserNameForm.js
src/components/UserNameForm.js
+99
-29
src/components/UserPanel.js
src/components/UserPanel.js
+3
-0
src/models/auth.js
src/models/auth.js
+3
-0
src/models/user.js
src/models/user.js
+3
-0
src/routes/Index.js
src/routes/Index.js
+6
-4
src/routes/Index.less
src/routes/Index.less
+17
-1
src/routes/Logout.js
src/routes/Logout.js
+3
-0
src/routes/Profiles.js
src/routes/Profiles.js
+17
-11
src/routes/Register.js
src/routes/Register.js
+1
-1
No files found.
i18n.json
View file @
4481f62d
This diff is collapsed.
Click to expand it.
public/index.html
View file @
4481f62d
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
<meta
charset=
"UTF-8"
>
<meta
charset=
"UTF-8"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1"
>
<link
rel=
"stylesheet"
href=
"index.css"
/>
<link
rel=
"stylesheet"
href=
"index.css"
/>
<link
rel=
"icon"
href=
"
https://moecube.com
/favicon.ico"
>
<link
rel=
"icon"
href=
"/favicon.ico"
>
<script
src=
"https://v-cn.vaptcha.com/v3.js"
></script>
<script
src=
"https://v-cn.vaptcha.com/v3.js"
></script>
</head>
</head>
<body>
<body>
...
...
src/components/EmailForm.js
View file @
4481f62d
import
{
Form
,
Input
}
from
'
antd
'
;
import
{
Button
,
Form
,
Input
}
from
'
antd
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
connect
}
from
'
react-redux
'
;
import
SubmitButton
from
'
./SubmitButton
'
;
import
SubmitButton
from
'
./SubmitButton
'
;
...
@@ -11,13 +11,15 @@ const formItemLayout = {
...
@@ -11,13 +11,15 @@ const formItemLayout = {
class
EmailForm
extends
React
.
Component
{
class
EmailForm
extends
React
.
Component
{
state
=
{
countdown
:
0
,
inCountdown
:
false
,
// Whether the countdown is active
};
// static contextTypes = {
// static contextTypes = {
// intl: PropTypes.object.isRequired,
// intl: PropTypes.object.isRequired,
// };
// };
onSubmit
=
(
e
)
=>
{
onSubmit
=
(
e
)
=>
{
const
{
form
,
dispatch
,
user
:
{
id
}
}
=
this
.
props
;
const
{
form
,
dispatch
,
user
:
{
id
}
}
=
this
.
props
;
if
(
e
)
{
if
(
e
)
{
e
.
preventDefault
();
e
.
preventDefault
();
}
}
...
@@ -28,17 +30,48 @@ class EmailForm extends React.Component {
...
@@ -28,17 +30,48 @@ class EmailForm extends React.Component {
const
{
email
,
password
}
=
values
;
const
{
email
,
password
}
=
values
;
dispatch
({
type
:
'
user/updateEmail
'
,
payload
:
{
email
,
password
,
user_id
:
id
}
});
dispatch
({
type
:
'
user/updateEmail
'
,
payload
:
{
email
,
password
,
user_id
:
id
}
});
this
.
setState
({
countdown
:
5
,
inCountdown
:
true
});
this
.
countdownTimer
=
setInterval
(
this
.
handleCountdown
,
1000
);
}
}
});
});
};
};
handleCountdown
=
()
=>
{
// 倒计时减1
this
.
setState
(
prevState
=>
({
countdown
:
prevState
.
countdown
-
1
}));
if
(
this
.
state
.
countdown
===
0
)
{
// 清除倒计时
clearInterval
(
this
.
countdownTimer
);
// 设置倒计时状态为false
this
.
setState
({
inCountdown
:
false
});
// 倒计时结束后调用退出
this
.
handleLogout
();
}
};
handleLogout
=
()
=>
{
clearInterval
(
this
.
countdownTimer
);
window
.
localStorage
.
removeItem
(
'
token
'
);
if
(
window
.
ygopro
)
{
window
.
ygopro
.
logoutUser
(
'
YGOMobile萌卡已登出
'
);
}
const
url
=
new
URL
(
window
.
location
.
href
);
const
redirect
=
url
.
searchParams
.
get
(
'
redirect
'
)
||
'
/
'
;
window
.
location
.
href
=
redirect
;
};
handleLogoutNow
=
()
=>
{
this
.
setState
({
countdown
:
0
},
()
=>
{
this
.
handleLogout
();
});
};
render
()
{
render
()
{
const
{
form
,
dispatch
,
user
,
checkEmail
,
isEmailExists
,
messages
}
=
this
.
props
;
const
{
form
,
dispatch
,
user
,
checkEmail
,
isEmailExists
,
messages
}
=
this
.
props
;
const
{
getFieldDecorator
}
=
form
;
const
{
getFieldDecorator
}
=
form
;
const
{
id
,
email
}
=
user
;
const
{
id
,
email
}
=
user
;
// const { intl: { messages } } = this.context;
// const { intl: { messages } } = this.context;
const
logoutNowText
=
this
.
props
.
messages
.
LogoutNow
;
const
loggingOutInText
=
this
.
props
.
messages
.
LoggingOutIn
;
const
secondsText
=
this
.
props
.
messages
.
Seconds
;
const
ChangeSuccessText
=
this
.
props
.
messages
.
EmailChangeSuccess
;
const
emailProps
=
{
const
emailProps
=
{
fromItem
:
{
fromItem
:
{
label
:
messages
.
email
,
label
:
messages
.
email
,
...
@@ -74,28 +107,47 @@ class EmailForm extends React.Component {
...
@@ -74,28 +107,47 @@ class EmailForm extends React.Component {
type
:
'
password
'
,
type
:
'
password
'
,
},
},
};
};
const
{
inCountdown
,
countdown
}
=
this
.
state
;
return
(
return
(
<
Form
onSubmit
=
{
this
.
onSubmit
}
>
<
div
>
<
FormItem
{...
emailProps
.
fromItem
}
>
{
inCountdown
?
(
{
getFieldDecorator
(
'
email
'
,
{
...
emailProps
.
decorator
})(
<
div
style
=
{{
display
:
'
flex
'
,
flexDirection
:
'
column
'
,
alignItems
:
'
center
'
,
height
:
'
100vh
'
}}
>
<
Input
<
div
style
=
{{
flex
:
9
/
10
,
textAlign
:
'
center
'
}}
>
{...
emailProps
.
input
}
<
h3
>
{
ChangeSuccessText
}
<
/h3
>
onBlur
=
{()
=>
dispatch
({
type
:
'
auth/checkEmail
'
,
payload
:
{
...
form
.
getFieldsValue
(),
user_id
:
id
}
})}
<
h3
>
/>
,
{
loggingOutInText
}
)}
<
span
style
=
{{
color
:
'
#4da9ee
'
,
fontSize
:
'
2em
'
}}
>&
nbsp
;{
`
${
countdown
}
`
}
<
/span
>
<
/FormItem
>
<
span
>&
nbsp
;{
secondsText
}
<
/span
>
<
/h3
>
<
FormItem
{...
passwordProps
.
fromItem
}
>
<
br
/>
{
getFieldDecorator
(
'
password
'
,
{
...
passwordProps
.
decorator
})(
<
Button
type
=
"
link
"
onClick
=
{
this
.
handleLogoutNow
}
>
<
Input
{...
passwordProps
.
input
}
/>
,
{
logoutNowText
}
)}
<
/Button
>
<
/FormItem
>
<
/div
>
<
/div
>
<
FormItem
>
)
:
(
<
SubmitButton
/>
<
Form
onSubmit
=
{
this
.
onSubmit
}
>
<
/FormItem
>
<
FormItem
{...
emailProps
.
fromItem
}
>
<
/Form
>
{
getFieldDecorator
(
'
email
'
,
{
...
emailProps
.
decorator
})(
<
Input
{...
emailProps
.
input
}
onBlur
=
{()
=>
dispatch
({
type
:
'
auth/checkEmail
'
,
payload
:
{
...
form
.
getFieldsValue
(),
user_id
:
id
}
})}
/>
,
)}
<
/FormItem
>
<
FormItem
{...
passwordProps
.
fromItem
}
>
{
getFieldDecorator
(
'
password
'
,
{
...
passwordProps
.
decorator
})(
<
Input
{...
passwordProps
.
input
}
/>
,
)}
<
/FormItem
>
<
FormItem
>
<
SubmitButton
/>
<
/FormItem
>
<
/Form
>
)}
<
/div
>
);
);
}
}
}
}
...
...
src/components/PasswordForm.js
View file @
4481f62d
import
{
Form
,
Input
}
from
'
antd
'
;
import
{
Form
,
Input
,
Button
}
from
'
antd
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
connect
}
from
'
react-redux
'
;
import
SubmitButton
from
'
./SubmitButton
'
;
import
SubmitButton
from
'
./SubmitButton
'
;
const
FormItem
=
Form
.
Item
;
const
FormItem
=
Form
.
Item
;
const
formItemLayout
=
{
const
formItemLayout
=
{
labelCol
:
{
span
:
4
},
labelCol
:
{
span
:
4
},
wrapperCol
:
{
span
:
15
},
wrapperCol
:
{
span
:
15
},
...
@@ -14,7 +12,10 @@ const formItemLayout = {
...
@@ -14,7 +12,10 @@ const formItemLayout = {
class
EmailForm
extends
React
.
Component
{
class
EmailForm
extends
React
.
Component
{
state
=
{
countdown
:
0
,
inCountdown
:
false
,
// 是否处于倒计时状态
};
onSubmit
=
(
e
)
=>
{
onSubmit
=
(
e
)
=>
{
const
{
form
,
dispatch
,
user
:
{
id
}
}
=
this
.
props
;
const
{
form
,
dispatch
,
user
:
{
id
}
}
=
this
.
props
;
...
@@ -28,13 +29,47 @@ class EmailForm extends React.Component {
...
@@ -28,13 +29,47 @@ class EmailForm extends React.Component {
const
{
new_password
,
password
}
=
values
;
const
{
new_password
,
password
}
=
values
;
dispatch
({
type
:
'
user/updateAccount
'
,
payload
:
{
new_password
,
password
,
user_id
:
id
}
});
dispatch
({
type
:
'
user/updateAccount
'
,
payload
:
{
new_password
,
password
,
user_id
:
id
}
});
// 设置倒计时状态为5秒
this
.
setState
({
countdown
:
5
,
inCountdown
:
true
});
// 启动倒计时
this
.
countdownTimer
=
setInterval
(
this
.
handleCountdown
,
1000
);
}
}
});
});
};
};
handleCountdown
=
()
=>
{
// 倒计时减1
this
.
setState
(
prevState
=>
({
countdown
:
prevState
.
countdown
-
1
}));
if
(
this
.
state
.
countdown
===
0
)
{
// 清除倒计时
clearInterval
(
this
.
countdownTimer
);
// 设置倒计时状态为false
this
.
setState
({
inCountdown
:
false
});
// 倒计时结束后调用退出
this
.
handleLogout
();
}
};
handleLogout
=
()
=>
{
clearInterval
(
this
.
countdownTimer
);
window
.
localStorage
.
removeItem
(
'
token
'
);
if
(
window
.
ygopro
)
{
window
.
ygopro
.
logoutUser
(
'
YGOMobile萌卡已登出
'
);
}
const
url
=
new
URL
(
window
.
location
.
href
);
const
redirect
=
url
.
searchParams
.
get
(
'
redirect
'
)
||
'
/
'
;
window
.
location
.
href
=
redirect
;
};
handleLogoutNow
=
()
=>
{
this
.
setState
({
countdown
:
0
},
()
=>
{
this
.
handleLogout
();
});
};
checkPassword
=
(
rule
,
value
,
callback
)
=>
{
checkPassword
=
(
rule
,
value
,
callback
)
=>
{
const
{
form
,
messages
}
=
this
.
props
;
const
{
form
,
messages
}
=
this
.
props
;
//const { intl: { messages } } = this.context;
//
const { intl: { messages } } = this.context;
if
(
value
&&
value
!==
form
.
getFieldValue
(
'
new_password
'
))
{
if
(
value
&&
value
!==
form
.
getFieldValue
(
'
new_password
'
))
{
callback
(
messages
[
'
Incorrect-password.2
'
]);
callback
(
messages
[
'
Incorrect-password.2
'
]);
}
else
{
}
else
{
...
@@ -54,7 +89,10 @@ class EmailForm extends React.Component {
...
@@ -54,7 +89,10 @@ class EmailForm extends React.Component {
render
()
{
render
()
{
const
{
form
,
messages
}
=
this
.
props
;
const
{
form
,
messages
}
=
this
.
props
;
const
{
getFieldDecorator
}
=
form
;
const
{
getFieldDecorator
}
=
form
;
const
logoutNowText
=
this
.
props
.
messages
.
LogoutNow
;
const
loggingOutInText
=
this
.
props
.
messages
.
LoggingOutIn
;
const
secondsText
=
this
.
props
.
messages
.
Seconds
;
const
ChangeSuccessText
=
this
.
props
.
messages
.
ChangeSuccess
;
const
passwordProps
=
{
const
passwordProps
=
{
fromItem
:
{
fromItem
:
{
label
:
messages
[
'
old-password
'
],
label
:
messages
[
'
old-password
'
],
...
@@ -100,31 +138,50 @@ class EmailForm extends React.Component {
...
@@ -100,31 +138,50 @@ class EmailForm extends React.Component {
type
:
'
password
'
,
type
:
'
password
'
,
},
},
};
};
const
{
inCountdown
,
countdown
}
=
this
.
state
;
return
(
return
(
<
Form
onSubmit
=
{
this
.
onSubmit
}
>
<
div
>
<
FormItem
{...
passwordProps
.
fromItem
}
label
=
{
messages
[
'
old-password
'
]}
>
{
inCountdown
?
(
{
getFieldDecorator
(
'
password
'
)(
<
div
style
=
{{
display
:
'
flex
'
,
flexDirection
:
'
column
'
,
alignItems
:
'
center
'
,
height
:
'
100vh
'
}}
>
<
Input
{...
passwordProps
.
input
}
/>
,
<
div
style
=
{{
flex
:
9
/
10
,
textAlign
:
'
center
'
}}
>
)}
<
h3
>
{
ChangeSuccessText
}
<
/h3
>
<
/FormItem
>
<
h3
>
{
loggingOutInText
}
<
FormItem
{...
passwordProps
.
fromItem
}
label
=
{
messages
[
'
new-password
'
]}
>
<
span
style
=
{{
color
:
'
#4da9ee
'
,
fontSize
:
'
2em
'
}}
>&
nbsp
;{
`
${
countdown
}
`
}
<
/span
>
{
getFieldDecorator
(
'
new_password
'
,
{
...
passwordProps
.
decorator
})(
<
span
>&
nbsp
;{
secondsText
}
<
/span
>
<
Input
{...
passwordProps
.
input2
}
/>
,
<
/h3
>
)}
<
br
/>
<
/FormItem
>
<
Button
type
=
"
link
"
onClick
=
{
this
.
handleLogoutNow
}
>
{
logoutNowText
}
<
FormItem
{...
confirmProps
.
fromItem
}
>
<
/Button
>
{
getFieldDecorator
(
'
confirm
'
,
{
...
confirmProps
.
decorator
})(
<
/div
>
<
Input
{...
confirmProps
.
input
}
/>
,
<
/div
>
)}
)
:
(
<
/FormItem
>
<
Form
onSubmit
=
{
this
.
onSubmit
}
>
<
FormItem
{...
passwordProps
.
fromItem
}
label
=
{
messages
[
'
old-password
'
]}
>
<
FormItem
>
{
getFieldDecorator
(
'
password
'
)(
<
SubmitButton
/>
<
Input
{...
passwordProps
.
input
}
/>
,
<
/FormItem
>
)}
<
/Form
>
<
/FormItem
>
<
FormItem
{...
passwordProps
.
fromItem
}
label
=
{
messages
[
'
new-password
'
]}
>
{
getFieldDecorator
(
'
new_password
'
,
{
...
passwordProps
.
decorator
})(
<
Input
{...
passwordProps
.
input2
}
/>
,
)}
<
/FormItem
>
<
FormItem
{...
confirmProps
.
fromItem
}
>
{
getFieldDecorator
(
'
confirm
'
,
{
...
confirmProps
.
decorator
})(
<
Input
{...
confirmProps
.
input
}
/>
,
)}
<
/FormItem
>
<
FormItem
>
<
SubmitButton
/>
<
/FormItem
>
<
/Form
>
)}
<
/div
>
);
);
}
}
}
}
...
@@ -135,6 +192,7 @@ function mapStateToProps(state) {
...
@@ -135,6 +192,7 @@ function mapStateToProps(state) {
user
:
{
user
},
user
:
{
user
},
common
:
{
messages
},
common
:
{
messages
},
}
=
state
;
}
=
state
;
return
{
return
{
messages
,
messages
,
user
,
user
,
...
...
src/components/UserNameForm.js
View file @
4481f62d
import
{
Form
,
Input
}
from
'
antd
'
;
import
{
Button
,
Form
,
Input
}
from
'
antd
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
connect
}
from
'
react-redux
'
;
import
SubmitButton
from
'
./SubmitButton
'
;
import
SubmitButton
from
'
./SubmitButton
'
;
...
@@ -11,7 +11,10 @@ const formItemLayout = {
...
@@ -11,7 +11,10 @@ const formItemLayout = {
class
EmailForm
extends
React
.
Component
{
class
EmailForm
extends
React
.
Component
{
state
=
{
countdown
:
0
,
inCountdown
:
false
,
// Whether the countdown is active
};
onSubmit
=
(
e
)
=>
{
onSubmit
=
(
e
)
=>
{
const
{
form
,
dispatch
,
user
:
{
id
}
}
=
this
.
props
;
const
{
form
,
dispatch
,
user
:
{
id
}
}
=
this
.
props
;
...
@@ -21,25 +24,74 @@ class EmailForm extends React.Component {
...
@@ -21,25 +24,74 @@ class EmailForm extends React.Component {
form
.
validateFieldsAndScroll
((
err
,
values
)
=>
{
form
.
validateFieldsAndScroll
((
err
,
values
)
=>
{
if
(
!
err
)
{
if
(
!
err
)
{
console
.
log
(
'
Received values of form:
'
,
values
);
console
.
log
(
'
Received values of form:
'
,
values
);
const
{
username
,
password
}
=
values
;
const
{
username
,
password
}
=
values
;
dispatch
({
type
:
'
user/updateAccount
'
,
payload
:
{
username
,
password
,
user_id
:
id
}
});
dispatch
({
type
:
'
user/updateAccount
'
,
payload
:
{
username
,
password
,
user_id
:
id
}
});
this
.
setState
({
countdown
:
5
,
inCountdown
:
true
});
this
.
countdownTimer
=
setInterval
(
this
.
handleCountdown
,
1000
);
}
}
});
});
};
};
handleCountdown
=
()
=>
{
// 倒计时减1
this
.
setState
(
prevState
=>
({
countdown
:
prevState
.
countdown
-
1
}));
if
(
this
.
state
.
countdown
===
0
)
{
// 清除倒计时
clearInterval
(
this
.
countdownTimer
);
// 设置倒计时状态为false
this
.
setState
({
inCountdown
:
false
});
// 倒计时结束后调用退出
this
.
handleLogout
();
}
};
handleLogout
=
()
=>
{
clearInterval
(
this
.
countdownTimer
);
window
.
localStorage
.
removeItem
(
'
token
'
);
if
(
window
.
ygopro
)
{
window
.
ygopro
.
logoutUser
(
'
YGOMobile萌卡已登出
'
);
}
const
url
=
new
URL
(
window
.
location
.
href
);
const
redirect
=
url
.
searchParams
.
get
(
'
redirect
'
)
||
'
/
'
;
window
.
location
.
href
=
redirect
;
};
handleLogoutNow
=
()
=>
{
this
.
setState
({
countdown
:
0
},
()
=>
{
this
.
handleLogout
();
});
};
checkPassword
=
(
rule
,
value
,
callback
)
=>
{
const
{
form
,
messages
}
=
this
.
props
;
// const { intl: { messages } } = this.context;
if
(
value
&&
value
!==
form
.
getFieldValue
(
'
new_password
'
))
{
callback
(
messages
[
'
Incorrect-password.2
'
]);
}
else
{
callback
();
}
};
checkConfirm
=
(
rule
,
value
,
callback
)
=>
{
const
form
=
this
.
props
.
form
;
if
(
value
)
{
form
.
validateFields
([
'
confirm
'
],
{
force
:
true
});
}
callback
();
};
render
()
{
render
()
{
const
{
form
,
dispatch
,
user
,
checkUsername
,
isUserNameExists
,
messages
}
=
this
.
props
;
const
{
form
,
dispatch
,
user
,
checkUsername
,
isUserNameExists
,
messages
}
=
this
.
props
;
const
{
getFieldDecorator
}
=
form
;
const
{
getFieldDecorator
}
=
form
;
const
{
id
,
username
}
=
user
;
const
{
id
,
username
}
=
user
;
const
logoutNowText
=
this
.
props
.
messages
.
LogoutNow
;
const
loggingOutInText
=
this
.
props
.
messages
.
LoggingOutIn
;
const
secondsText
=
this
.
props
.
messages
.
Seconds
;
const
temporaryPromptText
=
this
.
props
.
messages
.
TemporaryPrompt
;
const
ChangeSuccessText
=
this
.
props
.
messages
.
ChangeSuccess
;
const
usernameProps
=
{
const
usernameProps
=
{
fromItem
:
{
fromItem
:
{
label
:
messages
.
username
,
label
:
messages
.
username
,
hasFeedback
:
true
,
hasFeedback
:
true
,
validateStatus
:
checkUsername
,
validateStatus
:
checkUsername
,
extra
:
isUserNameExists
?
'
username exists
'
:
''
,
extra
:
isUserNameExists
?
messages
.
i_username_exists_or_invalid
:
''
,
...
formItemLayout
,
...
formItemLayout
,
},
},
decorator
:
{
decorator
:
{
...
@@ -70,34 +122,52 @@ class EmailForm extends React.Component {
...
@@ -70,34 +122,52 @@ class EmailForm extends React.Component {
type
:
'
password
'
,
type
:
'
password
'
,
},
},
};
};
const
{
inCountdown
,
countdown
}
=
this
.
state
;
return
(
return
(
<
Form
onSubmit
=
{
this
.
onSubmit
}
>
<
div
>
<
FormItem
{...
usernameProps
.
fromItem
}
>
{
inCountdown
?
(
{
getFieldDecorator
(
'
username
'
,
{
...
usernameProps
.
decorator
})(
<
div
style
=
{{
display
:
'
flex
'
,
flexDirection
:
'
column
'
,
alignItems
:
'
center
'
,
height
:
'
100vh
'
}}
>
<
Input
{...
usernameProps
.
input
}
disabled
/>
,
<
div
style
=
{{
flex
:
9
/
10
,
textAlign
:
'
center
'
}}
>
)}
<
h3
>
{
ChangeSuccessText
}
<
/h3
>
{
<
h3
>
<
div
class
=
"
alert alert-warning
"
role
=
"
alert
"
>
改名已经关闭。改名将在
1
月,
4
月,
7
月和
10
月的第一周开启。
<
/div
>
{
loggingOutInText
}
}
<
span
style
=
{{
color
:
'
#4da9ee
'
,
fontSize
:
'
2em
'
}}
>&
nbsp
;{
`
${
countdown
}
`
}
<
/span
>
<
span
>&
nbsp
;{
secondsText
}
<
/span
>
<
/FormItem
>
<
/h3
>
<
br
/>
<
FormItem
{...
passwordProps
.
fromItem
}
>
<
Button
type
=
"
link
"
onClick
=
{
this
.
handleLogoutNow
}
>
{
getFieldDecorator
(
'
password
'
,
{
...
passwordProps
.
decorator
})(
{
logoutNowText
}
<
Input
{...
passwordProps
.
input
}
/>
,
<
/Button
>
)}
<
/div
>
<
/FormItem
>
<
/div
>
)
:
(
<
FormItem
>
<
Form
onSubmit
=
{
this
.
onSubmit
}
>
<
SubmitButton
disabled
/>
<
FormItem
{...
usernameProps
.
fromItem
}
>
<
/FormItem
>
{
getFieldDecorator
(
'
username
'
,
{
...
usernameProps
.
decorator
})(
<
/Form
>
<
Input
{...
usernameProps
.
input
}
/>
,
)}
{
<
div
className
=
"
alert alert-warning
"
role
=
"
alert
"
>
{
temporaryPromptText
}
<
/div
>
}
<
/FormItem
>
<
FormItem
{...
passwordProps
.
fromItem
}
>
{
getFieldDecorator
(
'
password
'
,
{
...
passwordProps
.
decorator
})(
<
Input
{...
passwordProps
.
input
}
/>
,
)}
<
/FormItem
>
<
FormItem
>
<
SubmitButton
/>
<
/FormItem
>
<
/Form
>
)}
<
/div
>
);
);
}
}
}
}
function
mapStateToProps
(
state
)
{
function
mapStateToProps
(
state
)
{
const
{
const
{
user
:
{
user
},
user
:
{
user
},
...
...
src/components/UserPanel.js
View file @
4481f62d
...
@@ -11,6 +11,9 @@ function mutatedUserAvatar(avatar) {
...
@@ -11,6 +11,9 @@ function mutatedUserAvatar(avatar) {
if
(
!
avatar
)
{
if
(
!
avatar
)
{
return
avatar
;
return
avatar
;
}
}
if
(
avatar
.
includes
(
'
default_avatar
'
))
{
return
defaultAvatar
;
}
return
`https://sapi.moecube.com:444/avatar/url/
${
avatar
.
split
(
'
/
'
).
pop
()}
/40/avatar.png`
;
return
`https://sapi.moecube.com:444/avatar/url/
${
avatar
.
split
(
'
/
'
).
pop
()}
/40/avatar.png`
;
}
}
...
...
src/models/auth.js
View file @
4481f62d
...
@@ -24,6 +24,9 @@ export default {
...
@@ -24,6 +24,9 @@ export default {
signOut
(
state
)
{
signOut
(
state
)
{
console
.
log
(
'
sign out
'
);
console
.
log
(
'
sign out
'
);
localStorage
.
removeItem
(
'
token
'
);
localStorage
.
removeItem
(
'
token
'
);
if
(
window
.
ygopro
)
{
window
.
ygopro
.
logoutUser
(
"
YGOMobile萌卡登出
"
);
}
location
.
href
=
'
/
'
;
location
.
href
=
'
/
'
;
return
state
;
return
state
;
},
},
...
...
src/models/user.js
View file @
4481f62d
...
@@ -214,6 +214,9 @@ export default {
...
@@ -214,6 +214,9 @@ export default {
}
}
if
(
pathname
===
'
/logout
'
)
{
if
(
pathname
===
'
/logout
'
)
{
localStorage
.
removeItem
(
'
token
'
);
localStorage
.
removeItem
(
'
token
'
);
if
(
window
.
ygopro
)
{
window
.
ygopro
.
logoutUser
(
"
YGOMobile 萌卡登出
"
);
}
location
.
href
=
query
.
redirect
;
location
.
href
=
query
.
redirect
;
}
}
});
});
...
...
src/routes/Index.js
View file @
4481f62d
...
@@ -9,6 +9,8 @@ import Format from '../components/Format';
...
@@ -9,6 +9,8 @@ import Format from '../components/Format';
import
logo
from
'
../assets/MoeCube.png
'
;
import
logo
from
'
../assets/MoeCube.png
'
;
import
UserPanel
from
'
../components/UserPanel
'
;
import
UserPanel
from
'
../components/UserPanel
'
;
import
'
./Index.less
'
;
const
languageMap
=
{
const
languageMap
=
{
'
zh-CN
'
:
'
中文
'
,
'
zh-CN
'
:
'
中文
'
,
'
en-US
'
:
'
English
'
,
'
en-US
'
:
'
English
'
,
...
@@ -151,10 +153,10 @@ function Index({ children, messages, dispatch, client, language }) {
...
@@ -151,10 +153,10 @@ function Index({ children, messages, dispatch, client, language }) {
);
);
return
(
return
(
<
div
style
=
{{
display
:
'
flex
'
,
flexDirection
:
'
column
'
,
flex
:
1
,
minHeight
:
'
100%
'
}}
>
<
div
style
=
{{
display
:
'
flex
'
,
flexDirection
:
'
column
'
,
flex
:
1
,
minHeight
:
'
100%
'
}}
>
<
DocumentTitle
title
=
{
messages
.
title
||
'
Moe
Cube
'
}
/
>
<
DocumentTitle
title
=
{
messages
.
title
||
'
MoeCube
'
}
/
>
{
client
!==
'
electron
'
&&
{
client
!==
'
electron
'
&&
<
Header
style
=
{{
display
:
'
flex
'
,
alignItems
:
'
center
'
}}
>
<
Header
style
=
{{
display
:
'
flex
'
,
alignItems
:
'
center
'
}}
className
=
"
mc-header
"
>
<
Link
to
=
"
/
"
style
=
{{
marginTop
:
'
20px
'
}}
>
<
Link
to
=
"
/
"
style
=
{{
marginTop
:
'
20px
'
}}
>
<
img
alt
=
"
logo
"
src
=
{
logo
}
style
=
{{
width
:
'
140px
'
,
height
:
'
44px
'
}}
/
>
<
img
alt
=
"
logo
"
src
=
{
logo
}
style
=
{{
width
:
'
140px
'
,
height
:
'
44px
'
}}
/
>
<
/Link
>
<
/Link
>
...
@@ -182,7 +184,7 @@ function Index({ children, messages, dispatch, client, language }) {
...
@@ -182,7 +184,7 @@ function Index({ children, messages, dispatch, client, language }) {
<
/Menu.Item
>
<
/Menu.Item
>
<
/Menu
>
<
/Menu
>
<
div
style
=
{{
position
:
'
absolute
'
,
right
:
'
40px
'
}}
>
<
div
className
=
"
mc-userpanel
"
>
<
UserPanel
/>
<
UserPanel
/>
<
/div
>
<
/div
>
<
/Header
>
<
/Header
>
...
@@ -202,7 +204,7 @@ function Index({ children, messages, dispatch, client, language }) {
...
@@ -202,7 +204,7 @@ function Index({ children, messages, dispatch, client, language }) {
{
languageMap
[
language
]}
<
Icon
type
=
"
down
"
className
=
"
flag
"
/>
{
languageMap
[
language
]}
<
Icon
type
=
"
down
"
className
=
"
flag
"
/>
<
/a
>
<
/a
>
<
/Dropdown></
div
>
<
/Dropdown></
div
>
<
div
>
©
MoeCube
2017
-
202
2
all
right
reserved
.
<
/div
>
<
div
>
©
MoeCube
2017
-
202
3
all
right
reserved
.
<
/div
>
<
/Footer
>
<
/Footer
>
<
/div
>
<
/div
>
);
);
...
...
src/routes/Index.less
View file @
4481f62d
.particles {
.particles {
position: fixed;
position: fixed;
top: 0;
top: 0;
...
@@ -7,3 +6,20 @@
...
@@ -7,3 +6,20 @@
width: 100%;
width: 100%;
height: 100%;
height: 100%;
}
}
:global {
.mc-userpanel {
position: absolute;
right: 40px;
}
@media (max-width: 768px) {
.mc-header {
padding: 0 10px;
}
.mc-userpanel {
right: 10px;
}
}
}
\ No newline at end of file
src/routes/Logout.js
View file @
4481f62d
...
@@ -4,6 +4,9 @@ import React from 'react';
...
@@ -4,6 +4,9 @@ import React from 'react';
class
Logout
extends
React
.
Component
{
class
Logout
extends
React
.
Component
{
componentDidMount
()
{
componentDidMount
()
{
window
.
localStorage
.
removeItem
(
'
token
'
);
window
.
localStorage
.
removeItem
(
'
token
'
);
if
(
window
.
ygopro
)
{
window
.
ygopro
.
logoutUser
(
"
YGOMobile萌卡已登出
"
);
}
const
url
=
new
URL
(
window
.
location
.
href
);
const
url
=
new
URL
(
window
.
location
.
href
);
const
redirect
=
url
.
searchParams
.
get
(
'
redirect
'
)
||
'
/
'
;
const
redirect
=
url
.
searchParams
.
get
(
'
redirect
'
)
||
'
/
'
;
window
.
location
.
href
=
redirect
;
window
.
location
.
href
=
redirect
;
...
...
src/routes/Profiles.js
View file @
4481f62d
...
@@ -107,28 +107,31 @@ class Profiles extends React.Component {
...
@@ -107,28 +107,31 @@ class Profiles extends React.Component {
<
Form
onSubmit
=
{
this
.
onUpdateSubmit
}
>
<
Form
onSubmit
=
{
this
.
onUpdateSubmit
}
>
<
FormItem
style
=
{{
display
:
'
flex
'
,
justifyContent
:
'
center
'
}}
>
<
FormItem
style
=
{{
display
:
'
flex
'
,
justifyContent
:
'
center
'
}}
>
<
div
style
=
{{
display
:
isUpload
?
'
flex
'
:
'
none
'
,
flexDirection
:
'
column
'
}}
>
<
div
style
=
{{
display
:
'
flex
'
,
flexDirection
:
'
column
'
}}
>
<
Cropper
<
Cropper
ref
=
{(
cropper
)
=>
{
ref
=
{(
cropper
)
=>
{
this
.
cropper
=
cropper
;
this
.
cropper
=
cropper
;
}}
}}
src
=
{
imageUrl
||
defaultAvatar
}
src
=
{
imageUrl
||
defaultAvatar
}
className
=
"
cropper-image
"
className
=
"
cropper-image
"
style
=
{{
height
:
'
20vw
'
,
width
:
'
20vw
'
}}
style
=
{{
height
:
'
300px
'
,
width
:
'
300px
'
,
display
:
isUpload
?
'
block
'
:
'
none
'
}}
aspectRatio
=
{
1
/
1
}
aspectRatio
=
{
1
/
1
}
autoCropArea
=
{
1
}
guides
guides
/>
/>
<
br
/>
<
img
<
Button
type
=
"
primary
"
onClick
=
{
this
.
handleUpload
}
>
alt
=
"
avatar
"
<
Icon
type
=
"
upload
"
/>
<
Format
id
=
"
upload
"
/>
style
=
{{
height
:
'
300px
'
,
width
:
'
300px
'
,
display
:
!
isUpload
?
'
block
'
:
'
none
'
}}
src
=
{
avatar
||
imageUrl
||
defaultAvatar
}
/
>
<
Button
type
=
"
primary
"
onClick
=
{
this
.
handleUpload
}
style
=
{{
display
:
isUpload
?
'
inline-block
'
:
'
none
'
,
marginTop
:
'
2em
'
}}
>
<
Icon
type
=
"
check
"
/>
<
Format
id
=
"
Upload-Avatar
"
/>
<
/Button
>
<
/Button
>
<
/div
>
<
Button
type
=
"
default
"
style
=
{{
marginTop
:
'
2em
'
}}
>
<
div
style
=
{{
display
:
!
isUpload
?
'
flex
'
:
'
none
'
,
flexDirection
:
'
column
'
}}
>
<
img
alt
=
"
avatar
"
style
=
{{
height
:
'
20vw
'
,
width
:
'
20vw
'
}}
src
=
{
avatar
||
imageUrl
||
defaultAvatar
}
/
>
<
Button
style
=
{{
padding
:
'
4px 0
'
}}
>
<
label
style
=
{{
display
:
'
flex
'
,
flex
:
1
,
justifyContent
:
'
center
'
,
alignItems
:
'
center
'
}}
>
<
label
style
=
{{
display
:
'
flex
'
,
flex
:
1
,
justifyContent
:
'
center
'
,
alignItems
:
'
center
'
}}
>
<
Icon
type
=
"
plus
"
/><
Format
id
=
"
Change-Avatar
"
/>
<
Icon
type
=
"
plus
"
style
=
{{
marginRight
:
'
0.5em
'
}}
/
>
{(
!
isUpload
)
&&
<
Format
id
=
"
Change-Avatar
"
/>
}
{
isUpload
&&
<
Format
id
=
"
Reselect-Avatar
"
/>
}
<
input
<
input
type
=
"
file
"
onChange
=
{
this
.
onGetFile
}
ref
=
{(
file
)
=>
{
type
=
"
file
"
onChange
=
{
this
.
onGetFile
}
ref
=
{(
file
)
=>
{
this
.
file
=
file
;
this
.
file
=
file
;
...
@@ -143,6 +146,9 @@ class Profiles extends React.Component {
...
@@ -143,6 +146,9 @@ class Profiles extends React.Component {
{
getFieldDecorator
(
'
name
'
,
{
...
nameProps
.
decorator
})(
{
getFieldDecorator
(
'
name
'
,
{
...
nameProps
.
decorator
})(
<
Input
{...
nameProps
.
input
}
/>
,
<
Input
{...
nameProps
.
input
}
/>
,
)}
)}
{
<
div
className
=
"
alert alert-warning
"
role
=
"
alert
"
><
Format
id
=
"
Nickname-Hint
"
/><
/div
>
}
<
/FormItem
>
<
/FormItem
>
<
FormItem
>
<
FormItem
>
...
...
src/routes/Register.js
View file @
4481f62d
...
@@ -74,7 +74,7 @@ class Register extends React.Component {
...
@@ -74,7 +74,7 @@ class Register extends React.Component {
const
usernameProps
=
{
const
usernameProps
=
{
hasFeedback
:
true
,
hasFeedback
:
true
,
validateStatus
:
checkUsername
,
validateStatus
:
checkUsername
,
extra
:
isUserNameExists
?
'
username exists or invalid
'
:
''
,
extra
:
isUserNameExists
?
messages
.
i_username_exists
:
''
,
};
};
const
usernameInputProps
=
{
const
usernameInputProps
=
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment