chore: restructure project and add i18n support
- Reorganize project structure with new electron and shared directories - Add comprehensive i18n support with Chinese, English, and Japanese locales - Update build configurations and TypeScript paths for new structure - Add various UI components including chat interface and task management - Include Windows release binaries and localization files - Update dependencies and fix import paths throughout the codebase
This commit is contained in:
167
src/pages/login/index.vue
Normal file
167
src/pages/login/index.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div class="h-screen login-bg flex flex-col">
|
||||
<header-bar color="#fff">
|
||||
<drag-region class="w-full" />
|
||||
</header-bar>
|
||||
|
||||
<main class="box-border p-[8px] flex-auto flex ">
|
||||
<div class="w-[836px] box-border bg-white rounded-2xl p-[32px] flex flex-col">
|
||||
<div class="flex items-center">
|
||||
<img class="w-[48px] h-[48px]" src="@assets/images/login/blue_logo.png" />
|
||||
|
||||
<!-- <span class="ml-auto text-[14px] text-gray-600">没有账号?</span>
|
||||
<button
|
||||
class="bg-sky-50 rounded-[8px] text-[14px] text-sky-600 px-[12px] py-[6px] focus-visible:outline-none cursor-pointer">注册</button> -->
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-center justify-center mb-[24px] box-border pt-[40px]">
|
||||
<img class="w-[80px] h-[80px] mb-[12px]" src="@assets/images/login/user_icon.png" />
|
||||
<div class="text-[24px] font-500 text-gray-800 line-height-[32px] mb-[4px]">{{ t('login.title') }}</div>
|
||||
<div class="text-[16px] text-gray-500 line-height-[24px]">{{ t('login.subtitle') }}</div>
|
||||
</div>
|
||||
|
||||
<el-form class="w-[392px] ml-auto mr-auto" ref="formRef" :rules="rules" :model="form" label-position="top"
|
||||
@keyup.enter="onSubmit">
|
||||
<el-form-item prop="username">
|
||||
<div class="text-[14px] text-gray-600">{{ t('login.username') }}</div>
|
||||
<el-input class="h-[40px]" v-model.trim="form.username" :placeholder="t('login.usernamePlaceholder')" clearable autocomplete="off">
|
||||
<template #prefix>
|
||||
<RiUser3Fill size="20px" color="#99A0AE" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<div class="text-[14px] text-gray-600">{{ t('login.password') }}</div>
|
||||
<el-input class="h-[40px]" v-model.trim="form.password" type="password" :placeholder="t('login.passwordPlaceholder')" clearable
|
||||
autocomplete="off">
|
||||
<template #prefix>
|
||||
<RiKey2Fill size="20px" color="#99A0AE" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="code">
|
||||
<span class="text-[14px] text-gray-600">{{ t('login.code') }}</span>
|
||||
<el-input v-model.trim="form.code" :placeholder="t('login.codePlaceholder')" autocomplete="off">
|
||||
<template #suffix>
|
||||
<img class="w-[80px] h-[38px] cursor-pointer" :src="imgSrc" @click="getVerifyCode" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 记住密码|忘记密码 -->
|
||||
<!-- <div class="flex items-center justify-between mb-[24px] mt-[24px]">
|
||||
<div class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" v-model="showPwd" class="w-[14px] h-[14px] rounded-[4px]" />
|
||||
<span class="text-[14px] text-gray-600">记住密码</span>
|
||||
</div>
|
||||
<span class="text-[14px] text-sky-600 cursor-pointer">忘记密码?</span>
|
||||
</div> -->
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<button type="button"
|
||||
class="w-full py-2 bg-blue-600 cursor-pointer text-white rounded-[8px] hover:bg-blue-700 disabled:bg-blue-300"
|
||||
:loading="loading" @click="onSubmit">
|
||||
{{ t('login.loginButton') }}
|
||||
</button>
|
||||
|
||||
<!-- 同意协议 -->
|
||||
<!-- <div class="flex items-center justify-center gap-2 mt-[24px]">
|
||||
<input type="checkbox" v-model="isAgree" class="w-[14px] h-[14px] rounded-[4px]" />
|
||||
<span class="text-[14px] text-gray-600">我已同意</span>
|
||||
<span class="text-[14px] text-sky-600 cursor-pointer">《使用协议》</span>
|
||||
<span class="text-[14px] text-gray-600">和</span>
|
||||
<span class="text-[14px] text-sky-600 cursor-pointer">《隐私协议》</span>
|
||||
</div> -->
|
||||
</el-form>
|
||||
|
||||
<!-- Copy Right -->
|
||||
<!-- <div class="text-[14px] text-gray-500 text-center mt-auto">
|
||||
© 2025 贵州智念科技服务有限公司 版权所有
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<img class="w-[540px]" src="@assets/images/login/logo.png" />
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted } from "vue"
|
||||
import { useUserStore } from "../../store/userinfo"
|
||||
import { RiUser3Fill, RiKey2Fill } from '@remixicon/vue'
|
||||
import { generateUUID } from "../../utils/generateUUID"
|
||||
import { rule } from '../../utils/validate'
|
||||
import { useLocale } from '@src/composables/useLocale'
|
||||
|
||||
const { t } = useLocale()
|
||||
|
||||
// form 表单数据类型声明
|
||||
interface LoginForm {
|
||||
username: string;
|
||||
password: string;
|
||||
randomStr: string;
|
||||
code: string;
|
||||
grant_type: string;
|
||||
scope: string;
|
||||
}
|
||||
|
||||
const userStore = useUserStore()
|
||||
const form = reactive<LoginForm>({ username: "", password: "", randomStr: '', code: "", grant_type: '', scope: '' });
|
||||
const loading = ref(false);
|
||||
const showPwd = ref(false);
|
||||
const isAgree = ref(false);
|
||||
const imgSrc = ref('');
|
||||
const rules = reactive({
|
||||
username: [{ validator: rule.overLength, trigger: 'blur' }, { required: true, trigger: 'blur', message: () => t('login.usernameRequired') }], // 用户名校验规则
|
||||
password: [{ validator: rule.overLength, trigger: 'blur' }, { required: true, trigger: 'blur', message: () => t('login.passwordRequired') }], // 密码校验规则
|
||||
code: [{ validator: rule.overLength, trigger: 'blur' }, { required: true, trigger: 'blur', message: () => t('login.codeRequired') }], // 验证码校验规则
|
||||
})
|
||||
|
||||
//获取验证码图片
|
||||
const { VITE_SERVICE_URL } = (import.meta as any).env
|
||||
|
||||
const getVerifyCode = async () => {
|
||||
form.randomStr = generateUUID()
|
||||
const url = `${VITE_SERVICE_URL}/auth/code/image?randomStr=${form.randomStr}`
|
||||
console.log('验证码地址', url)
|
||||
imgSrc.value = url
|
||||
}
|
||||
|
||||
onMounted(() => getVerifyCode())
|
||||
|
||||
const router = useRouter()
|
||||
const formRef = ref()
|
||||
const onSubmit = async () => {
|
||||
const valid = await formRef.value.validate().catch(() => { }); // 表单校验
|
||||
if (!valid) return false;
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
userStore.login(form).then(() => {
|
||||
router.push({ path: '/home' })
|
||||
})
|
||||
} finally {
|
||||
getVerifyCode()
|
||||
loading.value = false; // 登录结束
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-bg {
|
||||
background: url('@assets/images/login/login_bg.png');
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__error) {
|
||||
padding-top: 8px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user