|
@@ -0,0 +1,192 @@
|
|
|
+<template>
|
|
|
+ <div class="flex size-full items-center justify-center bg-[#f8fafc]">
|
|
|
+ <div
|
|
|
+ class="w-full max-w-[420px] rounded-xl bg-white p-8"
|
|
|
+ style="box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1)"
|
|
|
+ >
|
|
|
+ <!-- Logo -->
|
|
|
+ <div class="mb-8 flex justify-center">
|
|
|
+ <img
|
|
|
+ src="@/assets/images/logo.png"
|
|
|
+ alt="北之星"
|
|
|
+ class="h-20 object-contain"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 登录表单 -->
|
|
|
+ <CzrForm ref="ref_form">
|
|
|
+ <!-- 账号输入框 -->
|
|
|
+ <div class="mb-6 w-full">
|
|
|
+ <label class="mb-1 block text-sm font-medium text-gray-700"
|
|
|
+ >账号</label
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="relative block w-full rounded-md border-gray-300 py-3 pl-4 pl-8 shadow-sm focus:outline-none"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-4"
|
|
|
+ >
|
|
|
+ <i class="fas fa-user text-gray-400"></i>
|
|
|
+ </div>
|
|
|
+ <CzrFormColumn
|
|
|
+ required
|
|
|
+ :span="24"
|
|
|
+ label-width="0px"
|
|
|
+ v-model:param="state.form.username"
|
|
|
+ :transparent="true"
|
|
|
+ default-error-msg="请输入账号"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 密码输入框 -->
|
|
|
+ <div class="mb-6 w-full">
|
|
|
+ <label class="mb-1 block text-sm font-medium text-gray-700"
|
|
|
+ >密码</label
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="relative block w-full rounded-md border-gray-300 py-3 pl-4 pl-8 shadow-sm focus:outline-none"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-4"
|
|
|
+ >
|
|
|
+ <i class="fas fa-lock text-gray-400"></i>
|
|
|
+ </div>
|
|
|
+ <CzrFormColumn
|
|
|
+ required
|
|
|
+ :span="24"
|
|
|
+ label-width="0px"
|
|
|
+ v-model:param="state.form.password"
|
|
|
+ type="password"
|
|
|
+ show-password
|
|
|
+ :transparent="true"
|
|
|
+ default-error-msg="请输入密码"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 验证码输入框 -->
|
|
|
+ <div class="mb-6 w-full">
|
|
|
+ <label class="mb-1 block text-sm font-medium text-gray-700"
|
|
|
+ >验证码</label
|
|
|
+ >
|
|
|
+ <div class="grid grid-cols-4 gap-4">
|
|
|
+ <div
|
|
|
+ class="relative col-span-3 block rounded-md border-gray-300 py-3 pl-4 pl-8 shadow-sm focus:outline-none"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-4"
|
|
|
+ >
|
|
|
+ <i class="fas fa-lock text-gray-400"></i>
|
|
|
+ </div>
|
|
|
+ <CzrFormColumn
|
|
|
+ required
|
|
|
+ :span="24"
|
|
|
+ label-width="0px"
|
|
|
+ v-model:param="state.form.code"
|
|
|
+ :transparent="true"
|
|
|
+ default-error-msg="请输入验证码"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="col-span-1 flex items-center">
|
|
|
+ <img
|
|
|
+ src="@/assets/images/logo.png"
|
|
|
+ alt="验证码"
|
|
|
+ class="captcha-img h-10 rounded border border-gray-300"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 登录按钮 -->
|
|
|
+ <div
|
|
|
+ v-loading="state.loading"
|
|
|
+ class="btn-login flex w-full justify-center rounded-md border border-transparent bg-blue-600 px-4 py-3 text-sm font-medium text-white shadow-sm hover:bg-blue-700 focus:outline-none"
|
|
|
+ @click="onLogin"
|
|
|
+ >
|
|
|
+ 登录
|
|
|
+ </div>
|
|
|
+ </CzrForm>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { reactive, ref } from 'vue'
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
+import { Notify } from 'quasar'
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+const state: any = reactive({
|
|
|
+ form: {
|
|
|
+ username: '',
|
|
|
+ password: '',
|
|
|
+ code: '',
|
|
|
+ },
|
|
|
+ loading: false,
|
|
|
+})
|
|
|
+const ref_form = ref()
|
|
|
+const onLogin = () => {
|
|
|
+ if (!state.loading) {
|
|
|
+ ref_form.value
|
|
|
+ .submit()
|
|
|
+ .then(() => {
|
|
|
+ state.loading = true
|
|
|
+ setTimeout(() => {
|
|
|
+ Notify.create({
|
|
|
+ message: '登录成功!',
|
|
|
+ position: 'top',
|
|
|
+ type: 'success',
|
|
|
+ })
|
|
|
+ localStorage.setItem((import.meta as any).env.VITE_TOKEN, 'SSS')
|
|
|
+ router.replace({ name: 'root' })
|
|
|
+ state.loading = false
|
|
|
+ }, 1000)
|
|
|
+ // loginSubmit(state.form)
|
|
|
+ // .then(({ data }: any) => {
|
|
|
+ // Notify.create({
|
|
|
+ // message: '登录成功!',
|
|
|
+ // position: 'top',
|
|
|
+ // type: 'success',
|
|
|
+ // })
|
|
|
+ // localStorage.setItem((import.meta as any).env.VITE_TOKEN, data)
|
|
|
+ // router.replace({ name: 'root' })
|
|
|
+ // state.loading = false
|
|
|
+ // })
|
|
|
+ // .catch(() => {})
|
|
|
+ // .finally(() => {
|
|
|
+ // state.loading = false
|
|
|
+ // })
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ Notify.create({
|
|
|
+ message: e[0].message,
|
|
|
+ position: 'top',
|
|
|
+ type: 'warning',
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.btn-login {
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+.btn-login:hover {
|
|
|
+ transform: translateY(-2px);
|
|
|
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+.captcha-img {
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+.captcha-img:hover {
|
|
|
+ opacity: 0.8;
|
|
|
+}
|
|
|
+:deep(.el-form-item) {
|
|
|
+ margin-bottom: 0;
|
|
|
+ .el-form-item__error {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|