Files
dmz/src/components/partials/layout/toolbar/ToolbarUserProfile.vue
2025-05-24 01:47:40 +09:00

940 lines
23 KiB
Vue

<script setup lang="ts">
import type { UserData, iRePassword } from '/@src/utils/types'
import regex from '/@src/utils/regex'
const userSession = useUserSession()
const router = useRouter()
const notyf = useNotyf()
const biz = ref<UserData>()
biz.value = userSession.user
const modifyFlag = ref(false)
const rePasswordFlag = ref(false)
const modifyForm = ref<UserData>(<UserData>{
bizNo: biz.value.bizNo,
email: biz.value.email,
compNm: biz.value.compNm,
repNm: biz.value.repNm,
})
const initModify = {
email: true,
}
const modifyValid = ref(initModify)
const rePasswordForm = ref<iRePassword>({
bizNo: biz.value.bizNo,
oldPwd: '',
pwd: '',
rePwd: '',
})
const initRePassword = {
pwd: true,
rePwd: true,
}
const rePasswordValid = ref(initRePassword)
const rules = {
email: {
mask: /^\S*@?\S*$/,
lazy: false,
},
}
const onEmailComplete = (e) => {
modifyForm.value.email = e.value
}
function logout() {
userSession.logoutUser()
router.push('/')
}
function onModify() {
notyf.dismissAll()
if (!regex.email.test(modifyForm.value.email)) {
notyf.error('이메일이 정상적이지 않습니다. 다시 입력해주세요.')
modifyValid.value.email = false
return false
}
api.modify(modifyForm.value).then(() => {
notyf.success('사용자 정보가 변경 되었습니다.')
modifyFlag.value = false
}).catch((res) => {
notyf.error(res.response._data.body)
})
}
function onRePassword() {
notyf.dismissAll()
if (rePasswordForm.value.pwd !== rePasswordForm.value.rePwd) {
notyf.error('비밀번호가 일치 하지 않습니다..')
rePasswordValid.value.pwd = false
rePasswordValid.value.rePwd = false
return false
}
else if (!regex.password.test(rePasswordForm.value.pwd)) {
notyf.error('비밀번호는 영문 숫자 특수기호 조합 8자리이상 으로 입력해주세요.')
rePasswordValid.value.pwd = false
rePasswordValid.value.rePwd = false
return false
}
api.rePassword(rePasswordForm.value).then(() => {
notyf.success('비밀번호가 변경 되었습니다.')
rePasswordFlag.value = false
}).catch((res) => {
notyf.error(res.response._data.body)
})
}
</script>
<template>
<VDropdown
spaced
class="profile-dropdown"
style="width: 100% !important;"
>
<template #button="{ toggle }">
<div class="avatar-area">
<div>
<a
role="button"
tabindex="0"
class="is-trigger dropdown-trigger"
aria-haspopup="true"
@keydown.enter.prevent="toggle"
@click="toggle"
>
<VAvatar picture="/images/avatars/svg/vuero-7.svg" />
</a>
</div>
<div class="company-nm">{{ biz.compNm }}</div>
</div>
</template>
<template #content>
<div class="dropdown-head">
<VAvatar
size="large"
picture="/images/avatars/svg/vuero-7.svg"
/>
<div class="meta">
<span>{{ biz == null ? '' : biz.compNm }}</span>
<span>{{ biz == null ? '' : biz.bizNo }}</span>
</div>
</div>
<a
href="#"
role="menuitem"
class="dropdown-item is-media"
@click="modifyFlag = true"
>
<div class="icon">
<i
aria-hidden="true"
class="lnil lnil-user-alt"
/>
</div>
<div class="meta">
<span>계정 수정</span>
</div>
</a>
<hr class="dropdown-divider">
<a
href="#"
role="menuitem"
class="dropdown-item is-media"
@click="rePasswordFlag = true"
>
<div class="icon">
<i
aria-hidden="true"
class="lnil lnil-cog"
/>
</div>
<div class="meta">
<span>비밀번호 변경</span>
<span />
</div>
</a>
<hr class="dropdown-divider">
<div class="dropdown-item is-button">
<VButton
class="logout-button"
icon="lucide:log-out"
color="primary"
role="menuitem"
raised
fullwidth
@click="logout"
>
로그아웃
</VButton>
</div>
<VModal
is="form"
method="post"
novalidate
title="계정 수정"
:open="modifyFlag"
cancel-label="취소"
size="medium"
actions="center"
@close="modifyFlag = false"
>
<template #content>
<div class="signup-wrapper">
<div class="hero">
<div class="hero-body">
<div class="columns signup-columns">
<div class="column is-12">
<h1 class="title is-5 signup-title has-text-centered">
사용자 정보 수정
</h1>
<h2 class="subtitle signup-subtitle has-text-centered">
계약 발생시 아래에 입력된 이메일로 발신 됩니다. 정확하게 입력해주세요.
</h2>
<div class="signup-card">
<form
method="post"
novalidate
class="signup-form is-mobile-spaced"
@submit.prevent=""
>
<VField class="hide">
<VInput
v-model="modifyForm.bizNo"
type="email"
autocomplete="username"
/>
</VField>
<div class="columns is-multiline">
<div class="column is-12">
<VField>
<VControl :class="[!modifyValid.email && 'valid-err']">
<VIMaskInput
class="input v-input"
:mask="String"
:model-value="modifyForm.email"
:options="rules.email"
placeholder="kospo@kospo.co.kr"
autocomplete="email"
@complete="onEmailComplete"
/>
<VLabel
raw
class="auth-label"
>
이메일
</VLabel>
</VControl>
</VField>
</div>
<div class="column is-12">
<VField>
<VControl>
<VInput
v-model="modifyForm.compNm"
type="text"
autocomplete="family-name"
/>
<VLabel
raw
class="auth-label"
>
업체명
</VLabel>
</VControl>
</VField>
</div>
<div class="column is-12">
<VField>
<VControl>
<VInput
v-model="modifyForm.repNm"
type="text"
autocomplete="family-name"
/>
<VLabel
raw
class="auth-label"
>
대표자명
</VLabel>
</VControl>
</VField>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<template #action>
<VButton
color="primary"
raised
@click="onModify"
>
수정
</VButton>
</template>
</VModal>
<VModal
is="form"
method="post"
novalidate
title="비밀번호 변경"
:open="rePasswordFlag"
cancel-label="취소"
size="medium"
actions="center"
@close="rePasswordFlag = false"
>
<template #content>
<div class="signup-wrapper">
<div class="hero">
<div class="hero-body">
<div class="columns signup-columns">
<div class="column is-12">
<h1 class="title is-5 signup-title has-text-centered">
비밀번호 변경
</h1>
<h2 class="subtitle signup-subtitle has-text-centered">
비밀번호 규칙(소문자 + 숫자 + 특수기호) 8자리 이상 입니다.
</h2>
<div class="signup-card">
<form
method="post"
novalidate
class="signup-form is-mobile-spaced"
@submit.prevent=""
>
<VField class="hide">
<VInput
v-model="rePasswordForm.bizNo"
type="email"
autocomplete="username"
/>
</VField>
<div class="columns is-multiline">
<div class="column is-12">
<VField>
<VControl>
<VInput
v-model="rePasswordForm.oldPwd"
type="password"
autocomplete="current-password"
/>
<VLabel
raw
class="auth-label"
>
기존 비밀번호
</VLabel>
</VControl>
</VField>
</div>
<div class="column is-12">
<VField>
<VControl :class="[!rePasswordValid.pwd && 'valid-err']">
<VInput
v-model="rePasswordForm.pwd"
type="password"
autocomplete="current-password"
/>
<VLabel
raw
class="auth-label"
>
비밀번호
</VLabel>
</VControl>
</VField>
</div>
<div class="column is-12">
<VField>
<VControl :class="[!rePasswordValid.rePwd && 'valid-err']">
<VInput
v-model="rePasswordForm.rePwd"
type="password"
autocomplete="current-password"
/>
<VLabel
raw
class="auth-label"
>
비밀번호 확인
</VLabel>
</VControl>
</VField>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<template #action>
<VButton
color="primary"
raised
@click="onRePassword"
>
수정
</VButton>
</template>
</VModal>
</template>
</VDropdown>
</template>
<style scoped lang="scss">
.profile-dropdown {
> img {
height: 32px;
width: 32px;
border-radius: var(--radius-rounded);
margin: 0 4px;
cursor: pointer;
}
.avatar-area {
width:100% !important;
display:flex;
justify-content: left;
}
.dropdown-content, :deep(.dropdown-content) {
padding-top: 0 !important;
overflow: hidden;
.dropdown-head {
display: flex;
align-items: center;
padding: 20px 16px;
margin-bottom: 12px;
background: #fafafa;
.meta {
margin-inline-start: 12px;
font-family: var(--font);
span {
display: block;
&:first-child {
font-size: 1.1rem;
font-weight: 500;
color: var(--dark-text);
line-height: 1.2;
}
&:nth-child(2) {
text-transform: uppercase;
color: var(--light-text);
font-size: 0.7rem;
}
}
}
}
.logout-button {
.iconify {
color: var(--smoke-white) !important;
}
}
}
}
.is-dark {
.profile-dropdown {
.dropdown-content, :deep(.dropdown-content) {
.dropdown-head {
background: color-mix(in oklab, var(--dark-sidebar), white 2%) !important;
&:hover,
&:focus {
background: color-mix(in oklab, var(--dark-sidebar), white 2%) !important;
}
.meta {
&:hover {
background: color-mix(in oklab, var(--dark-sidebar), white 2%) !important;
}
span {
&:first-child {
color: var(--dark-dark-text) !important;
}
}
}
}
}
}
}
.signup-columns {
animation: fadeInLeft 0.5s;
.column.is-8 {
margin: 0 auto;
}
}
.signup-wrapper {
position: relative;
.card-bg {
position: absolute;
inset-inline-end: 0;
bottom: 0;
transform: scaleX(calc(var(--transform-direction) * 1));
display: block;
width: 90%;
transition: all 0.3s; // transition-all test
&.faded {
opacity: 0;
}
}
.signup-title {
font-family: var(--font-alt);
color: var(--dark-text);
}
.signup-subtitle {
font-family: var(--font);
color: var(--muted-grey);
font-size: 1rem;
}
.hero {
.hero-body {
overflow-x: hidden;
}
.signup-form {
.control {
position: relative;
width: 100%;
&.has-switch {
display: flex;
align-items: center;
span {
display: block;
color: var(--muted-grey);
}
> div {
margin-inline-start: auto;
transform: scale(0.8);
}
}
&.is-agree {
span {
color: color-mix(in oklab, var(--placeholder), black 8%);
a {
color: var(--muted-grey);
font-weight: 500;
transition: color 0.3s;
&:hover,
&:focus {
color: var(--primary);
}
}
}
}
.input {
padding-top: 10px;
height: 60px;
padding-inline-start: 10px;
border-radius: 8px;
transition: all 0.3s; // transition-all test
&:focus {
background: color-mix(in oklab, var(--fade-grey), white 6%);
border-color: var(--placeholder);
~ .auth-label,
~ .autv-icon .iconify {
color: var(--muted-grey);
}
}
}
.error-text {
color: var(--danger);
font-size: 0.8rem;
display: none;
padding: 2px 6px;
}
.auth-label {
position: absolute;
top: 6px;
inset-inline-start: 10px;
font-size: 0.8rem;
color: var(--dark-text);
font-weight: 500;
z-index: 2;
transition: all 0.3s; // transition-all test
}
.autv-icon {
position: absolute;
top: 0;
inset-inline-start: 0;
height: 60px;
width: 60px;
display: flex;
justify-content: center;
align-items: center;
.iconify {
font-size: 24px;
color: var(--placeholder);
transition: all 0.3s; // transition-all test
}
}
&.has-validation {
.validation-icon {
position: absolute;
top: 0;
inset-inline-end: 0;
height: 60px;
width: 60px;
display: none;
justify-content: center;
align-items: center;
.icon-wrapper {
height: 20px;
width: 20px;
display: flex;
justify-content: center;
align-items: center;
border-radius: var(--radius-rounded);
.iconify {
height: 10px;
width: 10px;
stroke-width: 3px;
color: var(--white) !important;
}
}
&.is-success {
.icon-wrapper {
background: var(--success);
}
}
&.is-error {
.icon-wrapper {
background: var(--danger);
}
}
}
&.has-success {
.validation-icon {
&.is-success {
display: flex;
}
&.is-error {
display: none;
}
}
}
&.has-error {
.input {
border-color: var(--danger);
}
.error-text {
display: block;
}
.validation-icon {
&.is-error {
display: flex;
}
&.is-success {
display: none;
}
}
}
}
&.is-flex {
display: flex;
align-items: center;
a {
display: block;
margin-inline-start: auto;
color: var(--muted-grey);
font-weight: 500;
font-size: 0.9rem;
transition: color 0.3s;
&:hover,
&:focus {
color: var(--primary);
}
}
.remember-me {
font-size: 0.9rem;
color: var(--muted-grey);
font-weight: 500;
}
}
}
}
.button-wrap {
margin: 20px 0 0;
&.has-help {
display: flex;
align-items: center;
> span {
margin-inline-start: 12px;
font-family: var(--font);
a {
color: var(--primary);
font-weight: 500;
padding: 0 3px;
}
}
}
&.is-centered {
margin-top: 40px;
text-align: center;
.button {
min-width: 180px;
margin-inline-start: 0 !important;
}
}
.button {
height: 46px;
width: 190px;
margin-inline-start: 6px;
&:first-child {
&:hover {
opacity: 0.95;
box-shadow: var(--primary-box-shadow);
}
}
&:nth-child(2) {
color: var(--dark-text);
border-color: var(--placeholder);
}
}
}
.signup-type {
display: flex;
align-items: center;
// margin-top: 16px;
.box-wrap {
width: 100%;
position: relative;
input {
position: absolute;
top: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
&:checked + .signup-box {
border-color: var(--primary);
.iconify {
color: var(--primary);
}
.meta {
span:first-child {
color: var(--primary);
}
}
}
}
.signup-box {
display: flex;
align-items: center;
padding: 12px;
background: var(--white);
border: 1px solid color-mix(in oklab, var(--fade-grey), black 3%);
border-radius: var(--radius-large);
transition: all 0.3s; // transition-all test
.iconify, .lnil {
font-size: 2rem;
color: var(--muted-grey);
}
.meta {
margin-inline-start: 10px;
span {
display: block;
&:first-child {
font-size: 0.85rem;
font-weight: 500;
color: var(--dark-text);
}
&:nth-child(2) {
font-size: 0.8rem;
color: var(--muted-grey);
}
}
}
}
&:first-child {
margin-inline-end: 6px;
}
&:nth-child(2) {
margin-inline-start: 6px;
}
}
}
}
}
.signup-profile-wrapper {
padding: 80px 60px 10px;
.title,
.subtitle {
text-align: center;
}
.title {
font-family: var(--font-alt);
font-size: 1.4rem;
}
.subtitle {
font-family: var(--font);
font-size: 1rem;
}
.picture-selector,
.skill-picture-selector {
width: 100%;
text-align: center;
.image-container {
position: relative;
width: 140px;
height: 140px;
margin: 10px auto;
border-radius: var(--radius-rounded);
img {
width: 140px;
height: 140px;
border-radius: var(--radius-rounded);
display: block;
border: 4px solid #e8e8e8;
margin-inline-start: -1px;
}
.upload-button {
position: absolute;
bottom: 18px;
inset-inline-end: 0;
width: 36px;
height: 36px;
display: flex;
justify-content: center;
align-items: center;
background: var(--white);
border-radius: var(--radius-rounded);
border: 1px solid color-mix(in oklab, var(--fade-grey), black 4%);
z-index: 5;
transition: all 0.3s; // transition-all test
cursor: pointer;
&:hover,
&:focus {
box-shadow: var(--light-box-shadow);
}
.iconify {
height: 16px;
width: 16px;
color: var(--dark-text);
}
}
}
}
}
.company-nm {
padding-left: 20px;
line-height:42px;
font-weight: 600;
color: var(--modal-text)
}
@media (width <= 767px) {
.company-nm {
display: none;
}
.brand-end {
.profile-dropdown {
.avatar-area {
justify-content: right;
}
}
}
}
</style>