mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 10:12:51 +00:00
feat: user login
This commit is contained in:
parent
75f75f0111
commit
9912b85df0
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="chat-knowledge-source">
|
||||
<div class="flex align-center mt-16" v-if="!isWorkFlow(props.type)">
|
||||
<div class="flex align-center mt-16">
|
||||
<span class="mr-4 color-secondary">{{ $t('chat.KnowledgeSource.title') }}</span>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button type="primary" class="mr-8" link @click="openParagraph(data)">
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
{{ data.paragraph_list?.length || 0 }}</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="mt-8" v-if="!isWorkFlow(props.type)">
|
||||
<div class="mt-8">
|
||||
<el-row :gutter="8" v-if="uniqueParagraphList?.length">
|
||||
<template v-for="(item, index) in uniqueParagraphList" :key="index">
|
||||
<el-col :span="12" class="mb-8">
|
||||
|
|
@ -51,11 +51,10 @@
|
|||
>
|
||||
</div>
|
||||
<el-button
|
||||
v-if="isWorkFlow(props.type)"
|
||||
type="primary"
|
||||
link
|
||||
@click="openExecutionDetail(data.execution_details)"
|
||||
style="padding: 0;"
|
||||
style="padding: 0"
|
||||
>
|
||||
<el-icon class="mr-4"><Document /></el-icon>
|
||||
{{ $t('chat.executionDetails.title') }}</el-button
|
||||
|
|
@ -76,16 +75,16 @@ import { getImgUrl, getNormalizedUrl } from '@/utils/utils'
|
|||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
default: () => {},
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
default: '',
|
||||
},
|
||||
executionIsRightPanel: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['openExecutionDetail', 'openParagraph'])
|
||||
|
|
@ -100,7 +99,7 @@ function openParagraph(row: any, id?: string) {
|
|||
ParagraphSourceDialogRef.value.open(row, id)
|
||||
}
|
||||
function openExecutionDetail(row: any) {
|
||||
if(props.executionIsRightPanel){
|
||||
if (props.executionIsRightPanel) {
|
||||
emit('openExecutionDetail')
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
<div class="login-form-container">
|
||||
<div class="login-title">
|
||||
<div class="logo text-center">
|
||||
<LogoFull height="45px" />
|
||||
<slot name="logo">
|
||||
<LogoFull height="45px" />
|
||||
</slot>
|
||||
</div>
|
||||
<div class="sub-title text-center" v-if="subTitle">
|
||||
<el-text type="info">{{ subTitle }}</el-text>
|
||||
|
|
@ -16,7 +18,7 @@
|
|||
<script setup lang="ts">
|
||||
defineProps({
|
||||
title: String,
|
||||
subTitle: String
|
||||
subTitle: String,
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
|
@ -30,7 +32,6 @@ defineProps({
|
|||
}
|
||||
}
|
||||
.login-card {
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,54 +7,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { getThemeImg } from '@/utils/theme'
|
||||
import useStore from '@/stores'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
import { langList, localeConfigKey, getBrowserLang } from '@/locales/index'
|
||||
defineProps({
|
||||
lang: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
})
|
||||
const { user, theme } = useStore()
|
||||
|
||||
const changeLang = (lang: string) => {
|
||||
useLocalStorage(localeConfigKey, getBrowserLang()).value = lang
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
const currentLanguage = computed(() => {
|
||||
return langList.value?.filter((v: any) => v.value === user.getLanguage())?.[0]?.label
|
||||
})
|
||||
|
||||
const fileURL = computed(() => {
|
||||
if (theme.themeInfo?.loginImage) {
|
||||
if (typeof theme.themeInfo?.loginImage === 'string') {
|
||||
return theme.themeInfo?.loginImage
|
||||
} else {
|
||||
return URL.createObjectURL(theme.themeInfo?.loginImage)
|
||||
}
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
const loginImage = computed(() => {
|
||||
if (theme.themeInfo?.loginImage) {
|
||||
return `${fileURL.value}`
|
||||
} else {
|
||||
const imgName = getThemeImg(theme.themeInfo?.theme)
|
||||
const imgPath = `${window.MaxKB.prefix}/theme/${imgName}.jpg`
|
||||
const imageUrl = new URL(imgPath, import.meta.url).href
|
||||
return imageUrl
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<script setup lang="ts"></script>
|
||||
<style lang="scss" scoped>
|
||||
.login-warp {
|
||||
height: 100vh;
|
||||
background: url('@/assets/chat/user-login-bg.jpg') no-repeat center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@
|
|||
<AppIcon
|
||||
v-if="paginationConfig.total"
|
||||
iconName="app-chat-record"
|
||||
class="info mr-8"
|
||||
class="color-secondary mr-8"
|
||||
style="font-size: 16px"
|
||||
></AppIcon>
|
||||
<span v-if="paginationConfig.total" class="lighter">
|
||||
|
|
|
|||
|
|
@ -1,137 +0,0 @@
|
|||
<template>
|
||||
<UserLoginLayout>
|
||||
<LoginContainer :subTitle="$t('theme.defaultSlogan')">
|
||||
<h2 class="mb-24">{{ $t('views.login.resetPassword') }}</h2>
|
||||
<el-form
|
||||
class="reset-password-form"
|
||||
ref="resetPasswordFormRef"
|
||||
:model="resetPasswordForm"
|
||||
:rules="rules"
|
||||
>
|
||||
<div class="mb-24">
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
type="password"
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.password"
|
||||
:placeholder="$t('views.login.loginForm.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mb-24">
|
||||
<el-form-item prop="re_password">
|
||||
<el-input
|
||||
type="password"
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.re_password"
|
||||
:placeholder="$t('views.login.loginForm.re_password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<el-button size="large" type="primary" class="w-full" @click="resetPassword">{{
|
||||
$t('common.confirm')
|
||||
}}</el-button>
|
||||
<div class="operate-container mt-12">
|
||||
<el-button
|
||||
size="large"
|
||||
class="register"
|
||||
@click="router.push('/login')"
|
||||
link
|
||||
type="primary"
|
||||
icon="ArrowLeft"
|
||||
>
|
||||
{{ $t('views.login.buttons.backLogin') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</LoginContainer>
|
||||
</UserLoginLayout>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import type { ResetPasswordRequest } from '@/api/type/user'
|
||||
import LoginContainer from '@/layout/login-layout/LoginContainer.vue'
|
||||
import UserLoginLayout from '@/layout/login-layout/UserLoginLayout.vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import UserApi from '@/api/user/user'
|
||||
import { t } from '@/locales'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { code, email },
|
||||
} = route
|
||||
const resetPasswordForm = ref<ResetPasswordRequest>({
|
||||
password: '',
|
||||
re_password: '',
|
||||
email: '',
|
||||
code: '',
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (code && email) {
|
||||
resetPasswordForm.value.code = code as string
|
||||
resetPasswordForm.value.email = email as string
|
||||
} else {
|
||||
router.push('forgot_password')
|
||||
}
|
||||
})
|
||||
|
||||
const rules = ref<FormRules<ResetPasswordRequest>>({
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.login.loginForm.re_password.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.login.loginForm.password.lengthMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
re_password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.login.loginForm.re_password.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.login.loginForm.password.lengthMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (resetPasswordForm.value.password != resetPasswordForm.value.re_password) {
|
||||
callback(new Error(t('views.login.loginForm.re_password.validatorMessage')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
})
|
||||
const resetPasswordFormRef = ref<FormInstance>()
|
||||
const loading = ref<boolean>(false)
|
||||
const resetPassword = () => {
|
||||
resetPasswordFormRef.value
|
||||
?.validate()
|
||||
.then(() => UserApi.postResetPassword(resetPasswordForm.value, loading))
|
||||
.then(() => {
|
||||
MsgSuccess(t('common.modifySuccess'))
|
||||
router.push({ name: 'login' })
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
<template>
|
||||
<UserLoginLayout>
|
||||
<LoginContainer :subTitle="$t('theme.defaultSlogan')">
|
||||
<h2 class="mb-24">{{ $t('views.login.resetPassword') }}</h2>
|
||||
<el-form
|
||||
class="reset-password-form"
|
||||
ref="resetPasswordFormRef"
|
||||
:model="resetPasswordForm"
|
||||
:rules="rules"
|
||||
>
|
||||
<div class="mb-24">
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
type="password"
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.password"
|
||||
:placeholder="$t('views.login.loginForm.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mb-24">
|
||||
<el-form-item prop="re_password">
|
||||
<el-input
|
||||
type="password"
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.re_password"
|
||||
:placeholder="$t('views.login.loginForm.re_password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<el-button size="large" type="primary" class="w-full" @click="resetPassword">{{
|
||||
$t('common.confirm')
|
||||
}}</el-button>
|
||||
<div class="operate-container mt-12">
|
||||
<el-button
|
||||
size="large"
|
||||
class="register"
|
||||
@click="router.push('/login')"
|
||||
link
|
||||
type="primary"
|
||||
icon="ArrowLeft"
|
||||
>
|
||||
{{ $t('views.login.buttons.backLogin') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</LoginContainer>
|
||||
</UserLoginLayout>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import LoginContainer from '@/layout/login-layout/LoginContainer.vue'
|
||||
import UserLoginLayout from '@/layout/login-layout/UserLoginLayout.vue'
|
||||
import type { ResetPasswordRequest } from '@/api/type/user'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import UserApi from '@/api/user/user'
|
||||
import { t } from '@/locales'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { code, email },
|
||||
} = route
|
||||
const resetPasswordForm = ref<ResetPasswordRequest>({
|
||||
password: '',
|
||||
re_password: '',
|
||||
email: '',
|
||||
code: '',
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (code && email) {
|
||||
resetPasswordForm.value.code = code as string
|
||||
resetPasswordForm.value.email = email as string
|
||||
} else {
|
||||
router.push('forgot_password')
|
||||
}
|
||||
})
|
||||
|
||||
const rules = ref<FormRules<ResetPasswordRequest>>({
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.login.loginForm.re_password.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.login.loginForm.password.lengthMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
re_password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.login.loginForm.re_password.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.login.loginForm.password.lengthMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (resetPasswordForm.value.password != resetPasswordForm.value.re_password) {
|
||||
callback(new Error(t('views.login.loginForm.re_password.validatorMessage')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
})
|
||||
const resetPasswordFormRef = ref<FormInstance>()
|
||||
const loading = ref<boolean>(false)
|
||||
const resetPassword = () => {
|
||||
resetPasswordFormRef.value
|
||||
?.validate()
|
||||
.then(() => UserApi.postResetPassword(resetPasswordForm.value, loading))
|
||||
.then(() => {
|
||||
MsgSuccess(t('common.modifySuccess'))
|
||||
router.push({ name: 'login' })
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -1,13 +1,40 @@
|
|||
<template>
|
||||
<UserLoginLayout v-if="!loading" v-loading="loading">
|
||||
<LoginContainer
|
||||
v-if="chatUser.chat_profile?.authentication_type == 'password'"
|
||||
:subTitle="theme.themeInfo?.slogan || $t('theme.defaultSlogan')"
|
||||
>
|
||||
<LoginContainer v-if="chatUser.chat_profile?.authentication_type == 'password'">
|
||||
<template #logo>
|
||||
<div class="flex-center">
|
||||
<el-avatar
|
||||
v-if="isAppIcon(chatUser.chat_profile?.icon)"
|
||||
shape="square"
|
||||
:size="32"
|
||||
class="mr-8"
|
||||
style="background: none"
|
||||
>
|
||||
<img :src="chatUser.chat_profile?.icon" alt="" />
|
||||
</el-avatar>
|
||||
<LogoIcon v-else height="32px" class="mr-8" />
|
||||
<h4>{{ chatUser.chat_profile?.application_name }}</h4>
|
||||
</div>
|
||||
</template>
|
||||
<PasswordAuth></PasswordAuth>
|
||||
</LoginContainer>
|
||||
|
||||
<LoginContainer v-else :subTitle="theme.themeInfo?.slogan || $t('theme.defaultSlogan')">
|
||||
<LoginContainer v-else>
|
||||
<template #logo>
|
||||
<div class="flex-center">
|
||||
<el-avatar
|
||||
v-if="isAppIcon(chatUser.chat_profile?.icon)"
|
||||
shape="square"
|
||||
:size="32"
|
||||
class="mr-8"
|
||||
style="background: none"
|
||||
>
|
||||
<img :src="chatUser.chat_profile?.icon" alt="" />
|
||||
</el-avatar>
|
||||
<LogoIcon v-else height="32px" class="mr-8" />
|
||||
<h4>{{ chatUser.chat_profile?.application_name }}</h4>
|
||||
</div>
|
||||
</template>
|
||||
<h2 class="mb-24" v-if="!showQrCodeTab">
|
||||
{{ loginMode == 'LOCAL' ? $t('views.login.title') : loginMode }}
|
||||
</h2>
|
||||
|
|
@ -75,17 +102,6 @@
|
|||
>
|
||||
{{ $t('views.login.buttons.login') }}
|
||||
</el-button>
|
||||
<div class="operate-container flex-between mt-12">
|
||||
<el-button
|
||||
:loading="loading"
|
||||
class="forgot-password"
|
||||
@click="router.push('/forgot_password')"
|
||||
link
|
||||
type="primary"
|
||||
>
|
||||
{{ $t('views.login.forgotPassword') }}?
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showQrCodeTab">
|
||||
<QrCodeTab :tabs="orgOptions" />
|
||||
|
|
@ -147,7 +163,7 @@ import { useI18n } from 'vue-i18n'
|
|||
import QrCodeTab from '@/views/login/scanCompinents/QrCodeTab.vue'
|
||||
import { MsgConfirm, MsgError } from '@/utils/message.ts'
|
||||
import PasswordAuth from '@/views/chat/auth/component/password.vue'
|
||||
import useUserStore from '@/stores/modules/user.ts'
|
||||
import { isAppIcon } from '@/utils/common'
|
||||
|
||||
const router = useRouter()
|
||||
const { login, user, theme, chatUser } = useStore()
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ export default defineConfig((conf: any) => {
|
|||
const ENV = loadEnv(mode, envDir)
|
||||
const proxyConf: Record<string, string | ProxyOptions> = {}
|
||||
proxyConf['/admin/api'] = {
|
||||
target: 'http://47.92.195.88:8080/',
|
||||
// target: 'http://127.0.0.1:8080',
|
||||
// target: 'http://47.92.195.88:8080/',
|
||||
target: 'http://127.0.0.1:8080',
|
||||
changeOrigin: true,
|
||||
}
|
||||
proxyConf['/oss'] = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue