CheckBindcode(Usermailphone input)
{
var Orgcode_Key = "ewide_Orgcode";
diff --git a/web-react/package.json b/web-react/package.json
index 8f2e44b..3a99c4e 100644
--- a/web-react/package.json
+++ b/web-react/package.json
@@ -20,6 +20,7 @@
"photoswipe": "^4.1.3",
"react": "^17.0.2",
"react-color": "^2.19.3",
+ "react-cropper": "^2.1.8",
"react-dom": "^17.0.2",
"react-json-view": "^1.21.3",
"react-monaco-editor": "^0.43.0",
@@ -44,6 +45,7 @@
"rules": {
"eqeqeq": "off",
"no-unused-vars": "off",
+ "no-sparse-arrays": "off",
"array-callback-return": "off",
"jsx-a11y/anchor-is-valid": "off"
}
diff --git a/web-react/src/assets/style/lib/anchor.less b/web-react/src/assets/style/lib/anchor.less
index 198ee0d..e37e90f 100644
--- a/web-react/src/assets/style/lib/anchor.less
+++ b/web-react/src/assets/style/lib/anchor.less
@@ -9,6 +9,3 @@
border-radius: 0;
background-color: @primary-color;
}
-.ant-anchor-link-active {
- background: linear-gradient(90deg, #fff, transparent);
-}
diff --git a/web-react/src/assets/style/lib/form.less b/web-react/src/assets/style/lib/form.less
index c587a27..4efbe7a 100644
--- a/web-react/src/assets/style/lib/form.less
+++ b/web-react/src/assets/style/lib/form.less
@@ -220,6 +220,23 @@
color: fade(@black, 50%);
}
}
+ &.yo-form--no-border {
+ .ant-form-item {
+ padding: @padding-md 0;
+
+ border-right: 0;
+ border-left: 0;
+ &:first-child {
+ border-top: 0;
+ }
+ &:last-child {
+ border-bottom: 0;
+ }
+ }
+ .yo-form-group {
+ margin-bottom: 0;
+ }
+ }
}
.yo-modal-form {
.ant-modal-body {
diff --git a/web-react/src/common/api/requests/sys/userManage.js b/web-react/src/common/api/requests/sys/userManage.js
index af29f3f..2d9a478 100644
--- a/web-react/src/common/api/requests/sys/userManage.js
+++ b/web-react/src/common/api/requests/sys/userManage.js
@@ -78,12 +78,12 @@ const urls = {
/**
* 发送验证码
*/
- SendCode: ['/sysUser/SendCode', 'post'],
+ sysUserSendCode: ['/sysUser/sendCode', 'post'],
/**
* 绑定/验证
*/
- CheckBindcode: ['/sysUser/CheckBindcode', 'post'],
+ sysUserCheckBindcode: ['/sysUser/checkBindcode', 'post'],
}
diff --git a/web-react/src/components/container/index.jsx b/web-react/src/components/container/index.jsx
index d3c57fb..c2edbdc 100644
--- a/web-react/src/components/container/index.jsx
+++ b/web-react/src/components/container/index.jsx
@@ -1,29 +1,23 @@
import React, { Component } from 'react'
export default class Container extends Component {
-
getMode(mode) {
const c = 'container'
- switch (mode) {
- case 'sm':
- return c + '-sm'
- case 'md':
- return c + '-md'
- case 'fluid':
- return c + '-fluid'
- default:
- return c
+ const modes = ['xxs', 'xs', 'sm', 'md', 'fluid']
+ if (modes.includes(mode)) {
+ return `${c}-${mode}`
}
+ return c
}
render() {
- let className = this.getMode(this.props.mode)
- if (this.props.className) {
- className += ` ${this.props.className}`
+ const { mode, className, children } = this.props
+
+ let containerName = this.getMode(mode)
+ if (className) {
+ containerName = [containerName, className].join(' ')
}
- return (
-
- )
+ return
}
}
diff --git a/web-react/src/components/image/index.jsx b/web-react/src/components/image/index.jsx
index 2b2c6c5..d84dc6a 100644
--- a/web-react/src/components/image/index.jsx
+++ b/web-react/src/components/image/index.jsx
@@ -3,7 +3,7 @@ import { Avatar } from 'antd'
import { isEqual } from 'lodash'
import { PreviewFileBase64 } from 'util/file'
-const getSrc = async (id) => {
+const getSrc = async id => {
if (id) {
const base64 = await PreviewFileBase64(id)
return base64
@@ -12,9 +12,8 @@ const getSrc = async (id) => {
}
export default class Image extends Component {
-
state = {
- src: ''
+ src: '',
}
id = ''
@@ -25,9 +24,9 @@ export default class Image extends Component {
this.setSrc()
}
- shouldComponentUpdate(props) {
+ shouldComponentUpdate(props, state) {
// props变更或state.src变更时进行渲染
- return !isEqual(this.props, props) || !this.state.src
+ return !isEqual(this.props, props) || this.state.src !== state.src
}
componentDidUpdate() {
@@ -46,13 +45,9 @@ export default class Image extends Component {
render() {
if (this.props.type === 'avatar') {
- return (
-
- )
+ return
} else {
- return (
-
- )
+ return
}
}
}
diff --git a/web-react/src/components/index.js b/web-react/src/components/index.js
index b66489e..6ed3ee0 100644
--- a/web-react/src/components/index.js
+++ b/web-react/src/components/index.js
@@ -1,4 +1,4 @@
-export { default as AntIcon } from 'components/ant-icon'
+export { default as AntIcon } from './ant-icon'
export { default as AuthorityView } from './authority-view'
export { default as Auth } from './authorized'
export { default as ColorSelector } from './form/color-selector'
diff --git a/web-react/src/pages/system/account/base.jsx b/web-react/src/pages/system/account/base.jsx
new file mode 100644
index 0000000..7d7348b
--- /dev/null
+++ b/web-react/src/pages/system/account/base.jsx
@@ -0,0 +1,186 @@
+import React, { Component } from 'react'
+import { Button, Card, Col, Descriptions, Modal, Row, Spin, Tooltip, Upload } from 'antd'
+import { AntIcon, Image } from 'components'
+import { Cropper } from 'react-cropper'
+import 'cropperjs/dist/cropper.css'
+import { BlobToFile } from 'util/file'
+
+import './base.less'
+import { api } from 'common/api'
+
+export default class base extends Component {
+ state = {
+ img: true,
+
+ cropperVisible: false,
+ loadingAvatar: false,
+ }
+
+ cropper = React.createRef()
+
+ avatarFile = null
+
+ async onOpenAvatarCropper() {
+ this.setState({ cropperVisible: true })
+ }
+
+ onCloseAvatarCropper() {
+ this.setState({ cropperVisible: false }, () => {
+ setTimeout(() => {
+ const cropper = this.cropper.current && this.cropper.current.cropper
+ if (cropper) {
+ cropper.destroy()
+ }
+ this.avatarFile = null
+ this.setState({ img: true })
+ }, 300)
+ })
+ }
+
+ onUploadAvatar() {
+ this.setState({ loadingAvatar: true })
+ const canvas = this.cropper.current.cropper.getCroppedCanvas()
+ canvas.toBlob(async data => {
+ try {
+ const file = BlobToFile(data, this.avatarFile.name, this.avatarFile.type)
+ const fd = new FormData()
+ fd.append('file', file)
+ const { data: avatar } = await api.sysFileInfoUpload(fd)
+ await api.sysUserUpdateInfo({ avatar })
+ this.onCloseAvatarCropper()
+ this.props.loadData()
+ } finally {
+ this.setState({ loadingAvatar: false })
+ }
+ })
+ }
+
+ render() {
+ const { user } = this.props
+
+ const { img, cropperVisible, loadingAvatar } = this.state
+
+ const cropper = this.cropper.current && this.cropper.current.cropper
+
+ return (
+ <>
+
+
+
+
this.onOpenAvatarCropper()}
+ className="yo-avatar-info--cover"
+ >
+
+
+
+
+
+ {user.name}
+ {user.nickName}
+ {user.account}
+ {user.sex}
+
+ {user.birthday &&
+ (typeof user.birthday === 'string'
+ ? user.birthday
+ : user.birthday.format('YYYY-MM-DD'))}
+
+
+
+ this.onCloseAvatarCropper()}
+ >
+ }>
+
+
+
+
+
+
+
+
+
+
+ {
+ this.avatarFile = file
+ const reader = new FileReader()
+ reader.readAsDataURL(file)
+ reader.onload = () => {
+ this.setState({ img: reader.result })
+ }
+ return false
+ }}
+ showUploadList={false}
+ className="mr-xs"
+ >
+ }>
+ 选择图片
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+ }
+}
diff --git a/web-react/src/pages/system/account/base.less b/web-react/src/pages/system/account/base.less
new file mode 100644
index 0000000..1ee4118
--- /dev/null
+++ b/web-react/src/pages/system/account/base.less
@@ -0,0 +1,51 @@
+@import (reference) '~assets/style/app.less';
+.yo-avatar-info {
+ position: relative;
+
+ overflow: hidden;
+
+ width: 128px;
+ margin: 0 auto;
+
+ border-radius: 50%;
+ &--cover {
+ font-size: @font-size-lg * 2;
+
+ position: absolute;
+ top: 0;
+ left: 0;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ width: 100%;
+ height: 100%;
+
+ cursor: pointer;
+ transition: @animation-duration-slow;
+
+ opacity: 0;
+ color: @white;
+ background-color: fade(@black, 50%);
+ &:hover {
+ opacity: 1;
+ }
+ }
+}
+.yo-avatar-cropper {
+ overflow: hidden;
+
+ border-radius: @border-radius-base;
+ background-color: #ccc;
+}
+.yo-avatar-preview {
+ overflow: hidden;
+
+ width: 200px;
+ height: 200px;
+ margin: 0 auto;
+
+ border-radius: 50%;
+ background: #ccc;
+}
diff --git a/web-react/src/pages/system/account/index.jsx b/web-react/src/pages/system/account/index.jsx
index 4492f45..4ba41f6 100644
--- a/web-react/src/pages/system/account/index.jsx
+++ b/web-react/src/pages/system/account/index.jsx
@@ -1,41 +1,113 @@
import React, { Component } from 'react'
-import { Anchor, Form, Input, InputNumber, Spin } from 'antd'
-import { AntIcon, Container, IconSelector } from 'components'
-import { cloneDeep } from 'lodash'
-import Safety from './setting/satety/index'
+import ReactDOM from 'react-dom'
+import { Anchor, Card, Col, Row, Spin } from 'antd'
+import { AntIcon, Container } from 'components'
+import moment from 'moment'
+import store from 'store'
+import { api } from 'common/api'
+
+import Base from './base'
import Info from './setting/info'
-import nav from 'store/reducer/nav'
+import Safety from './setting/satety'
+
+const { getState, dispatch, subscribe } = store
+
+const navs = [
+ { title: '基本信息', component: Info },
+ { title: '安全设置', component: Safety },
+]
export default class index extends Component {
- state = {}
+ state = {
+ loading: false,
+ user: getState('user'),
+ }
+
+ container = window
+
+ constructor(props) {
+ super(props)
+
+ this.unsubscribe = subscribe('user', user => {
+ this.setState({ user })
+ })
+ }
+
+ componentDidMount() {
+ this.loadData()
+ }
+
+ componentWillUnmount() {
+ this.unsubscribe()
+ }
+
+ loadData = async () => {
+ this.setState({ loading: true })
+ try {
+ const { data } = await api.getLoginUser()
+ if (data.birthday) {
+ data.birthday = moment(data.birthday)
+ }
+ dispatch({
+ type: 'SET_USER_ACCOUNT',
+ user: data,
+ })
+ } finally {
+ this.setState({ loading: false })
+ }
+ }
+
+ setContainer = container => {
+ this.container = (ReactDOM.findDOMNode(container) || {}).parentNode
+ }
render() {
- // let navs = [
- // {
- // title: '我的信息',
- // component: require('./setting/info'),
- // },
- // {
- // title: '安全设置',
- // component: require('./setting/satety'),
- // },
- // ]
+ const { loadData } = this
+
+ const { loading, user } = this.state
- // return (
- //
- //
- // {navs.map(item => {
- // return
- // })}
- //
- //
- //
- // )
return (
-
-
-
-
+ } ref={this.setContainer}>
+
+
+
+ this.container}
+ offsetTop={24}
+ targetOffset={100}
+ wrapperStyle={{ backgroundColor: 'transparent' }}
+ onClick={e => e.preventDefault()}
+ >
+ {navs.map((item, i) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+ {navs.map((item, i) => (
+
+ ))}
+
+
+
+
+
+
)
}
}
diff --git a/web-react/src/pages/system/account/setting/info.jsx b/web-react/src/pages/system/account/setting/info.jsx
index 211d2e1..8af5300 100644
--- a/web-react/src/pages/system/account/setting/info.jsx
+++ b/web-react/src/pages/system/account/setting/info.jsx
@@ -1,127 +1,87 @@
import React, { Component } from 'react'
-import { Button, DatePicker, Form, Input, message, Radio, Spin } from 'antd'
+import { Button, DatePicker, Form, Input, message as Message, Radio } from 'antd'
+import { AntIcon } from 'components'
import { api } from 'common/api'
-import { cloneDeep } from 'lodash'
-import { AntIcon, Container, IconSelector, Image } from 'components'
-import store from 'store'
import moment from 'moment'
-const { getState } = store
-
export default class index extends Component {
state = {
- info: getState('user'),
saving: false,
- loading: false,
}
+
form = React.createRef()
+
componentDidMount() {
- this.setState({
- loading: true,
- })
- api.getLoginUser()
- .then(({ data }) => {
- delete data.apps
- delete data.menus
- this.setState({
- info: data,
- })
- let birthday = data.birthday
- birthday = moment(birthday)
- data = {
- ...data,
- birthday: birthday,
- }
- this.form.current.setFieldsValue(data)
- })
- .finally(() => {
- this.setState({
- loading: false,
- })
- })
+ const { user } = this.props
+ if (user.birthday) {
+ user.birthday = moment(user.birthday)
+ }
+ this.form.current.setFieldsValue(user)
}
- onSvaeInfo(data) {
- this.setState({
- saving: true,
- })
- let { birthday } = data.current.getFieldsValue()
- let { nickName } = data.current.getFieldsValue()
- let { sex } = data.current.getFieldsValue()
- let { tel } = data.current.getFieldsValue()
- api.sysUserUpdateInfo({
- nickName: nickName,
- birthday: birthday,
- sex: sex,
- tel: tel,
- }).then(() => {
- message.success('更新个人信息成功')
- this.setState({
- saving: false,
- })
- })
+
+ async onSvaeInfo() {
+ this.setState({ saving: true })
+ try {
+ await api.sysUserUpdateInfo(this.form.current.getFieldsValue())
+ await this.props.loadData()
+ Message.success('更新个人信息成功')
+ } finally {
+ this.setState({ saving: false })
+ }
}
onAvatarStart() {}
render() {
- const { info } = this.state
+ const { user } = this.props
+
+ const { saving } = this.state
+
return (
-
- }>
-
-
-
+ >
)
}
}
diff --git a/web-react/src/pages/system/account/setting/satety/index.jsx b/web-react/src/pages/system/account/setting/satety/index.jsx
index df20c83..e6ab368 100644
--- a/web-react/src/pages/system/account/setting/satety/index.jsx
+++ b/web-react/src/pages/system/account/setting/satety/index.jsx
@@ -1,179 +1,126 @@
import React, { Component } from 'react'
-import { Button, DatePicker, Form, Input, List, message as Message, Spin } from 'antd'
+import { List } from 'antd'
import { api } from 'common/api'
-import { cloneDeep } from 'lodash'
-import { AntIcon, Container, IconSelector, Image, ModalForm } from 'components'
-import store from 'store'
-import moment from 'moment'
-import Item from 'antd/lib/list/Item'
+import { AntIcon, ModalForm, QueryTableActions } from 'components'
import PasswordForm from './password'
+
import Mail from './mail'
import Phone from './phone'
-const { getState } = store
+
const apiAction = {
- update: api.sysUserUpdatePwd,
+ updatePwd: api.sysUserUpdatePwd,
}
export default class form extends Component {
- state = {
- saving: false,
- info: [],
- loading: true,
- }
- form = React.createRef()
- // 新增窗口实例
- updateForm = React.createRef()
- MailForm = React.createRef()
- PhoneForm = React.createRef()
- /**
- * 对表格上的操作进行统一处理
- * [异步]
- * @param {*} action
- * @param {*} successMessage
- */
- async onAction(action, successMessage) {
- const { onLoading, onLoaded, onReloadData } = this.table.current
- onLoading()
- try {
- if (action) {
- await action
- }
- if (successMessage) {
- Message.success(successMessage)
- }
- onReloadData()
- } catch {
- onLoaded()
- }
+ updatePwdForm = React.createRef()
+ mailForm = React.createRef()
+ mhoneForm = React.createRef()
+
+ onOpen(modal) {
+ modal.current.open()
}
- /**
- * 打开新增/编辑弹窗
- * @param {*} modal
- * @param {*} record
- */
- onOpen(modal, record) {
- modal.current.open({
- record,
- })
- }
-
- componentDidMount() {
- api.getLoginUser().then(({ data }) => {
- this.setState({
- loading: true,
- })
- let index = []
- //密码
- index.push({
- title: '登录密码',
- description:
- '安全性高的密码可以使帐号更安全。建议您定期更换密码,设置一个包含字母,符号或数字中至少两项且长度超过6位的密码。',
- extra: (
-
- 当前密码强度为:
- {
- [
- 弱,
- 中,
- 强,
- ][data.securityLevel - 1]
- }
-
- ),
- done: true,
- action: () => {
- this.onOpen(this.updateForm)
- },
- })
- //手机
- index.push({
- title: '手机绑定(发送验证码到手机,未实现)',
- description: (
-
- 手机号可以直接用于登录、找回密码等。
- {data.phone && (
-
- 您已绑定了手机{data.phone}
-
- )}
-
- ),
- done: !!data.phone,
- action: () => {
- this.onOpen(this.PhoneForm)
- },
- })
- //邮箱
- index.push({
- title: '邮箱绑定(发送验证码到邮箱,未实现)',
- description: (
-
- 安全邮箱可以直接用于登录、找回密码等。
- {data.email && (
-
- 您已绑定了邮箱{data.email}
-
- )}
-
- ),
- done: !!data.email,
- action: () => {
- this.onOpen(this.MailForm)
- },
- })
- this.setState({
- info: index,
- loading: false,
- })
- })
- }
render() {
+ const { user, loadData } = this.props
+
+ const index = []
+ //密码
+ index.push({
+ title: '登录密码',
+ description:
+ '安全性高的密码可以使帐号更安全。建议您定期更换密码,设置一个包含字母,符号或数字中至少两项且长度超过6位的密码。',
+ // extra: (
+ //
+ // 当前密码强度为:
+ // {
+ // [
+ // 弱,
+ // 中,
+ // 强,
+ // ][user.securityLevel - 1]
+ // }
+ //
+ // ),
+ done: true,
+ action: () => {
+ this.onOpen(this.updatePwdForm)
+ },
+ })
+ //手机
+ index.push({
+ title: '手机绑定',
+ description: (
+
+ 手机号可以直接用于登录、找回密码等。
+ {user.phone && (
+ <>
+ 您已绑定了手机{user.phone}
+ >
+ )}
+
+ ),
+ done: !!user.phone,
+ action: () => {
+ this.onOpen(this.mhoneForm)
+ },
+ })
+ //邮箱
+ index.push({
+ title: '邮箱绑定',
+ description: (
+
+ 安全邮箱可以直接用于登录、找回密码等。
+ {user.email && (
+ <>
+ 您已绑定了邮箱{user.email}
+ >
+ )}
+
+ ),
+ done: !!user.email,
+ action: () => {
+ this.onOpen(this.mailForm)
+ },
+ })
+
return (
-
- }>
-
-
安全设置
-
- (
-
- {item.done == true ? (
- <>
-
+ <>
+ (
+
+
已设置
-
- 修改
-
- >
+ 修改
+
) : (
- <>
-
+
+
未设置
-
- 设置
-
- >
- )}
-
-
- )}
- />
-
-
-
-
-
-
-
-
+ 设置
+
+ ),
+ ]}
+ >
+
+
+ )}
+ />
+
+
+
+
+
+ >
)
}
}
diff --git a/web-react/src/pages/system/account/setting/satety/mail.jsx b/web-react/src/pages/system/account/setting/satety/mail.jsx
index e391cc0..4a8467a 100644
--- a/web-react/src/pages/system/account/setting/satety/mail.jsx
+++ b/web-react/src/pages/system/account/setting/satety/mail.jsx
@@ -1,454 +1,376 @@
import React, { Component } from 'react'
-import {
- Form,
- Input,
- InputNumber,
- Modal,
- Spin,
- Steps,
- Button,
- Row,
- Col,
- message,
- Select,
-} from 'antd'
-import { AntIcon, Container, IconSelector } from 'components'
-import { cloneDeep, indexOf } from 'lodash'
+import { Form, Input, Modal, Spin, Steps, Button, Row, Col, message as Message, Select } from 'antd'
+import { AntIcon } from 'components'
import { api } from 'common/api'
import { COUNT_DWON_KEY } from 'common/storage'
-import { Option } from 'antd/lib/mentions'
-import { set } from 'nprogress'
-import { getKeyThenIncreaseKey } from 'antd/lib/message'
+import store from 'store'
+import { cloneDeep } from 'lodash'
-const initialValues = {
- orgcode: '',
- target: '',
- code: '',
- type: null,
+const { getState } = store
+
+const steps = [
+ {
+ title: '验证',
+ },
+ {
+ title: '绑定',
+ },
+]
+
+const reg = /^([a-zA-Z]|[0-9])(\w|)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/
+
+const initState = {
+ visible: false,
+ loading: false,
+
+ // 可用于验证的类型
+ types: [],
+ // 当前步骤
+ currentStep: 0,
+
+ nextDisabled: true,
+ // 正在发送验证码
+ sendingCode: false,
+ // 冷却时间
+ countDown: 0,
}
-var tempcode = ''
-const { Step } = Steps
+
export default class form extends Component {
- state = {
- buttondisabled: true,
- visible: false,
- loading: false,
- codeLoading: false,
- current: 0,
- countdown: 0,
- sendOrNo: true,
- type: [],
- }
+ state = cloneDeep(initState)
+
form = React.createRef()
- //发送验证码
- sendcode(data) {
- this.setState({
- codeLoading: true,
- })
- var reg = /^([a-zA-Z]|[0-9])(\w|)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/
- let { target } = data.current.getFieldsValue()
- let { type } = data.current.getFieldsValue()
- let { code } = data.current.getFieldsValue()
- let { orgcode } = data.current.getFieldsValue()
- if (!reg.test(target) && type != '1' && type != '2') {
- message.warn('请输入正确的邮箱')
- this.setState({
- codeLoading: true,
+
+ orgCode = ''
+
+ //打开窗口
+ open = () => {
+ this.setState({ visible: true })
+
+ this.showCountDown()
+
+ const data = getState('user')
+ const types = []
+ data.phone &&
+ types.push({
+ title: `使用手机号${data.phone}进行验证`,
+ value: 1,
})
- return
- }
- api.SendCode({
- target: target,
- type: type,
- code: code,
- orgcode: orgcode,
- })
- .then(res => {
- if (res.success) {
- this.addTime()
- this.showcountdown()
- }
- })
- .finally(() => {
- this.setState({
- codeLoading: false,
- })
+ data.email &&
+ types.push({
+ title: `使用邮箱${data.email}进行验证`,
+ value: 2,
})
+
+ this.setState({ types })
}
- //进入下一步
- next(data) {
- this.setState({
- loading: true,
- })
- let { target } = data.current.getFieldsValue()
- let { type } = data.current.getFieldsValue()
- let { code } = data.current.getFieldsValue()
- let { orgcode } = data.current.getFieldsValue()
- tempcode = data.current.getFieldsValue()
- let form = {
- target: target,
- type: type,
- code: code,
- orgcode: orgcode,
- }
- api.CheckBindcode(form)
- .then(res => {
- if (res.data) {
- window.localStorage.removeItem(COUNT_DWON_KEY)
- let current = this.state.current + 1
- this.setState({
- form: {
- ...form,
- type: null,
- },
- buttondisabled: true,
- current: current,
- })
- }
- })
- .finally(() => {
- this.setState({
- loading: false,
- })
- })
+
+ close() {
+ this.setState(cloneDeep(initState))
}
+
/**
* 将倒计时添加入到本地
*/
addTime() {
- const now = Date.now()
- var date = now + 60 * 1000 + 500
- window.localStorage.setItem(COUNT_DWON_KEY, date)
+ const now = Date.now() + 60 * 1000
+ window.localStorage.setItem(COUNT_DWON_KEY, now)
}
/**
* 显示倒计时
*/
- showcountdown() {
- let _this = this
- var Furdate = window.localStorage.getItem(COUNT_DWON_KEY)
- var nowdate = new Date().getTime()
- if (Furdate >= nowdate) {
+ showCountDown() {
+ const surplusTime = window.localStorage.getItem(COUNT_DWON_KEY)
+ const nowTime = Date.now()
+ if (surplusTime >= nowTime) {
this.setState({
- sendOrNo: false,
- countdown: parseInt((Furdate - nowdate) / 1000),
+ countDown: parseInt((surplusTime - nowTime) / 1000),
})
setTimeout(() => {
- _this.showcountdown()
+ this.showCountDown()
}, 1000)
} else {
- this.setState({
- sendOrNo: true,
- })
+ this.setState({ countDown: 0 })
}
}
- //打开窗口
- open = (data = {}) => {
- this.setState({ visible: true, loading: true })
- api.getLoginUser().then(({ data }) => {
- let index = []
- data.phone &&
- index.push({
- Title: '使用手机号' + data.phone + '进行验证 ',
- Value: 1,
- })
- data.email &&
- index.push({
- Title: '使用邮箱' + data.email + '进行验证',
- Value: 2,
- })
+
+ //发送验证码
+ async onSendCode() {
+ const form = this.form.current
+
+ const valid = await form.validateFields()
+ if (!valid) {
+ return
+ }
+
+ this.setState({ sendingCode: true })
+
+ const data = form.getFieldsValue()
+ try {
+ await api.sysUserSendCode(data)
+ const typeName = data.type ? [, '手机', '邮箱'][data.type] : '手机'
+ Message.success(`已发送验证码到${typeName},请注意查收`)
+ this.addTime()
+ this.showCountDown()
+ } finally {
+ this.setState({ sendingCode: false })
+ }
+ }
+
+ // 下一步
+ async onNext() {
+ this.setState({ loading: true })
+ const data = this.form.current.getFieldsValue()
+ this.orgCode = data.orgCode
+
+ try {
+ await api.sysUserCheckBindcode(data)
+ window.localStorage.removeItem(COUNT_DWON_KEY)
this.setState({
- type: index,
+ nextDisabled: true,
+ currentStep: this.state.currentStep + 1,
})
- if (index.length > 0) {
- this.form.current.setFieldsValue({
- type: index[0].Value,
- })
- }
+ } finally {
this.setState({ loading: false })
- })
- }
- // 前一步
- prev() {
- window.localStorage.removeItem(COUNT_DWON_KEY)
- let current = this.state.current - 1
- this.setState({
- current: current,
- })
- }
- //完成
- complete(data) {
- let { target } = data.current.getFieldsValue()
- let { code } = data.current.getFieldsValue()
- let { orgcode } = tempcode
- api.CheckBindcode({
- target: target,
- type: null,
- code: code,
- orgcode: orgcode,
- }).then(res => {
- if (res.data) {
- window.localStorage.removeItem(COUNT_DWON_KEY)
- message.success('改绑完成')
- this.onResetFields()
- }
- })
- }
- onResetFields() {
- setTimeout(() => {
- this.setState({ visible: false })
- this.setState({ current: 0 })
- //window.localStorage.removeItem(COUNT_DWON_KEY)
- /** 在这里可以初始化当前组件中其他属性 */
- /* ... */
- }, 300)
- }
- render() {
- let steps = [
- {
- title: '验证',
- },
- {
- title: '绑定',
- },
- ]
- const close = () => {
- this.setState({
- visible: false,
- current: 0,
- })
}
+ }
+
+ // 上一步
+ onPrev() {
+ window.localStorage.removeItem(COUNT_DWON_KEY)
+ this.setState({
+ currentStep: this.state.currentStep - 1,
+ })
+ }
+
+ //完成
+ async onComplete() {
+ this.setState({ loading: true })
+ try {
+ await api.sysUserCheckBindcode({
+ ...this.form.current.getFieldsValue(),
+ orgCode: this.orgCode,
+ })
+ await this.props.loadData()
+ window.localStorage.removeItem(COUNT_DWON_KEY)
+ Message.success('绑定邮箱成功')
+ this.close()
+ } finally {
+ this.setState({ loading: false })
+ }
+ }
+
+ renderForm() {
+ const { nextDisabled, sendingCode, countDown } = this.state
+
return (
-
-
+
-
+ ) : (
+ this.onSendCode()}
+ loading={sendingCode}
+ >
+ 发送验证码
+
+ )}
+
+
+
+ >
+ )}
+ {currentStep === 1 && (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ {countDown ? (
+
+ {countDown}
+ 秒后重新发送
+
+ ) : (
+ this.onSendCode()}
+ loading={sendingCode}
+ >
+ 发送验证码
+
+ )}
+
+
+
+ >
+ )}
+
+
+ {currentStep === 0 && (
+ <>
+ this.onNext(this.form)}
+ type="primary"
+ disabled={this.state.nextDisabled}
+ >
+ 下一步,绑定
+
+ >
+ )}
+ {currentStep === 1 && (
+ <>
+ this.onPrev()} className="mr-sm">
+ 上一步,验证
+
+ this.onComplete()}
+ type="primary"
+ >
+ 完成
+
+ >
+ )}
+
+
+ )
+ }
+
+ render() {
+ const { visible, loading, types } = this.state
+
+ return (
+ this.close()}
+ visible={visible}
+ className="yo-modal-form"
+ title="绑定邮箱"
+ >
+ }>
+
+ {types.length ? this.renderStepForm() : this.renderForm()}
+
+
+
)
}
}
diff --git a/web-react/src/pages/system/account/setting/satety/password.jsx b/web-react/src/pages/system/account/setting/satety/password.jsx
index 0616fc1..6e0c9db 100644
--- a/web-react/src/pages/system/account/setting/satety/password.jsx
+++ b/web-react/src/pages/system/account/setting/satety/password.jsx
@@ -1,15 +1,9 @@
import React, { Component } from 'react'
-import { Form, Input, InputNumber, Spin } from 'antd'
-import { AntIcon, IconSelector } from 'components'
-import { cloneDeep } from 'lodash'
+import { Form, Input } from 'antd'
-const initialValues = {
- sort: 100,
-}
export default class form extends Component {
state = {
// 加载状态
- loading: true,
exist: false,
}
// 表单实例
@@ -31,25 +25,7 @@ export default class form extends Component {
* [异步,必要]
* @param {*} params
*/
- async fillData(params) {
- this.record = cloneDeep(params.record)
- //#region 从后端转换成前段所需格式
- const exist = !!params.record
- this.setState({
- exist,
- })
-
- this.record = {
- ...this.record,
- }
- //#endregion
-
- this.form.current.setFieldsValue(this.record)
-
- this.setState({
- loading: false,
- })
- }
+ async fillData() {}
/**
* 获取数据
@@ -63,9 +39,6 @@ export default class form extends Component {
const valid = await form.validateFields()
if (valid) {
const postData = form.getFieldsValue()
- if (this.record) {
- postData.id = this.record.id
- }
//#region 从前段转换后端所需格式
//#endregion
return postData
@@ -75,32 +48,39 @@ export default class form extends Component {
render() {
return (
+
+
+
+
+
+ ({
+ validator(_, value) {
+ if (!value || getFieldValue('newPassword') === value) {
+ return Promise.resolve()
+ }
+ return Promise.reject(new Error('确认新密码不匹配'))
+ },
+ }),
+ ]}
+ name="confirm"
+ >
+
+
+
)
}
diff --git a/web-react/src/pages/system/account/setting/satety/phone.jsx b/web-react/src/pages/system/account/setting/satety/phone.jsx
index d5ebb56..f0bb4e9 100644
--- a/web-react/src/pages/system/account/setting/satety/phone.jsx
+++ b/web-react/src/pages/system/account/setting/satety/phone.jsx
@@ -1,455 +1,376 @@
import React, { Component } from 'react'
-import {
- Form,
- Input,
- InputNumber,
- Modal,
- Spin,
- Steps,
- Button,
- Row,
- Col,
- message,
- Select,
-} from 'antd'
-import { AntIcon, Container, IconSelector } from 'components'
-import { cloneDeep, indexOf } from 'lodash'
+import { Form, Input, Modal, Spin, Steps, Button, Row, Col, message as Message, Select } from 'antd'
+import { AntIcon } from 'components'
import { api } from 'common/api'
import { COUNT_DWON_KEY } from 'common/storage'
-import { Option } from 'antd/lib/mentions'
-import { set } from 'nprogress'
-import { getKeyThenIncreaseKey } from 'antd/lib/message'
+import store from 'store'
+import { cloneDeep } from 'lodash'
-const initialValues = {
- orgcode: '',
- target: '',
- code: '',
- type: null,
+const { getState } = store
+
+const steps = [
+ {
+ title: '验证',
+ },
+ {
+ title: '绑定',
+ },
+]
+
+const reg = /^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$/
+
+const initState = {
+ visible: false,
+ loading: false,
+
+ // 可用于验证的类型
+ types: [],
+ // 当前步骤
+ currentStep: 0,
+
+ nextDisabled: true,
+ // 正在发送验证码
+ sendingCode: false,
+ // 冷却时间
+ countDown: 0,
}
-var tempcode = ''
-const { Step } = Steps
+
export default class form extends Component {
- state = {
- buttondisabled: true,
- visible: false,
- loading: false,
- codeLoading: false,
- current: 0,
- countdown: 0,
- sendOrNo: true,
- type: [],
- }
+ state = cloneDeep(initState)
+
form = React.createRef()
- //发送验证码
- sendcode(data) {
- this.setState({
- codeLoading: true,
- })
- var reg =
- /^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$/
- let { target } = data.current.getFieldsValue()
- let { type } = data.current.getFieldsValue()
- let { code } = data.current.getFieldsValue()
- let { orgcode } = data.current.getFieldsValue()
- if (!reg.test(target) && type != '1' && type != '2') {
- message.warn('请输入正确的手机号码')
- this.setState({
- codeLoading: true,
+
+ orgCode = ''
+
+ //打开窗口
+ open = () => {
+ this.setState({ visible: true })
+
+ this.showCountDown()
+
+ const data = getState('user')
+ const types = []
+ data.phone &&
+ types.push({
+ title: `使用手机号${data.phone}进行验证`,
+ value: 1,
})
- return
- }
- api.SendCode({
- target: target,
- type: type,
- code: code,
- orgcode: orgcode,
- })
- .then(res => {
- if (res.success) {
- this.addTime()
- this.showcountdown()
- }
- })
- .finally(() => {
- this.setState({
- codeLoading: false,
- })
+ data.email &&
+ types.push({
+ title: `使用邮箱${data.email}进行验证`,
+ value: 2,
})
+
+ this.setState({ types })
}
- //进入下一步
- next(data) {
- this.setState({
- loading: true,
- })
- let { target } = data.current.getFieldsValue()
- let { type } = data.current.getFieldsValue()
- let { code } = data.current.getFieldsValue()
- let { orgcode } = data.current.getFieldsValue()
- tempcode = data.current.getFieldsValue()
- let form = {
- target: target,
- type: type,
- code: code,
- orgcode: orgcode,
- }
- api.CheckBindcode(form)
- .then(res => {
- if (res.data) {
- window.localStorage.removeItem(COUNT_DWON_KEY)
- let current = this.state.current + 1
- this.setState({
- form: {
- ...form,
- type: null,
- },
- buttondisabled: true,
- current: current,
- })
- }
- })
- .finally(() => {
- this.setState({
- loading: false,
- })
- })
+
+ close() {
+ this.setState(cloneDeep(initState))
}
+
/**
* 将倒计时添加入到本地
*/
addTime() {
- const now = Date.now()
- var date = now + 60 * 1000 + 500
- window.localStorage.setItem(COUNT_DWON_KEY, date)
+ const now = Date.now() + 60 * 1000
+ window.localStorage.setItem(COUNT_DWON_KEY, now)
}
/**
* 显示倒计时
*/
- showcountdown() {
- let _this = this
- var Furdate = window.localStorage.getItem(COUNT_DWON_KEY)
- var nowdate = new Date().getTime()
- if (Furdate >= nowdate) {
+ showCountDown() {
+ const surplusTime = window.localStorage.getItem(COUNT_DWON_KEY)
+ const nowTime = Date.now()
+ if (surplusTime >= nowTime) {
this.setState({
- sendOrNo: false,
- countdown: parseInt((Furdate - nowdate) / 1000),
+ countDown: parseInt((surplusTime - nowTime) / 1000),
})
setTimeout(() => {
- _this.showcountdown()
+ this.showCountDown()
}, 1000)
} else {
- this.setState({
- sendOrNo: true,
- })
+ this.setState({ countDown: 0 })
}
}
- //打开窗口
- open = (data = {}) => {
- this.setState({ visible: true, loading: true })
- api.getLoginUser().then(({ data }) => {
- let index = []
- data.phone &&
- index.push({
- Title: '使用手机号' + data.phone + '进行验证 ',
- Value: 1,
- })
- data.email &&
- index.push({
- Title: '使用邮箱' + data.email + '进行验证',
- Value: 2,
- })
+
+ //发送验证码
+ async onSendCode() {
+ const form = this.form.current
+
+ const valid = await form.validateFields()
+ if (!valid) {
+ return
+ }
+
+ this.setState({ sendingCode: true })
+
+ const data = form.getFieldsValue()
+ try {
+ await api.sysUserSendCode(data)
+ const typeName = data.type ? [, '手机', '邮箱'][data.type] : '手机'
+ Message.success(`已发送验证码到${typeName},请注意查收`)
+ this.addTime()
+ this.showCountDown()
+ } finally {
+ this.setState({ sendingCode: false })
+ }
+ }
+
+ // 下一步
+ async onNext() {
+ this.setState({ loading: true })
+ const data = this.form.current.getFieldsValue()
+ this.orgCode = data.orgCode
+
+ try {
+ await api.sysUserCheckBindcode(data)
+ window.localStorage.removeItem(COUNT_DWON_KEY)
this.setState({
- type: index,
+ nextDisabled: true,
+ currentStep: this.state.currentStep + 1,
})
- if (index.length > 0) {
- this.form.current.setFieldsValue({
- type: index[0].Value,
- })
- }
+ } finally {
this.setState({ loading: false })
- })
- }
- // 前一步
- prev() {
- window.localStorage.removeItem(COUNT_DWON_KEY)
- let current = this.state.current - 1
- this.setState({
- current: current,
- })
- }
- //完成
- complete(data) {
- let { target } = data.current.getFieldsValue()
- let { code } = data.current.getFieldsValue()
- let { orgcode } = tempcode
- api.CheckBindcode({
- target: target,
- type: null,
- code: code,
- orgcode: orgcode,
- }).then(res => {
- if (res.data) {
- window.localStorage.removeItem(COUNT_DWON_KEY)
- message.success('改绑完成')
- this.onResetFields()
- }
- })
- }
- onResetFields() {
- setTimeout(() => {
- this.setState({ visible: false })
- this.setState({ current: 0 })
- //window.localStorage.removeItem(COUNT_DWON_KEY)
- /** 在这里可以初始化当前组件中其他属性 */
- /* ... */
- }, 300)
- }
- render() {
- let steps = [
- {
- title: '验证',
- },
- {
- title: '绑定',
- },
- ]
- const close = () => {
- this.setState({
- visible: false,
- current: 0,
- })
}
+ }
+
+ // 上一步
+ onPrev() {
+ window.localStorage.removeItem(COUNT_DWON_KEY)
+ this.setState({
+ currentStep: this.state.currentStep - 1,
+ })
+ }
+
+ //完成
+ async onComplete() {
+ this.setState({ loading: true })
+ try {
+ await api.sysUserCheckBindcode({
+ ...this.form.current.getFieldsValue(),
+ orgCode: this.orgCode,
+ })
+ await this.props.loadData()
+ window.localStorage.removeItem(COUNT_DWON_KEY)
+ Message.success('绑定手机号成功')
+ this.close()
+ } finally {
+ this.setState({ loading: false })
+ }
+ }
+
+ renderForm() {
+ const { nextDisabled, sendingCode, countDown } = this.state
+
return (
-
-
+
-
+ ) : (
+ this.onSendCode()}
+ loading={sendingCode}
+ >
+ 发送验证码
+
+ )}
+
+
+
+ >
+ )}
+ {currentStep === 1 && (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ {countDown ? (
+
+ {countDown}
+ 秒后重新发送
+
+ ) : (
+ this.onSendCode()}
+ loading={sendingCode}
+ >
+ 发送验证码
+
+ )}
+
+
+
+ >
+ )}
+
+
+ {currentStep === 0 && (
+ <>
+ this.onNext(this.form)}
+ type="primary"
+ disabled={this.state.nextDisabled}
+ >
+ 下一步,绑定
+
+ >
+ )}
+ {currentStep === 1 && (
+ <>
+ this.onPrev()} className="mr-sm">
+ 上一步,验证
+
+ this.onComplete()}
+ type="primary"
+ >
+ 完成
+
+ >
+ )}
+
+
+ )
+ }
+
+ render() {
+ const { visible, loading, types } = this.state
+
+ return (
+ this.close()}
+ visible={visible}
+ className="yo-modal-form"
+ title="绑定手机"
+ >
+ }>
+
+ {types.length ? this.renderStepForm() : this.renderForm()}
+
+
+
)
}
}
diff --git a/web-react/src/views/main/_layout/header/user.jsx b/web-react/src/views/main/_layout/header/user.jsx
index 083aafa..d637fb6 100644
--- a/web-react/src/views/main/_layout/header/user.jsx
+++ b/web-react/src/views/main/_layout/header/user.jsx
@@ -94,9 +94,10 @@ class User extends Component {
个人中心
- 其他菜单
- 其他菜单
- 其他菜单
+
+
+ 操作手册
+
this.onLogout()}>
diff --git a/web-react/yarn.lock b/web-react/yarn.lock
index 1bb675f..62e133f 100644
--- a/web-react/yarn.lock
+++ b/web-react/yarn.lock
@@ -3762,6 +3762,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
+cropperjs@^1.5.12:
+ version "1.5.12"
+ resolved "https://registry.nlark.com/cropperjs/download/cropperjs-1.5.12.tgz?cache=0&sync_timestamp=1623485718941&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcropperjs%2Fdownload%2Fcropperjs-1.5.12.tgz#d9c0db2bfb8c0d769d51739e8f916bbc44e10f50"
+ integrity sha1-2cDbK/uMDXadUXOej5FrvEThD1A=
+
cross-fetch@^3.0.4:
version "3.1.4"
resolved "https://registry.npm.taobao.org/cross-fetch/download/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39"
@@ -9686,6 +9691,13 @@ react-color@^2.19.3:
reactcss "^1.2.0"
tinycolor2 "^1.4.1"
+react-cropper@^2.1.8:
+ version "2.1.8"
+ resolved "https://registry.nlark.com/react-cropper/download/react-cropper-2.1.8.tgz?cache=0&sync_timestamp=1624865139834&other_urls=https%3A%2F%2Fregistry.nlark.com%2Freact-cropper%2Fdownload%2Freact-cropper-2.1.8.tgz#bf35a7de65769f8ad357e8ae884e791fe3fe9212"
+ integrity sha1-vzWn3mV2n4rTV+iuiE55H+P+khI=
+ dependencies:
+ cropperjs "^1.5.12"
+
react-dev-utils@^11.0.3:
version "11.0.4"
resolved "https://registry.npm.taobao.org/react-dev-utils/download/react-dev-utils-11.0.4.tgz?cache=0&sync_timestamp=1615231838520&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-dev-utils%2Fdownload%2Freact-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a"