|
|
|
|
@ -1,43 +1,68 @@
|
|
|
|
|
<template>
|
|
|
|
|
<!-- 头部头部控制区域容器
|
|
|
|
|
- 绝对定位在右上角,使用flex布局
|
|
|
|
|
- 绑定keydown事件,按k键打开搜索模型
|
|
|
|
|
-->
|
|
|
|
|
<div class="header-controls absolute top-10 right-0 flex flex-row" @keydown.k="handleOpenModel" tabindex="0">
|
|
|
|
|
<!-- 搜索按钮
|
|
|
|
|
- 点击触发打开搜索模型
|
|
|
|
|
- 使用自定义阴影样式和图标
|
|
|
|
|
-->
|
|
|
|
|
<span class="ob-drop-shadow" data-dia="search" @click="handleOpenModel">
|
|
|
|
|
<svg-icon icon-class="search" />
|
|
|
|
|
</span>
|
|
|
|
|
<!-- 多语言切换下拉菜单
|
|
|
|
|
- 当启用多语言功能时显示
|
|
|
|
|
- 点击触发语言切换事件
|
|
|
|
|
-->
|
|
|
|
|
<Dropdown v-if="multiLanguage === 1" @command="handleClick">
|
|
|
|
|
<span class="ob-drop-shadow" data-dia="language">
|
|
|
|
|
<svg-icon icon-class="globe" />
|
|
|
|
|
<!-- 显示当前语言 -->
|
|
|
|
|
<span v-if="$i18n.locale == 'cn'">中文</span>
|
|
|
|
|
<span v-if="$i18n.locale == 'en'">EN</span>
|
|
|
|
|
</span>
|
|
|
|
|
<!-- 语言选择下拉菜单 -->
|
|
|
|
|
<DropdownMenu>
|
|
|
|
|
<DropdownItem name="en">English</DropdownItem>
|
|
|
|
|
<DropdownItem name="cn">中文</DropdownItem>
|
|
|
|
|
</DropdownMenu>
|
|
|
|
|
</Dropdown>
|
|
|
|
|
<!-- 未登录状态显示登录按钮 -->
|
|
|
|
|
<template v-if="userInfo === ''">
|
|
|
|
|
<span class="mr-3" @click="openLoginDialog">{{ t('settings.login') }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
<!-- 已登录状态显示用户头像和下拉菜单 -->
|
|
|
|
|
<template v-if="userInfo !== ''">
|
|
|
|
|
<Dropdown hover>
|
|
|
|
|
<span class="mr-2">
|
|
|
|
|
<div class="flex-shrink-0">
|
|
|
|
|
<!-- 用户头像容器 -->
|
|
|
|
|
<div class="rounded-full ring-gray-100 overflow-hidden shaodw-lg w-9">
|
|
|
|
|
<img class="avatar-img" :src="userInfo.avatar" alt="" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</span>
|
|
|
|
|
<!-- 用户操作下拉菜单 -->
|
|
|
|
|
<DropdownMenu>
|
|
|
|
|
<!-- 非移动端显示个人中心选项 -->
|
|
|
|
|
<template v-if="!isMobile">
|
|
|
|
|
<DropdownItem @click="openUserCenter">{{ t('settings.personal-center') }}</DropdownItem>
|
|
|
|
|
</template>
|
|
|
|
|
<!-- 登出选项 -->
|
|
|
|
|
<DropdownItem @click="logout">{{ t('settings.logout') }}</DropdownItem>
|
|
|
|
|
</DropdownMenu>
|
|
|
|
|
</Dropdown>
|
|
|
|
|
</template>
|
|
|
|
|
<!-- 主题切换按钮 -->
|
|
|
|
|
<span no-hover-effect class="ob-drop-shadow" data-dia="light-switch">
|
|
|
|
|
<ThemeToggle />
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 登录对话框
|
|
|
|
|
- 控制显示隐藏(v-model)
|
|
|
|
|
- 宽度30%,移动端全屏显示
|
|
|
|
|
-->
|
|
|
|
|
<el-dialog v-model="loginDialogVisible" width="30%" :fullscreen="isMobile">
|
|
|
|
|
<el-form @keyup.enter.native="login">
|
|
|
|
|
<el-form-item model="userInfo" class="mt-5">
|
|
|
|
|
@ -58,6 +83,7 @@
|
|
|
|
|
</div>
|
|
|
|
|
</el-form>
|
|
|
|
|
</el-dialog>
|
|
|
|
|
<!-- 注册对话框 -->
|
|
|
|
|
<el-dialog v-model="registerDialogVisible" width="30%" :fullscreen="isMobile">
|
|
|
|
|
<el-form>
|
|
|
|
|
<el-form-item model="userInfo" class="mt-5">
|
|
|
|
|
@ -129,9 +155,10 @@ import { useSearchStore } from '@/stores/search'
|
|
|
|
|
import config from '@/config/config'
|
|
|
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
|
import emitter from '@/utils/mitt'
|
|
|
|
|
|
|
|
|
|
// 定义Controls组件
|
|
|
|
|
export default defineComponent({
|
|
|
|
|
name: 'Controls',
|
|
|
|
|
// 注册组件
|
|
|
|
|
components: {
|
|
|
|
|
Dropdown,
|
|
|
|
|
DropdownMenu,
|
|
|
|
|
@ -140,38 +167,48 @@ export default defineComponent({
|
|
|
|
|
SearchModel
|
|
|
|
|
},
|
|
|
|
|
setup() {
|
|
|
|
|
// 获取国际化翻译函数
|
|
|
|
|
const { t } = useI18n()
|
|
|
|
|
// 获取全局属性
|
|
|
|
|
const proxy: any = getCurrentInstance()?.appContext.config.globalProperties
|
|
|
|
|
// 获取状态管理实例
|
|
|
|
|
const appStore = useAppStore()
|
|
|
|
|
const commonStore = useCommonStore()
|
|
|
|
|
const userStore = useUserStore()
|
|
|
|
|
const searchStore = useSearchStore()
|
|
|
|
|
// 获取路由实例
|
|
|
|
|
const route = useRoute()
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
const loginInfo = reactive({
|
|
|
|
|
// 登录信息响应式对象
|
|
|
|
|
username: '' as any,
|
|
|
|
|
password: '' as any,
|
|
|
|
|
code: '' as any
|
|
|
|
|
})
|
|
|
|
|
// 对话框状态响应式对象
|
|
|
|
|
const reactiveDate = reactive({
|
|
|
|
|
loginDialogVisible: false,
|
|
|
|
|
registerDialogVisible: false,
|
|
|
|
|
forgetPasswordDialogVisible: false,
|
|
|
|
|
articlePasswordDialogVisible: false,
|
|
|
|
|
articlePassword: '',
|
|
|
|
|
articleId: ''
|
|
|
|
|
loginDialogVisible: false,// 登录对话框显示状态
|
|
|
|
|
registerDialogVisible: false,// 注册对话框显示状态
|
|
|
|
|
forgetPasswordDialogVisible: false,// 忘记密码对话框显示状态
|
|
|
|
|
articlePasswordDialogVisible: false,// 文章密码对话框显示状态
|
|
|
|
|
articlePassword: '',// 文章密码
|
|
|
|
|
articleId: '' // 文章ID
|
|
|
|
|
})
|
|
|
|
|
// 监听文章密码对话框显示事件
|
|
|
|
|
emitter.on('changeArticlePasswordDialogVisible', (articleId: any) => {
|
|
|
|
|
reactiveDate.articlePasswordDialogVisible = true
|
|
|
|
|
reactiveDate.articlePassword = ''
|
|
|
|
|
reactiveDate.articleId = articleId
|
|
|
|
|
// 下一帧聚焦密码输入框
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
document.getElementById('article-password-input')?.focus()
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
// 处理语言切换
|
|
|
|
|
const handleClick = (name: string): void => {
|
|
|
|
|
appStore.changeLocale(name)
|
|
|
|
|
}
|
|
|
|
|
// 登录处理
|
|
|
|
|
const login = () => {
|
|
|
|
|
if (loginInfo.username.trim().length == 0 || loginInfo.password.trim().length == 0) {
|
|
|
|
|
proxy.$notify({
|
|
|
|
|
@ -321,6 +358,7 @@ export default defineComponent({
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
// 暴露组件内部属性和方法供模板使用
|
|
|
|
|
return {
|
|
|
|
|
handleOpenModel,
|
|
|
|
|
loginInfo,
|
|
|
|
|
@ -340,6 +378,7 @@ export default defineComponent({
|
|
|
|
|
updatePassword,
|
|
|
|
|
openForgetPasswordDialog,
|
|
|
|
|
accessArticle,
|
|
|
|
|
// 计算属性:多语言配置
|
|
|
|
|
multiLanguage: computed(() => {
|
|
|
|
|
let websiteConfig: any = appStore.websiteConfig
|
|
|
|
|
return websiteConfig.multiLanguage
|
|
|
|
|
@ -351,39 +390,48 @@ export default defineComponent({
|
|
|
|
|
</script>
|
|
|
|
|
<style lang="scss">
|
|
|
|
|
.my-el-button {
|
|
|
|
|
// 自定义按钮样式
|
|
|
|
|
width: 300px !important;
|
|
|
|
|
}
|
|
|
|
|
.el-button {
|
|
|
|
|
width: 300px;
|
|
|
|
|
}
|
|
|
|
|
// 对话框头部按钮样式
|
|
|
|
|
.el-dialog__headerbtn {
|
|
|
|
|
outline: none !important;
|
|
|
|
|
}
|
|
|
|
|
// 输入框附加内容样式
|
|
|
|
|
.el-input-group__append {
|
|
|
|
|
background-color: var(--background-primary-alt) !important;
|
|
|
|
|
}
|
|
|
|
|
// 表单标签样式
|
|
|
|
|
.el-form-item__label {
|
|
|
|
|
text-align: left;
|
|
|
|
|
width: 70px;
|
|
|
|
|
color: var(--text-normal) !important;
|
|
|
|
|
}
|
|
|
|
|
.el-input__inner {
|
|
|
|
|
// 输入框内部样式
|
|
|
|
|
color: var(--text-normal) !important;
|
|
|
|
|
background-color: var(--background-primary-alt) !important;
|
|
|
|
|
}
|
|
|
|
|
// 输入框容器样式
|
|
|
|
|
.el-input__wrapper {
|
|
|
|
|
background: var(--background-primary-alt) !important;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
// 文本样式
|
|
|
|
|
.text {
|
|
|
|
|
color: var(--text-normal);
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
// 提交按钮样式
|
|
|
|
|
#submit-button {
|
|
|
|
|
outline: none;
|
|
|
|
|
background: #0fb6d6;
|
|
|
|
|
}
|
|
|
|
|
// 头部控制区域样式
|
|
|
|
|
.header-controls {
|
|
|
|
|
span {
|
|
|
|
|
display: flex;
|
|
|
|
|
@ -393,14 +441,17 @@ export default defineComponent({
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: opacity 250ms ease;
|
|
|
|
|
padding-right: 0.5rem;
|
|
|
|
|
// 无悬停效果样式
|
|
|
|
|
&[no-hover-effect] {
|
|
|
|
|
&:hover {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 悬停效果
|
|
|
|
|
&:hover {
|
|
|
|
|
opacity: 0.5;
|
|
|
|
|
}
|
|
|
|
|
// 图标样式
|
|
|
|
|
.svg-icon {
|
|
|
|
|
stroke: #fff;
|
|
|
|
|
height: 2rem;
|
|
|
|
|
|