Register.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. <template>
  2. <div class="main user-layout-register">
  3. <h3><span>注册</span></h3>
  4. <a-form ref="formRegister" :autoFormCreate="(form)=>{this.form = form}" id="formRegister">
  5. <a-form-item
  6. fieldDecoratorId="username"
  7. :fieldDecoratorOptions="{rules: [{ required: true, message: '用户名不能为空'}, { validator: this.checkUsername }], validateTrigger: ['change', 'blur']}">
  8. <a-input size="large" type="text" autocomplete="false" placeholder="请输入用户名"></a-input>
  9. </a-form-item>
  10. <a-popover placement="rightTop" trigger="click" :visible="state.passwordLevelChecked">
  11. <template slot="content">
  12. <div :style="{ width: '240px' }">
  13. <div :class="['user-register', passwordLevelClass]">强度:<span>{{ passwordLevelName }}</span></div>
  14. <a-progress :percent="state.percent" :showInfo="false" :strokeColor=" passwordLevelColor "/>
  15. <div style="margin-top: 10px;">
  16. <span>请至少输入 8 个字符。请不要使用容易被猜到的密码。</span>
  17. </div>
  18. </div>
  19. </template>
  20. <a-form-item
  21. fieldDecoratorId="password"
  22. :fieldDecoratorOptions="{rules: [{ required: false}, { validator: this.handlePasswordLevel }], validateTrigger: ['change', 'blur']}">
  23. <a-input size="large" type="password" @click="handlePasswordInputClick" autocomplete="false" placeholder="至少8位密码,区分大小写"></a-input>
  24. </a-form-item>
  25. </a-popover>
  26. <a-form-item
  27. fieldDecoratorId="password2"
  28. :fieldDecoratorOptions="{rules: [{ required: true, message: '至少8位密码,区分大小写' }, { validator: this.handlePasswordCheck }], validateTrigger: ['change', 'blur']}">
  29. <a-input size="large" type="password" autocomplete="false" placeholder="确认密码"></a-input>
  30. </a-form-item>
  31. <a-form-item
  32. fieldDecoratorId="email"
  33. :fieldDecoratorOptions="{rules: [{ required: true, type: 'email', message: '请输入正确的邮箱地址' }, { validator: this.handleEmailCheck }], validateTrigger: ['change', 'blur']}">
  34. <a-input size="large" type="text" placeholder="邮箱"></a-input>
  35. </a-form-item>
  36. <a-form-item
  37. fieldDecoratorId="mobile"
  38. :fieldDecoratorOptions="{rules: [{ required: true, pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号' }, { validator: this.handlePhoneCheck } ], validateTrigger: ['change', 'blur'] }">
  39. <a-input size="large" placeholder="11 位手机号">
  40. <a-select slot="addonBefore" size="large" defaultValue="+86">
  41. <a-select-option value="+86">+86</a-select-option>
  42. <a-select-option value="+87">+87</a-select-option>
  43. </a-select>
  44. </a-input>
  45. </a-form-item>
  46. <!--<a-input-group size="large" compact>
  47. <a-select style="width: 20%" size="large" defaultValue="+86">
  48. <a-select-option value="+86">+86</a-select-option>
  49. <a-select-option value="+87">+87</a-select-option>
  50. </a-select>
  51. <a-input style="width: 80%" size="large" placeholder="11 位手机号"></a-input>
  52. </a-input-group>-->
  53. <!--todo 暂无短信服务-->
  54. <!--<a-row :gutter="16">
  55. <a-col class="gutter-row" :span="16">
  56. <a-form-item
  57. fieldDecoratorId="captcha"
  58. :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入验证码' }], validateTrigger: 'blur'}">
  59. <a-input size="large" type="text" placeholder="验证码">
  60. <a-icon slot="prefix" type="mail" :style="{ color: 'rgba(0,0,0,.25)' }"/>
  61. </a-input>
  62. </a-form-item>
  63. </a-col>
  64. <a-col class="gutter-row" :span="8">
  65. <a-button
  66. class="getCaptcha"
  67. size="large"
  68. :disabled="state.smsSendBtn"
  69. @click.stop.prevent="getCaptcha"
  70. v-text="!state.smsSendBtn && '获取验证码'||(state.time+' s')"></a-button>
  71. </a-col>
  72. </a-row>-->
  73. <a-form-item>
  74. <a-button
  75. size="large"
  76. type="primary"
  77. htmlType="submit"
  78. class="register-button"
  79. :loading="registerBtn"
  80. @click.stop.prevent="handleSubmit"
  81. :disabled="registerBtn">注册
  82. </a-button>
  83. <router-link class="login" :to="{ name: 'login' }">使用已有账户登录</router-link>
  84. </a-form-item>
  85. </a-form>
  86. </div>
  87. </template>
  88. <script>
  89. import {mixinDevice} from '@/utils/mixin.js'
  90. import {getSmsCaptcha} from '@/api/login'
  91. import {getAction, postAction} from '@/api/manage'
  92. import {checkOnlyUser} from '@/api/api'
  93. const levelNames = {
  94. 0: '低',
  95. 1: '低',
  96. 2: '中',
  97. 3: '强'
  98. }
  99. const levelClass = {
  100. 0: 'error',
  101. 1: 'error',
  102. 2: 'warning',
  103. 3: 'success'
  104. }
  105. const levelColor = {
  106. 0: '#ff0000',
  107. 1: '#ff0000',
  108. 2: '#ff7e05',
  109. 3: '#52c41a',
  110. }
  111. export default {
  112. name: "Register",
  113. components: {},
  114. mixins: [mixinDevice],
  115. data() {
  116. return {
  117. form: null,
  118. state: {
  119. time: 60,
  120. smsSendBtn: false,
  121. passwordLevel: 0,
  122. passwordLevelChecked: false,
  123. percent: 10,
  124. progressColor: '#FF0000'
  125. },
  126. registerBtn: false
  127. }
  128. },
  129. computed: {
  130. passwordLevelClass() {
  131. return levelClass[this.state.passwordLevel]
  132. },
  133. passwordLevelName() {
  134. return levelNames[this.state.passwordLevel]
  135. },
  136. passwordLevelColor() {
  137. return levelColor[this.state.passwordLevel]
  138. }
  139. },
  140. methods: {
  141. checkUsername(rule, value, callback) {
  142. var params = {
  143. username: value,
  144. };
  145. checkOnlyUser(params).then((res) => {
  146. if (res.success) {
  147. callback()
  148. } else {
  149. callback("用户名已存在!")
  150. }
  151. })
  152. },
  153. handleEmailCheck(rule, value, callback) {
  154. var params = {
  155. email: value,
  156. };
  157. checkOnlyUser(params).then((res) => {
  158. if (res.success) {
  159. callback()
  160. } else {
  161. callback("邮箱已存在!")
  162. }
  163. })
  164. },
  165. handlePasswordLevel(rule, value, callback) {
  166. let level = 0
  167. let reg = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/;
  168. if (!reg.test(value)) {
  169. callback(new Error('密码由8位数字、大小写字母和特殊符号组成!'))
  170. }
  171. // 判断这个字符串中有没有数字
  172. if (/[0-9]/.test(value)) {
  173. level++
  174. }
  175. // 判断字符串中有没有字母
  176. if (/[a-zA-Z]/.test(value)) {
  177. level++
  178. }
  179. // 判断字符串中有没有特殊符号
  180. if (/[^0-9a-zA-Z_]/.test(value)) {
  181. level++
  182. }
  183. this.state.passwordLevel = level
  184. this.state.percent = level * 30
  185. if (level >= 2) {
  186. if (level >= 3) {
  187. this.state.percent = 100
  188. }
  189. callback()
  190. } else {
  191. if (level === 0) {
  192. this.state.percent = 10
  193. }
  194. callback(new Error('密码强度不够'))
  195. }
  196. },
  197. handlePasswordCheck(rule, value, callback) {
  198. let password = this.form.getFieldValue('password')
  199. //console.log('value', value)
  200. if (value === undefined) {
  201. callback(new Error('请输入密码'))
  202. }
  203. if (value && password && value.trim() !== password.trim()) {
  204. callback(new Error('两次密码不一致'))
  205. }
  206. callback()
  207. },
  208. handlePhoneCheck(rule, value, callback) {
  209. var params = {
  210. phone: value,
  211. };
  212. checkOnlyUser(params).then((res) => {
  213. if (res.success) {
  214. callback()
  215. } else {
  216. callback("手机号已存在!")
  217. }
  218. })
  219. },
  220. handlePasswordInputClick() {
  221. if (!this.isMobile()) {
  222. this.state.passwordLevelChecked = true
  223. return;
  224. }
  225. this.state.passwordLevelChecked = false
  226. },
  227. handleSubmit() {
  228. this.form.validateFields((err, values) => {
  229. if (!err) {
  230. var register = {
  231. username: values.username,
  232. password: values.password,
  233. email: values.email,
  234. phone: values.mobile,
  235. smscode: values.captcha
  236. };
  237. postAction("/sys/user/register", register).then((res) => {
  238. if (!res.success) {
  239. this.registerFailed(res.message)
  240. } else {
  241. this.$router.push({name: 'registerResult', params: {...values}})
  242. }
  243. })
  244. }
  245. })
  246. },
  247. getCaptcha(e) {
  248. e.preventDefault()
  249. let that = this
  250. this.form.validateFields(['mobile'], {force: true}, (err, values) => {
  251. if (!err) {
  252. this.state.smsSendBtn = true;
  253. let interval = window.setInterval(() => {
  254. if (that.state.time-- <= 0) {
  255. that.state.time = 60;
  256. that.state.smsSendBtn = false;
  257. window.clearInterval(interval);
  258. }
  259. }, 1000);
  260. const hide = this.$message.loading('验证码发送中..', 0);
  261. const params = {
  262. mobile: values.mobile,
  263. smsmode: "1"
  264. };
  265. postAction("/sys/sms", params).then((res) => {
  266. if (!res.success) {
  267. this.registerFailed(res.message);
  268. setTimeout(hide, 0);
  269. }
  270. setTimeout(hide, 500);
  271. }).catch(err => {
  272. setTimeout(hide, 1);
  273. clearInterval(interval);
  274. that.state.time = 60;
  275. that.state.smsSendBtn = false;
  276. this.requestFailed(err);
  277. });
  278. }
  279. }
  280. );
  281. },
  282. registerFailed(message) {
  283. this.$notification['error']({
  284. message: "注册失败",
  285. description: message,
  286. duration: 2,
  287. });
  288. },
  289. requestFailed(err) {
  290. this.$notification['error']({
  291. message: '错误',
  292. description: ((err.response || {}).data || {}).message || "请求出现错误,请稍后再试",
  293. duration: 4,
  294. });
  295. this.registerBtn = false;
  296. },
  297. },
  298. watch: {
  299. 'state.passwordLevel'(val) {
  300. console.log(val)
  301. }
  302. }
  303. }
  304. </script>
  305. <style lang="less">
  306. .user-register {
  307. &.error {
  308. color: #ff0000;
  309. }
  310. &.warning {
  311. color: #ff7e05;
  312. }
  313. &.success {
  314. color: #52c41a;
  315. }
  316. }
  317. .user-layout-register {
  318. .ant-input-group-addon:first-child {
  319. background-color: #fff;
  320. }
  321. }
  322. </style>
  323. <style lang="less" scoped>
  324. .user-layout-register {
  325. & > h3 {
  326. font-size: 16px;
  327. margin-bottom: 20px;
  328. }
  329. .getCaptcha {
  330. display: block;
  331. width: 100%;
  332. height: 40px;
  333. }
  334. .register-button {
  335. width: 50%;
  336. }
  337. .login {
  338. float: right;
  339. line-height: 40px;
  340. }
  341. }
  342. </style>