ljw 1 год назад
Родитель
Сommit
d3031ae5d8

+ 9 - 1
src/api/user.js

@@ -79,6 +79,14 @@ export function groupUsers (data) {
79 79
   return request({
80 80
     url: '/user/groupUsers',
81 81
     method: 'post',
82
-    data
82
+    data,
83
+  })
84
+}
85
+
86
+export function register (data) {
87
+  return request({
88
+    url: '/user/register',
89
+    method: 'post',
90
+    data,
83 91
   })
84 92
 }

+ 1 - 1
src/permission.js

@@ -10,7 +10,7 @@ import { T } from '@/utils/i18n'
10 10
 
11 11
 NProgress.configure({ showSpinner: false }) // NProgress Configuration
12 12
 
13
-const whiteList = ['/login']
13
+const whiteList = ['/login', '/register']
14 14
 const routeStore = useRouteStore(pinia)
15 15
 const appStore = useAppStore(pinia)
16 16
 router.beforeEach(async (to, from, next) => {

+ 6 - 1
src/router/index.js

@@ -7,7 +7,12 @@ const constantRoutes = [
7 7
     meta: { title: 'Login' },
8 8
     component: () => import('@/views/login/login.vue'),
9 9
   },
10
-
10
+  {
11
+    path: '/register',
12
+    name: 'Register',
13
+    meta: { title: 'Register' },
14
+    component: () => import('@/views/register/index.vue'),
15
+  },
11 16
   {
12 17
     path: '/404',
13 18
     component: () => import('@/views/error-page/404.vue'),

+ 9 - 0
src/utils/i18n/en.json

@@ -438,5 +438,14 @@
438 438
   },
439 439
   "LastOnlineIp": {
440 440
     "One": "Last Online Ip"
441
+  },
442
+  "ConfirmPassword": {
443
+    "One": "Confirm Password"
444
+  },
445
+  "PasswordNotMatchConfirmPassword": {
446
+    "One": "Password not match Confirm Password"
447
+  },
448
+  "ToLogin": {
449
+    "One": "To Login"
441 450
   }
442 451
 }

+ 9 - 0
src/utils/i18n/ko.json

@@ -424,5 +424,14 @@
424 424
   },
425 425
   "LastOnlineIp": {
426 426
     "One": "마지막 온라인 IP"
427
+  },
428
+  "ConfirmPassword": {
429
+    "One": "비밀번호 확인"
430
+  },
431
+  "PasswordNotMatchConfirmPassword": {
432
+    "One": "비밀번호가 확인 비밀번호와 일치하지 않습니다"
433
+  },
434
+  "ToLogin": {
435
+    "One": "로그인하려면 클릭하십시오"
427 436
   }
428 437
 }

+ 9 - 0
src/utils/i18n/ru.json

@@ -438,6 +438,15 @@
438 438
   },
439 439
   "LastOnlineIp": {
440 440
     "One": "Последний IP онлайн"
441
+  },
442
+  "ConfirmPassword": {
443
+    "One": "Подтвердите пароль"
444
+  },
445
+  "PasswordNotMatchConfirmPassword": {
446
+    "One": "Пароль и подтверждение пароля не совпадают"
447
+  },
448
+  "ToLogin": {
449
+    "One": "Войти"
441 450
   }
442 451
 }
443 452
 

+ 10 - 2
src/utils/i18n/zh_CN.json

@@ -428,8 +428,16 @@
428 428
   "LastOnlineIp": {
429 429
     "One": "最后在线IP"
430 430
   },
431
-  "or login in with" :
432
-  {
431
+  "or login in with": {
433 432
     "One": "或使用以下登陆"
433
+  },
434
+  "ConfirmPassword": {
435
+    "One": "确认密码"
436
+  },
437
+  "PasswordNotMatchConfirmPassword": {
438
+    "One": "密码与确认密码不匹配"
439
+  },
440
+  "ToLogin": {
441
+    "One": "去登录"
434 442
   }
435 443
 }

+ 9 - 1
src/views/login/login.vue

@@ -15,6 +15,7 @@
15 15
 
16 16
         <el-form-item>
17 17
           <el-button @click="login" type="primary" class="login-button">{{ T('Login') }}</el-button>
18
+          <el-button v-if="allowRegister" @click="register" class="login-button">{{ T('Register') }}</el-button>
18 19
         </el-form-item>
19 20
       </el-form>
20 21
 
@@ -103,11 +104,13 @@ const getProviderImage = (provider) => {
103 104
   return providerImageMap[provider] || providerImageMap.default;
104 105
 };
105 106
 
107
+const allowRegister = ref(false)
106 108
 const loadLoginOptions = async () => {
107 109
   try {
108 110
     const res = await loginOptions().catch(_ => false);
109 111
     if(!res || !res.data) return console.error('No valid response received');
110
-    res.data.map(option => (options.push({ name: option }))); // 创建新的对象数组
112
+    res.data.ops.map(option => (options.push({ name: option }))); // 创建新的对象数组
113
+    allowRegister.value = res.data.register
111 114
   } catch (error) {
112 115
     console.error('Error loading login options:', error.message);
113 116
   }
@@ -130,6 +133,9 @@ onMounted(async () => {
130 133
   }
131 134
 });
132 135
 
136
+const register = () => {
137
+  router.push('/register')
138
+}
133 139
 </script>
134 140
 
135 141
 <style scoped lang="scss">
@@ -140,6 +146,7 @@ onMounted(async () => {
140 146
   height: 100vh;
141 147
   background-color: #2d3a4b;
142 148
   padding: 20px;
149
+  box-sizing: border-box;
143 150
 }
144 151
 
145 152
 .login-card {
@@ -169,6 +176,7 @@ h1 {
169 176
   width: 100%;
170 177
   height: 40px;
171 178
   margin-bottom: 20px;
179
+  margin-left: 0;
172 180
 }
173 181
 
174 182
 .divider {

+ 147 - 0
src/views/register/index.vue

@@ -0,0 +1,147 @@
1
+<template>
2
+  <div class="login-container">
3
+    <div class="login-card">
4
+      <img src="@/assets/logo.png" alt="logo" class="login-logo"/>
5
+      <el-form ref="f" :model="form" label-position="top" class="login-form" :rules="rules">
6
+        <el-form-item :label="T('Username')" prop="username">
7
+          <el-input v-model="form.username" class="login-input"></el-input>
8
+        </el-form-item>
9
+
10
+        <el-form-item :label="T('Password')" prop="password">
11
+          <el-input v-model="form.password" type="password" show-password
12
+                    class="login-input"></el-input>
13
+        </el-form-item>
14
+        <el-form-item :label="T('ConfirmPassword')" prop="confirm_password">
15
+          <el-input v-model="form.confirm_password" type="password" @keyup.enter.native="submit" show-password
16
+                    class="login-input"></el-input>
17
+        </el-form-item>
18
+        <el-form-item label="">
19
+          <el-button @click="submit" class="login-button" type="success">{{ T('Submit') }}</el-button>
20
+          <el-button @click="toLogin" class="login-button">{{ T('ToLogin') }}</el-button>
21
+        </el-form-item>
22
+      </el-form>
23
+    </div>
24
+  </div>
25
+</template>
26
+
27
+<script setup>
28
+  import { reactive, ref } from 'vue'
29
+  import { ElMessage } from 'element-plus'
30
+  import { T } from '@/utils/i18n'
31
+  import { useRoute, useRouter } from 'vue-router'
32
+  import { register } from '@/api/user'
33
+  import { useUserStore } from '@/store/user'
34
+
35
+  const router = useRouter()
36
+  const userStore = useUserStore()
37
+  const form = reactive({
38
+    username: '',
39
+    password: '',
40
+    confirm_password: '',
41
+  })
42
+  const rules = {
43
+    username: [
44
+      { required: true, message: T('ParamRequired', { param: T('Username') }), trigger: 'blur' },
45
+    ],
46
+    password: [
47
+      { required: true, message: T('ParamRequired', { param: T('Password') }), trigger: 'blur' },
48
+    ],
49
+    confirm_password: [
50
+      { required: true, message: T('ParamRequired', { param: T('ConfirmPassword') }), trigger: 'blur' },
51
+      {
52
+        validator: (rule, value, callback) => {
53
+          if (value !== form.password) {
54
+            callback(new Error(T('PasswordNotMatchConfirmPassword')))
55
+          } else {
56
+            callback()
57
+          }
58
+        }, trigger: 'blur',
59
+      },
60
+    ],
61
+  }
62
+  const f = ref(null)
63
+  const submit = async () => {
64
+    const v = await f.value.validate().catch(_ => false)
65
+    if (!v) {
66
+      return
67
+    }
68
+    const res = await register(form).catch(_ => false)
69
+    if (!res) {
70
+      return
71
+    }
72
+    userStore.saveUserData(res.data)
73
+    ElMessage.success('Submit')
74
+    router.push('/')
75
+  }
76
+  const toLogin = () => {
77
+    router.push('/login')
78
+
79
+  }
80
+</script>
81
+
82
+<style scoped lang="scss">
83
+.login-container {
84
+  display: flex;
85
+  justify-content: center;
86
+  align-items: center;
87
+  height: 100vh;
88
+  background-color: #2d3a4b;
89
+  padding: 20px;
90
+  box-sizing: border-box;
91
+}
92
+
93
+.login-card {
94
+  width: 360px;
95
+  background-color: #283342;
96
+  padding: 40px;
97
+  border-radius: 8px;
98
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
99
+  text-align: center;
100
+}
101
+
102
+h1 {
103
+  margin-bottom: 20px;
104
+  font-size: 24px;
105
+  font-weight: bold;
106
+}
107
+
108
+.login-form {
109
+  margin-bottom: 20px;
110
+}
111
+
112
+.login-input {
113
+  width: 100%;
114
+}
115
+
116
+.login-button {
117
+  width: 100%;
118
+  height: 40px;
119
+  margin-bottom: 20px;
120
+  margin-top: 20px;
121
+  margin-left: 0;
122
+}
123
+
124
+.login-logo {
125
+  width: 80px;
126
+  height: 80px;
127
+  margin: 0 auto 20px;
128
+  display: block;
129
+}
130
+
131
+.el-form-item {
132
+  ::v-deep(.el-form-item__label) {
133
+    color: #fff;
134
+  }
135
+
136
+  .el-input {
137
+    ::v-deep(.el-input__wrapper) {
138
+      border: 1px solid rgba(255, 255, 255, 0.1);
139
+      background: transparent;
140
+    }
141
+
142
+    ::v-deep(input) {
143
+      color: #fff;
144
+    }
145
+  }
146
+}
147
+</style>