Files
boursecu_admin/src/core/layouts/BasicHeader.vue
T
2026-07-30 18:30:32 +03:30

319 lines
10 KiB
Vue

<template>
<ALayoutHeader
:theme="menuTheme"
:class="[prefixCls]"
:style="`height:${layoutStore.header.height}`"
>
<!-- :style="`height:${layoutStore.header.height};line-height:${layoutStore.header.height}`"-->
<div class="flex w-full min-w-0 items-center gap-2 overflow-hidden">
<div class="header-menu-zone flex min-w-0 flex-1 items-center overflow-hidden">
<img :src="getConfigApp('avatar')" style="height: 38px" class="mr-5 mt-1 shrink-0" />
<BaseButton
type="text"
icon="vuesax-linear:menu"
@click="handleCollapseSideMenu"
v-if="layoutStore.layout == 'side'"
class="shrink-0"
/>
<BasicMenu />
</div>
<div class="header-actions flex shrink-0 items-center gap-2">
<SmsCreditWidget variant="desktop" class="header-actions__credit min-w-0" />
<div class="header-actions__fixed flex shrink-0 items-center gap-3">
<button
v-if="supportChatEnabled"
type="button"
class="flex cursor-pointer items-center justify-center rounded-full border-0 bg-transparent text-[var(--admin-text-secondary)] transition-colors hover:opacity-80"
aria-label="چت پشتیبانی"
@click="goToSupport"
>
<a-badge
:count="totalUnreadCount"
:overflow-count="99"
:show-zero="false"
>
<span class="inline-flex items-center justify-center">
<Icon icon="vuesax-linear:messages-2" size="22" />
</span>
</a-badge>
</button>
<ADropdown placement="bottomLeft" class="ml-5">
<a class="ant-dropdown-link" @click.prevent>
<!-- Hover me-->
<div class="flex items-center gap-1 text-[var(--admin-text-secondary)]">
<AAvatar :src="placeholderM" class="header-avatar" />
<Icon icon="vuesax-linear:arrow-down" size="15" />
</div>
</a>
<template #overlay>
<AMenu>
<AMenuItem>
<div class="flex flex-col">
<span class="font-bold">{{ userStore.userInfo?.name }}</span>
<span>{{ userStore.userInfo?.post_user }}</span>
</div>
</AMenuItem>
<AMenuDivider />
<ThemeMenuSection />
<AMenuItem @click="myInfoVisible = true">
<div class="flex items-center gap-1">
<Icon icon="vuesax-linear:profile" size="18" />
<span>اطلاعات حساب کاربری</span>
</div>
</AMenuItem>
<AMenuItem @click="clearLocalStorage">
<div class="flex items-center gap-1">
<Icon icon="vuesax-linear:logout" size="18" />
<span>خروج</span>
</div>
</AMenuItem>
</AMenu>
</template>
</ADropdown>
<!-- todo remove -->
<div class="w-2"></div>
<BaseButton
iconSize="20"
icon="vuesax-linear:setting"
type="text"
v-if="layoutStore.showSettingsIcon"
@click="handleShowSettings"
/>
</div>
</div>
</div>
<BasicModal
v-model:visible="myInfoVisible"
width="40rem"
title="اطلاعات حساب کاربری"
@ok="ok"
:loading="loading"
@close="myInfoVisible = false"
>
<a-form :model="form" ref="formRef" autocomplete="off">
<div class="grid md:grid-cols-2 gap-4">
<a-form-item label="نام" name="fname" :rules="inputRules()">
<BasicInput v-model:value="form.fname" />
</a-form-item>
<a-form-item label="نام خانوادگی" name="lname" :rules="inputRules()">
<BasicInput v-model:value="form.lname" />
</a-form-item>
<a-form-item label="شماره موبایل" name="mobile" :rules="inputLenRules(11)">
<BasicInput v-model:value="form.mobile" type="number" />
</a-form-item>
<a-form-item label="رمز کاربری" name="password">
<BasicInput type="password" v-model:value="form.password" />
</a-form-item>
</div>
</a-form>
</BasicModal>
<!-- this is admin header-->
<!-- <div :class="['admin-header-wide', layout, pageWidth]">
<router-link
v-if="isMobile || layout === 'head'"
to="/"s
:class="['logo', isMobile ? null : 'pc', headerTheme]"
>
<img width="32" src="@/assets/img/logo.png" />
<h1 v-if="!isMobile">{{ systemName }}</h1>
</router-link>
<a-divider v-if="isMobile" type="vertical" />
<a-icon
v-if="layout !== 'head'"
class="trigger"
:type="collapsed ? 'menu-unfold' : 'menu-fold'"
@click="toggleCollapse"
/>
<div
v-if="layout !== 'side' && !isMobile"
class="admin-header-menu"
:style="`width: ${menuWidth};`"
>
<i-menu
class="head-menu"
:theme="headerTheme"
mode="horizontal"
:options="menuData"
@select="onSelect"
/>
</div>
<div :class="['admin-header-right', headerTheme]">
<header-search class="header-item" @active="(val) => (searchActive = val)" />
<a-tooltip class="header-item" title="帮助文档" placement="bottom">
<a href="https://iczer.gitee.io/vue-antd-admin-docs/" target="_blank">
<a-icon type="question-circle-o" />
</a>
</a-tooltip>
<header-notice class="header-item" />
<header-avatar class="header-item" />
<a-dropdown class="lang header-item">
<div><a-icon type="global" /> {{ langAlias }}</div>
<a-menu @click="(val) => setLang(val.key)" :selected-keys="[lang]" slot="overlay">
<a-menu-item v-for="lang in langList" :key="lang.key">{{
lang.key.toLowerCase() + ' ' + lang.name
}}</a-menu-item>
</a-menu>
</a-dropdown>
</div>
</div>-->
</ALayoutHeader>
</template>
<script lang="ts" setup>
import { usePrefix } from '@core/composable/usePrefix'
import SmsCreditWidget from '@/components/SmsCreditWidget.vue'
import { useLayoutStore } from '@core/stores/layout'
import BasicMenu from '@core/layouts/composnts/BasicMenu.vue'
import placeholderM from '@core/assets/img/avatars/placeholder-m.jpg'
import Icon from '@core/components/BaseIcon/src/Icon.vue'
import { useSettingsStore } from '@core/stores/settings'
import { useStaticApiListsStore } from '@/store/staticApisStore'
import { useUserStore } from '@/store/userStore'
import { inputRules, inputLenRules } from '@/utils/inputRules'
import type { User } from '@/model/user'
import { createUser, updateMyInformation, updateUser } from '@/api/user'
import { message } from 'ant-design-vue/es'
import { onMounted, ref, computed } from 'vue'
import type { FormInstance } from 'ant-design-vue'
import { cloneDeep } from 'lodash'
import { useWindowSize } from '@vueuse/core'
import {getConfigApp} from "@/utils/config";
import ThemeMenuSection from '@core/components/ThemeMenuSection.vue'
import { useAdminTheme } from '@core/composable/useAdminTheme'
import { useAdminChatService } from '@/utils/adminChat'
import { supportChatMenuEnabledSetting } from '@/utils/config'
const { prefixCls } = usePrefix('basic-header')
const layoutStore = useLayoutStore()
const store = useStaticApiListsStore()
const userStore = useUserStore()
const settingsStore = useSettingsStore()
const { menuTheme } = useAdminTheme()
const router = useRouter()
const { totalUnreadCount } = useAdminChatService()
const supportChatEnabled = computed(() => supportChatMenuEnabledSetting.value)
function goToSupport() {
router.push({ name: 'supportMain' })
}
const { width } = useWindowSize()
//my info modal
const loading = ref<boolean>(false)
const myInfoVisible = ref<boolean>(false)
const formRef = ref<FormInstance>()
const form = ref<User>({
fname: '',
lname: '',
mobile: '',
post_user: '',
manager_id: '',
responsible_id: '',
section: '',
section_id: undefined,
process_id: '',
qc_id: undefined,
user_type: undefined,
permission: []
})
onMounted(() => {
form.value = cloneDeep(userStore?.userInfo) as User
})
//submit user
async function ok() {
formRef.value?.validateFields().then(async () => {
loading.value = true
try {
await updateMyInformation(form.value)
userStore.getMyInfo()
message.success('اطلاعات با موفقیت ویرایش شد')
myInfoVisible.value = false
} catch (e) {
// message.error('خطا در بارگذاری اطلاعات')
console.error(e)
} finally {
loading.value = false
}
})
}
//const temp = 12
function handleCollapseSideMenu() {
layoutStore.sideMenu.collapsed = !layoutStore.sideMenu.collapsed
}
function handleShowSettings() {
settingsStore.showSettingsDrawer = !settingsStore.showSettingsDrawer
}
function clearLocalStorage() {
const colorSchema = localStorage.getItem('color-schema')
localStorage.clear()
if (colorSchema) {
localStorage.setItem('color-schema', colorSchema)
}
location.reload()
}
</script>
<style lang="less">
@prefix: ~'@{prefixCls}-basic-header';
.@{prefix} {
padding: 0 12px !important;
line-height: normal !important;
overflow: hidden;
max-width: 100%;
display: flex;
align-items: center;
border-bottom: 1px solid var(--admin-border);
background-color: var(--admin-bg-surface);
> .flex {
height: 100%;
align-items: center;
}
.header-menu-zone {
position: relative;
z-index: 2;
min-width: 0;
flex: 1 1 0%;
overflow: hidden;
}
.header-actions {
position: relative;
z-index: 3;
flex-shrink: 0;
background: var(--admin-bg-surface);
padding-inline-start: 4px;
}
.header-actions__credit {
max-width: min(220px, 38vw);
}
.header-avatar {
border: 2px solid var(--admin-border-strong);
}
.hr-tamin-base-button.ant-btn-text {
color: var(--admin-text-secondary);
background: transparent !important;
border-color: transparent !important;
box-shadow: none !important;
&:hover,
&:focus {
color: var(--admin-text);
background: var(--admin-bg-hover) !important;
}
}
}
</style>