243 lines
5.5 KiB
Vue
243 lines
5.5 KiB
Vue
|
|
<template>
|
||
|
|
<SettingsSection
|
||
|
|
:title="t('Settings.security.title')"
|
||
|
|
:description="t('Settings.security.description')"
|
||
|
|
content-class="security-container"
|
||
|
|
>
|
||
|
|
<div class="inner-divider" />
|
||
|
|
<div class="security-row">
|
||
|
|
<div class="security-inline-row">
|
||
|
|
<div class="security-label inline">{{ t('Settings.security.email') }}</div>
|
||
|
|
<div class="security-static">{{ email }}</div>
|
||
|
|
<button v-show="isEditing" type="button" class="small-btn" @click="emit('reset-email')">
|
||
|
|
{{ t('Settings.buttons.cancel') }}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div v-show="isEditing" class="security-row">
|
||
|
|
<div class="security-label">{{ t('Settings.security.newEmail') }}</div>
|
||
|
|
<div class="outlined-field verify-field">
|
||
|
|
<el-input
|
||
|
|
:model-value="newEmail"
|
||
|
|
:placeholder="t('Settings.security.newEmailPlaceholder')"
|
||
|
|
@update:model-value="emit('update:newEmail', String($event))"
|
||
|
|
/>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
class="verify-btn"
|
||
|
|
:class="{ verified: isEmailVerified }"
|
||
|
|
@click="emit('verify-email')"
|
||
|
|
>
|
||
|
|
{{ isEmailVerified ? t('Settings.security.verified') : t('Settings.security.verify') }}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
<div v-if="isEmailVerified" class="security-tip verified-tip">
|
||
|
|
{{ t('Settings.security.verifiedTip') }}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="inner-divider" />
|
||
|
|
|
||
|
|
<div class="security-row">
|
||
|
|
<div class="security-inline-row">
|
||
|
|
<div class="security-label inline">{{ t('Settings.security.password') }}</div>
|
||
|
|
<div class="security-static password-mask">.........</div>
|
||
|
|
<button v-show="isEditing" type="button" class="small-btn" @click="emit('reset-password')">
|
||
|
|
{{ t('Settings.buttons.cancel') }}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div v-show="isEditing" class="security-row">
|
||
|
|
<div class="security-label">{{ t('Settings.security.newPassword') }}</div>
|
||
|
|
<div class="outlined-field">
|
||
|
|
<el-input
|
||
|
|
:model-value="newPassword"
|
||
|
|
type="password"
|
||
|
|
show-password
|
||
|
|
:placeholder="t('Settings.security.newPasswordPlaceholder')"
|
||
|
|
@update:model-value="emit('update:newPassword', String($event))"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
<div class="security-tip">{{ t('Settings.security.passwordTip') }}</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div v-show="isEditing" class="security-row">
|
||
|
|
<div class="security-label">{{ t('Settings.security.currentPassword') }}</div>
|
||
|
|
<div class="outlined-field">
|
||
|
|
<el-input
|
||
|
|
:model-value="currentPassword"
|
||
|
|
type="password"
|
||
|
|
show-password
|
||
|
|
:placeholder="t('Settings.security.currentPasswordPlaceholder')"
|
||
|
|
@update:model-value="emit('update:currentPassword', String($event))"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="inner-divider" />
|
||
|
|
</SettingsSection>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
import { useI18n } from 'vue-i18n'
|
||
|
|
import SettingsSection from './SettingsSection.vue'
|
||
|
|
|
||
|
|
defineProps<{
|
||
|
|
email: string
|
||
|
|
newEmail: string
|
||
|
|
newPassword: string
|
||
|
|
currentPassword: string
|
||
|
|
isEditing: boolean
|
||
|
|
isEmailVerified: boolean
|
||
|
|
}>()
|
||
|
|
|
||
|
|
const emit = defineEmits<{
|
||
|
|
(event: 'update:newEmail', value: string): void
|
||
|
|
(event: 'update:newPassword', value: string): void
|
||
|
|
(event: 'update:currentPassword', value: string): void
|
||
|
|
(event: 'reset-email'): void
|
||
|
|
(event: 'reset-password'): void
|
||
|
|
(event: 'verify-email'): void
|
||
|
|
}>()
|
||
|
|
|
||
|
|
const { t } = useI18n()
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="less" scoped>
|
||
|
|
.field-text() {
|
||
|
|
font-family: 'KaiseiOpti-Regular';
|
||
|
|
font-size: 1.6rem;
|
||
|
|
line-height: 2.4rem;
|
||
|
|
color: #232323;
|
||
|
|
}
|
||
|
|
|
||
|
|
.field-frame() {
|
||
|
|
width: 100%;
|
||
|
|
min-height: 4rem;
|
||
|
|
border: 0.1rem solid #979797;
|
||
|
|
}
|
||
|
|
|
||
|
|
.control-wrapper() {
|
||
|
|
box-shadow: none;
|
||
|
|
border-radius: 0;
|
||
|
|
padding: 0 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.security-row + .security-row {
|
||
|
|
margin-top: 2.8rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.security-label {
|
||
|
|
margin: 0 0 0.8rem;
|
||
|
|
font-family: 'KaiseiOpti-Medium';
|
||
|
|
font-size: 1.4rem;
|
||
|
|
line-height: 2.4rem;
|
||
|
|
letter-spacing: 0.04em;
|
||
|
|
color: #585858;
|
||
|
|
|
||
|
|
&.inline {
|
||
|
|
width: 10.8rem;
|
||
|
|
margin-bottom: 0;
|
||
|
|
flex-shrink: 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.security-static {
|
||
|
|
.field-text();
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
flex: 1;
|
||
|
|
min-height: 2.4rem;
|
||
|
|
padding: 0.1rem 0 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.security-inline-row {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 2.8rem;
|
||
|
|
min-height: 3.2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.security-tip {
|
||
|
|
margin-top: 0.6rem;
|
||
|
|
font-family: 'KaiseiOpti-Regular';
|
||
|
|
font-size: 1.2rem;
|
||
|
|
line-height: 1.6rem;
|
||
|
|
color: #9f9f9f;
|
||
|
|
}
|
||
|
|
|
||
|
|
.outlined-field {
|
||
|
|
.field-frame();
|
||
|
|
|
||
|
|
:deep(.el-input) {
|
||
|
|
width: 100%;
|
||
|
|
min-height: 4rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
:deep(.el-input__wrapper) {
|
||
|
|
.control-wrapper();
|
||
|
|
min-height: 4rem;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.verify-field {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
margin-top: 0.8rem;
|
||
|
|
|
||
|
|
:deep(.el-input) {
|
||
|
|
flex: 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.verify-btn {
|
||
|
|
border: none;
|
||
|
|
min-width: 11rem;
|
||
|
|
height: 2.8rem;
|
||
|
|
line-height: 2.8rem;
|
||
|
|
border-left: 0.1rem solid #979797;
|
||
|
|
background: #ffffff;
|
||
|
|
font-family: 'KaiseiOpti-Medium';
|
||
|
|
font-size: 1.4rem;
|
||
|
|
color: #232323;
|
||
|
|
cursor: pointer;
|
||
|
|
padding: 0 2rem;
|
||
|
|
|
||
|
|
&.verified {
|
||
|
|
color: #ffffff;
|
||
|
|
background: #232323;
|
||
|
|
border-left-color: #232323;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.password-mask {
|
||
|
|
font-family: 'KaiseiOpti-Bold';
|
||
|
|
letter-spacing: 0.08rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.inner-divider {
|
||
|
|
height: 1px;
|
||
|
|
margin: 2rem 0;
|
||
|
|
background-color: #c4c4c4;
|
||
|
|
}
|
||
|
|
|
||
|
|
.small-btn {
|
||
|
|
width: 10rem;
|
||
|
|
height: 3.2rem;
|
||
|
|
align-self: flex-start;
|
||
|
|
border: 0.1rem solid #c4c4c4;
|
||
|
|
background: #f6f6f6;
|
||
|
|
font-family: 'KaiseiOpti-Bold';
|
||
|
|
font-size: 1.2rem;
|
||
|
|
line-height: 2.6rem;
|
||
|
|
letter-spacing: -0.03em;
|
||
|
|
color: #232323;
|
||
|
|
cursor: pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
.verified-tip {
|
||
|
|
color: #6f7f68;
|
||
|
|
}
|
||
|
|
</style>
|