feat: dev 新增我的账户,修改昵称和密码

pull/107/head
huoyong.msb 5 years ago
parent 6e1f76b8d3
commit 022ad46b81

@ -159,3 +159,32 @@ export interface DoFetchUserSettingsAction {
cb?: (isOk: boolean, payload?: any) => void
}
}
export type UPDATE_ACCOUNT_REQUEST = 'UPDATE_ACCOUNT_REQUEST'
export const UPDATE_ACCOUNT_REQUEST: UPDATE_ACCOUNT_REQUEST = 'UPDATE_ACCOUNT_REQUEST'
export type UPDATE_ACCOUNT_SUCCESS = 'UPDATE_ACCOUNT_SUCCESS'
export const UPDATE_ACCOUNT_SUCCESS: UPDATE_ACCOUNT_SUCCESS = 'UPDATE_ACCOUNT_SUCCESS'
export type UPDATE_ACCOUNT_FAILURE = 'UPDATE_ACCOUNT_FAILURE'
export const UPDATE_ACCOUNT_FAILURE: UPDATE_ACCOUNT_FAILURE = 'UPDATE_ACCOUNT_FAILURE'
export const updateAccount = (payload: { fullname?: string, password?: string}) => ({
[RSAA]: mergeRSAABase({
endpoint: `${serve}/account/updateAccount`,
method: 'POST',
body: JSON.stringify(payload),
types: [UPDATE_ACCOUNT_REQUEST, UPDATE_ACCOUNT_SUCCESS, UPDATE_ACCOUNT_FAILURE],
}),
})
export type DO_UPDATE_ACCOUNT = 'DO_UPDATE_ACCOUNT'
export const DO_UPDATE_ACCOUNT = 'DO_UPDATE_ACCOUNT'
export const doUpdateAccount = (params: {fullname?: string, password?: string}, cb: TCB) => ({
type: DO_UPDATE_ACCOUNT,
payload: {
params,
cb,
},
})

@ -2,7 +2,12 @@ import { RouterState } from 'connected-react-router'
import { THEME_TEMPLATE_KEY } from 'components/account/ThemeChangeOverlay'
export interface RootState {
auth: any
auth: {
id: number
empId: string
fullname: string
email: string
}
router: RouterState
repository: any
repositories: any
@ -62,6 +67,7 @@ export interface User {
id: number
fullname: string
email: string
empId: string
}
export interface INumItem {

@ -0,0 +1,58 @@
import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { TextField, Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@material-ui/core'
import { doUpdateAccount } from 'actions/account'
function EditMyAccountDialog({ handleClose }: { handleClose: (isOk: boolean) => void }) {
const [pwd, setPwd] = useState('')
const [name, setName] = useState('')
const dispatch = useDispatch()
const onSubmit = () => {
dispatch(doUpdateAccount({ fullname: name, password: pwd }, isOk => {
if (isOk) {
handleClose(true)
}
}))
}
return (
<Dialog open={true} onClose={() => handleClose(false)} style={{ width: 600 }}>
<DialogTitle></DialogTitle>
<DialogContent>
<TextField
autoFocus={true}
margin="dense"
label="修改密码"
type="password"
fullWidth={true}
placeholder="不修改留空即可"
onChange={e => setPwd(e.target.value)}
value={pwd}
/>
<TextField
autoFocus={true}
margin="dense"
label="修改昵称"
fullWidth={true}
placeholder="不修改留空即可"
onChange={e => setName(e.target.value)}
value={name}
/>
</DialogContent>
<DialogActions>
<Button onClick={() => handleClose(false)} color="secondary">
</Button>
<Button
color="primary"
onClick={onSubmit}
>
</Button>
</DialogActions>
</Dialog>
)
}
export default EditMyAccountDialog

@ -0,0 +1,80 @@
import React, { useState } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { RootState } from 'actions/types'
import { makeStyles, Theme, Card, CardActionArea, CardContent, Typography, CardActions, Button } from '@material-ui/core'
import EditMyAccountDialog from './EditMyAccountDialog'
import { logout, fetchLoginInfo } from 'actions/account'
const useStyles = makeStyles(({ palette, spacing }: Theme) => ({
root: {
margin: spacing(2),
},
dialog: {
},
card: {
minWidth: 375,
maxWidth: 500,
maxHeight: `calc(100% - ${spacing(4)}px)`,
overflowY: 'auto',
},
media: {
objectFit: 'cover',
height: 250,
},
title: {
marginTop: spacing(1),
color: palette.primary.main,
},
dialogPapaer: {
margin: spacing(2),
},
}))
function MyAccountView() {
const me = useSelector((state: RootState) => state.auth)
const classes = useStyles()
const [editing, setEditing] = useState(false)
const dispatch = useDispatch()
const onEditSubmit = (isOk: boolean) => {
setEditing(false)
if (isOk) {
dispatch(fetchLoginInfo())
}
}
return (
<div className={classes.root}>
<Card className={classes.card}>
<CardActionArea>
<CardContent>
<Typography gutterBottom={true} variant="h6" component="h6" className={classes.title}>
{me.fullname}
</Typography>
<Typography component="p">
....
</Typography>
<Typography gutterBottom={true} variant="subtitle1" component="h6" className={classes.title} >
</Typography>
<Typography component="p">
{me.fullname}
</Typography>
<Typography gutterBottom={true} variant="subtitle1" component="h6" className={classes.title} >
/
</Typography>
<Typography component="p">
{me.email}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary" onClick={() => setEditing(true)}></Button>
<Button size="small" color="primary" onClick={() => dispatch(logout())}>退</Button>
</CardActions>
</Card>
{editing && <EditMyAccountDialog handleClose={onEditSubmit} />}
</div>
)
}
export default MyAccountView

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react'
import { List, ListItem, ListItemText, Drawer, makeStyles, Avatar, ListItemAvatar, ListItemSecondaryAction, IconButton, TablePagination, Button } from '@material-ui/core'
import { List, ListItem, ListItemText, Drawer, makeStyles, ListItemSecondaryAction, IconButton, TablePagination, Button } from '@material-ui/core'
import { ENTITY_TYPE, TablePaginationProps } from 'utils/consts'
import RepositoryService from '../../relatives/services/Repository'
import DateUtility from 'utils/DateUtility'
@ -102,11 +102,6 @@ function HistoryLogDrawer({ entityId, entityType, open, onClose }:
<List className={classes.list}>
{result.rows.map(row => (
<ListItem key={row.id}>
<ListItemAvatar>
<Avatar>
<img alt={String(row.user.empId)} src={`https://work.alibaba-inc.com/photo/${row.user.empId}.40x40.jpg`} className="avatar" />
</Avatar>
</ListItemAvatar>
<ListItemText primary={<FormattedRow row={row} />} secondary={`${DateUtility.formatDate(row.createdAt)} by ${row.user.fullname}`} />
{!row.jsonDataIsNull &&
<ListItemSecondaryAction>

@ -18,6 +18,9 @@ import { useDispatch } from 'react-redux'
import { logout } from 'actions/account'
const options = [{
key: 'myAccount',
text: '我的账户',
}, {
key: 'preferences',
text: '偏好设置',
}, {
@ -80,6 +83,8 @@ function AccountButton({ user }: { user: User }) {
dispatch(logout())
} else if (key === 'preferences') {
dispatch(push('/preferences'))
} else if (key === 'myAccount') {
dispatch(push('/account/myAccount'))
}
setOpen(false)
}
@ -106,10 +111,10 @@ function AccountButton({ user }: { user: User }) {
onClick={handleToggle}
ref={anchorRef}
>
<span className={`mr5 ${classes.accountName} guide-3`}>
<span className={`mr1 ${classes.accountName} guide-3`}>
{user.fullname}
<ExpandMoreIcon fontSize="small" style={{ color: '#FFFFFF' }} />
</span>
<ExpandMoreIcon fontSize="small" style={{ color: '#FFFFFF' }} />
</Button>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition={true}>
{({ TransitionProps, placement }) => (

@ -51,12 +51,6 @@ function Repository(props: Props) {
<Link to={`${editor}?id=${repository.id}`}>{repository.name}</Link>
</div>
<div className="desc">{repository.description}</div>
{/* TODO 2.x 成员列表参考 ProductHunt仓库成员不怎么重要暂时不现实 */}
{/* <div className='members'>
{repository.members.map(user =>
<img key={user.id} alt={user.id} title={user.fullname} src={`https://work.alibaba-inc.com/photo/${user.id}.220x220.jpg`} className='avatar' />
)}
</div> */}
<div className="toolbar">
<a
href={`${serve}/app/plugin/${repository.id}`}

@ -6,8 +6,9 @@ import { StoreStateRouterLocationURI, replace, push } from '../family'
import { RootState } from '../actions/types'
import { showMessage, MSG_TYPE } from 'actions/common'
import { THEME_TEMPLATE_KEY } from 'components/account/ThemeChangeOverlay'
import { CHANGE_THEME, DoUpdateUserSettingAction, updateUserSetting, UPDATE_USER_SETTING_SUCCESS, DO_UPDATE_USER_SETTING } from '../actions/account'
import { CHANGE_THEME, DoUpdateUserSettingAction, updateUserSetting, UPDATE_USER_SETTING_SUCCESS, DO_UPDATE_USER_SETTING, UPDATE_ACCOUNT_SUCCESS, UPDATE_ACCOUNT_FAILURE } from '../actions/account'
import { AnyAction } from 'redux'
import { createCommonDoActionSaga } from './effects/commonSagas'
const relatives = {
reducers: {
@ -267,6 +268,10 @@ const relatives = {
const opAction = yield take(UPDATE_USER_SETTING_SUCCESS)
cb && cb(opAction.payload.isOk)
},
*[AccountAction.DO_UPDATE_ACCOUNT](action: ReturnType<typeof AccountAction.doUpdateAccount>) {
console.log(`saga run`)
yield createCommonDoActionSaga(AccountAction.updateAccount, UPDATE_ACCOUNT_SUCCESS, UPDATE_ACCOUNT_FAILURE)(action)
}
},
listeners: {
'/account': [AccountAction.fetchUserList],

@ -0,0 +1,26 @@
import { IRSAA } from 'redux-api-middleware'
import { put, take } from 'redux-saga/effects'
import { AnyAction } from 'redux'
import { MSG_TYPE, showMessage } from 'actions/common'
export function createCommonDoActionSaga(
fetchActionCreator: (params: object) => { [x: string]: IRSAA },
fetchSuccessActionType: string,
_fetchErrorActionType?: string,
hideSuccessMsg?: boolean,
msg?: string
) {
return function*(action: AnyDoAction) {
const { cb, params } = action.payload
yield put(fetchActionCreator(params) as AnyAction)
const retAction: TCommonDoAction = yield take(fetchSuccessActionType)
if (retAction.payload.isOk) {
if (!hideSuccessMsg || retAction.payload.errMsg) {
yield put(showMessage(`${msg || '操作成功!'}${retAction.payload.errMsg || ''}`, MSG_TYPE.SUCCESS))
}
} else {
yield put(showMessage(`操作失败: ${retAction.payload.errMsg}`, MSG_TYPE.ERROR))
}
cb && cb(retAction.payload.isOk, retAction.payload.isOk ? retAction.payload.data : null)
}
}

@ -15,6 +15,7 @@ import { useSelector } from 'react-redux'
import { RootState } from 'actions/types'
import MySettingsView from './components/account/MySettingsView'
import AboutView from './components/home/AboutView'
import MyAccountView from 'components/account/MyAccountView'
const UserList = lazy(() => import(/* webpackChunkName: "./components/account/UserList" */ './components/account/UserList'))
@ -119,6 +120,7 @@ const Routes = () => {
path="/account"
children={() => (
<Switch>
<Route exact={true} path="/account/myAccount" component={MyAccountView} />
<Route exact={true} path="/account" component={UserList} />
<Route path="/account/users" component={UserList} />
<Route path="/account/login" component={LoginForm} />

@ -27,4 +27,21 @@ declare interface IPager {
declare interface IPagerList<T> {
rows: T[]
count: number
}
}
declare interface AnyDoAction {
type: string
payload: {
cb?: TCB
params: any
}
}
declare type TCommonDoAction = {
type: string
payload: {
isOk: true
data?: any
errMsg?: string
} | TCommonError
}

Loading…
Cancel
Save