mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-11-15 07:03:48 +08:00
【V3.5.0】1、【新增】轻量级定时任务 SmartJob;2、【新增】站内信;3、【新增】个人中心;4、【新增】岗位管理;5、【优化】部门员工管理
This commit is contained in:
@@ -1,24 +1,28 @@
|
||||
<!--
|
||||
* 头像
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-09-06 20:02:01
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-09-06 20:02:01
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
|
||||
<template>
|
||||
<a-dropdown class="header-trigger">
|
||||
<div class="wrapper">
|
||||
<a-avatar style="margin: 0 5px" :size="24" id="smartAdminAvatar">
|
||||
<img class="avatar-image" :src="avatar" v-if="avatar" />
|
||||
<a-avatar v-else style="margin: 0 5px" :size="20" id="smartAdminAvatar">
|
||||
{{ avatarName }}
|
||||
</a-avatar>
|
||||
<span class="name">{{ actualName }}</span>
|
||||
</div>
|
||||
<template #overlay>
|
||||
<a-menu :class="['avatar-menu']">
|
||||
<a-menu-item @click="showUpdatePwdModal">
|
||||
<a-menu-item @click="toAccount()">
|
||||
<span>个人中心</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="toAccount(ACCOUNT_MENU.PASSWORD.menuId)">
|
||||
<span>修改密码</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="onLogout">
|
||||
@@ -36,6 +40,8 @@
|
||||
import { localClear } from '/@/utils/local-util';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import HeaderResetPassword from './header-reset-password-modal/index.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ACCOUNT_MENU } from '/@/views/system/account/account-menu.js';
|
||||
|
||||
// 头像背景颜色
|
||||
const AVATAR_BACKGROUND_COLOR_ARRAY = ['#87d068', '#00B853', '#f56a00', '#1890ff'];
|
||||
@@ -53,6 +59,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------ 个人中心 ------------------------
|
||||
const router = useRouter();
|
||||
function toAccount(menuId) {
|
||||
router.push({
|
||||
path: '/account',
|
||||
query: { menuId },
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------ 修改密码 ------------------------
|
||||
const resetPasswordRef = ref();
|
||||
|
||||
@@ -63,7 +78,9 @@
|
||||
// ------------------------ 以下是 头像和姓名 相关 ------------------------
|
||||
|
||||
const avatarName = ref('');
|
||||
const avatar = computed(() => useUserStore().avatar);
|
||||
const actualName = computed(() => useUserStore().actualName);
|
||||
|
||||
// 更新头像信息
|
||||
function updateAvatar() {
|
||||
if (useUserStore().actualName) {
|
||||
@@ -98,7 +115,15 @@
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.avatar-image {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.header-trigger {
|
||||
height: @header-user-height;
|
||||
line-height: @header-user-height;
|
||||
|
||||
@@ -1,77 +1,65 @@
|
||||
<!--
|
||||
* 消息通知
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-09-06 20:17:18
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-09-06 20:17:18
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
|
||||
<template>
|
||||
<a-dropdown trigger="click" v-model:open="show">
|
||||
<div @click="fetchMessage">
|
||||
<a-badge count="12">
|
||||
<a-button type="text" @click="queryMessage" style="padding: 4px 5px">
|
||||
<a-badge :count="unreadMessageCount">
|
||||
<div style="width: 26px; height: 26px">
|
||||
<BellOutlined :style="{ fontSize: '18px' }" />
|
||||
<BellOutlined :style="{ fontSize: '16px' }" />
|
||||
</div>
|
||||
</a-badge>
|
||||
</div>
|
||||
</a-button>
|
||||
|
||||
<template #overlay>
|
||||
<div>
|
||||
<a-card class="message-container" :bodyStyle="{ padding: 0 }">
|
||||
<a-spin :spinning="loading">
|
||||
<a-tabs class="dropdown-tabs" centered :tabBarStyle="{ textAlign: 'center' }" style="width: 300px">
|
||||
<a-tab-pane tab="通知" key="1">
|
||||
<a-tab-pane tab="未读消息" key="message">
|
||||
<a-list class="tab-pane" size="small">
|
||||
<a-list-item>
|
||||
<a-list-item-meta description="7天前">
|
||||
<a-list-item v-for="item in messageList" :key="item.messageId">
|
||||
<a-list-item-meta>
|
||||
<template #title>
|
||||
<a href="#">今天洛阳天气39°c,洛阳变各阳...</a>
|
||||
<div class="title">
|
||||
<a @click="gotoMessage">{{ item.title }}</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar src="https://zhuoda.vip/images/blog/profile-128-128.jpg" />
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-list-item-meta description="7天前">
|
||||
<template #title>
|
||||
<a href="#">六月的雨 就是无情的你...</a>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar src="https://zhuoda.vip/images/blog/profile-128-128.jpg" />
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-list-item-meta description="7天前">
|
||||
<template #title>
|
||||
<a href="#">今年河南天气炎热,河南变可南...</a>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar src="https://zhuoda.vip/images/blog/profile-128-128.jpg" />
|
||||
<template #description>
|
||||
<span> {{ timeago(item.createTime) }}</span>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="消息" key="2">
|
||||
<a-list class="tab-pane" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="待办" key="3">
|
||||
<a-tab-pane tab="待办工作" key="todo">
|
||||
<a-list class="tab-pane" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-spin>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { BellOutlined } from '@ant-design/icons-vue';
|
||||
import { useUserStore } from '/@/store/modules/system/user.js';
|
||||
import { smartSentry } from '/@/lib/smart-sentry.js';
|
||||
import { messageApi } from '/@/api/support/message-api.js';
|
||||
import dayjs from 'dayjs';
|
||||
import { theme } from 'ant-design-vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const { useToken } = theme;
|
||||
const { token } = useToken();
|
||||
|
||||
defineExpose({ showMessage });
|
||||
|
||||
@@ -82,19 +70,97 @@
|
||||
const loading = ref(false);
|
||||
const show = ref(false);
|
||||
|
||||
const fetchMessage = () => {
|
||||
if (loading.value) {
|
||||
// ------------------------- 查询消息 -------------------------
|
||||
|
||||
// 未读消息
|
||||
const unreadMessageCount = computed(() => {
|
||||
return useUserStore().unreadMessageCount;
|
||||
});
|
||||
|
||||
// 消息列表
|
||||
const messageList = ref([]);
|
||||
|
||||
// 查询我的未读消息
|
||||
async function queryMessage() {
|
||||
try {
|
||||
loading.value = true;
|
||||
let responseModel = await messageApi.queryMessage({
|
||||
pageNum: 1,
|
||||
pageSize: 3,
|
||||
readFlag: false,
|
||||
});
|
||||
messageList.value = responseModel.data.list;
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 700);
|
||||
};
|
||||
}
|
||||
|
||||
const router = useRouter();
|
||||
function gotoMessage() {
|
||||
show.value = false;
|
||||
router.push({ path: '/account', query: { menuId: 'message' } });
|
||||
}
|
||||
|
||||
// ------------------------- 时间计算 -------------------------
|
||||
function timeago(dateStr) {
|
||||
let dateTimeStamp = dayjs(dateStr).toDate().getTime();
|
||||
let result = '';
|
||||
let minute = 1000 * 60; //把分,时,天,周,半个月,一个月用毫秒表示
|
||||
let hour = minute * 60;
|
||||
let day = hour * 24;
|
||||
let week = day * 7;
|
||||
let month = day * 30;
|
||||
let now = new Date().getTime(); //获取当前时间毫秒
|
||||
let diffValue = now - dateTimeStamp; //时间差
|
||||
|
||||
if (diffValue < 0) {
|
||||
return '刚刚';
|
||||
}
|
||||
let minC = diffValue / minute; //计算时间差的分,时,天,周,月
|
||||
let hourC = diffValue / hour;
|
||||
let dayC = diffValue / day;
|
||||
let weekC = diffValue / week;
|
||||
let monthC = diffValue / month;
|
||||
if (monthC >= 1 && monthC <= 3) {
|
||||
result = ' ' + parseInt(monthC) + '月前';
|
||||
} else if (weekC >= 1 && weekC <= 3) {
|
||||
result = ' ' + parseInt(weekC) + '周前';
|
||||
} else if (dayC >= 1 && dayC <= 6) {
|
||||
result = ' ' + parseInt(dayC) + '天前';
|
||||
} else if (hourC >= 1 && hourC <= 23) {
|
||||
result = ' ' + parseInt(hourC) + '小时前';
|
||||
} else if (minC >= 1 && minC <= 59) {
|
||||
result = ' ' + parseInt(minC) + '分钟前';
|
||||
} else if (diffValue >= 0 && diffValue <= minute) {
|
||||
result = '刚刚';
|
||||
} else {
|
||||
let datetime = new Date();
|
||||
datetime.setTime(dateTimeStamp);
|
||||
let year = datetime.getFullYear();
|
||||
let month = datetime.getMonth() + 1 < 10 ? '0' + (datetime.getMonth() + 1) : datetime.getMonth() + 1;
|
||||
let date = datetime.getDate() < 10 ? '0' + datetime.getDate() : datetime.getDate();
|
||||
result = year + '-' + month + '-' + date;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
<style lang="less" scoped>
|
||||
@smart-page-tag-operate-width: 40px;
|
||||
@color-primary: v-bind('token.colorPrimary');
|
||||
|
||||
.message-icon-div {
|
||||
cursor: pointer;
|
||||
height: 32px;
|
||||
width: 42px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.message-icon-div:hover {
|
||||
background: @hover-bg-color !important;
|
||||
}
|
||||
|
||||
.header-notice {
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
@@ -108,6 +174,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.message-container {
|
||||
border: #eeeeee solid 1px;
|
||||
}
|
||||
|
||||
.dropdown-tabs {
|
||||
background-color: @base-bg-color;
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -11,8 +11,13 @@
|
||||
<template>
|
||||
<a-drawer :title="$t('setting.title')" placement="right" :open="visible" @close="close">
|
||||
<a-form layout="horizontal" :label-col="{ span: 8 }">
|
||||
<a-form-item label="语言/Language">
|
||||
<a-select v-model:value="formState.language" @change="changeLanguage" style="width: 120px">
|
||||
<a-select-option v-for="item in i18nList" :key="item.value" :value="item.value">{{ item.text }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.color')">
|
||||
<div style="display: flex; align-items: center">
|
||||
<div class="color-container">
|
||||
<template v-for="(item, index) in themeColors">
|
||||
<div v-if="index === formState.colorIndex" class="color">
|
||||
<CheckSquareFilled :style="{ color: item.primaryColor, fontSize: '22px' }" />
|
||||
@@ -38,6 +43,14 @@
|
||||
<a-form-item :label="$t('setting.border.radius')">
|
||||
<a-slider v-model:value="formState.borderRadius" :min="0" :max="6" @change="changeBorderRadius" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.menu.width')" v-if="formState.layout === LAYOUT_ENUM.SIDE.value">
|
||||
<a-input-number @change="changeSideMenuWidth" v-model:value="formState.sideMenuWidth" :min="1" />
|
||||
像素(px)
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.page.width')" v-if="formState.layout === LAYOUT_ENUM.TOP.value">
|
||||
<a-input @change="changePageWidth" v-model:value="formState.pageWidth" />
|
||||
像素(px)或者 百分比
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.compact')">
|
||||
<a-radio-group v-model:value="formState.compactFlag" button-style="solid" @change="changeCompactFlag">
|
||||
<a-radio-button :value="false">默认</a-radio-button>
|
||||
@@ -57,35 +70,39 @@
|
||||
<a-radio-button value="light">Light</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.menu.width')" v-if="formState.layout === LAYOUT_ENUM.SIDE.value">
|
||||
<a-input-number @change="changeSideMenuWidth" v-model:value="formState.sideMenuWidth" :min="1" />
|
||||
像素(px)
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.page.width')" v-if="formState.layout === LAYOUT_ENUM.TOP.value">
|
||||
<a-input @change="changePageWidth" v-model:value="formState.pageWidth" />
|
||||
像素(px)或者 百分比
|
||||
</a-form-item>
|
||||
<a-form-item label="语言/Language">
|
||||
<a-select v-model:value="formState.language" @change="changeLanguage" style="width: 120px">
|
||||
<a-select-option v-for="item in i18nList" :key="item.value" :value="item.value">{{ item.text }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.bread')">
|
||||
<a-switch @change="changeBreadCrumbFlag" v-model:checked="formState.breadCrumbFlag" checked-children="显示" un-checked-children="隐藏" />
|
||||
<a-form-item :label="$t('setting.pagetag.style')">
|
||||
<a-radio-group v-model:value="formState.pageTagStyle" button-style="solid" @change="changePageTagStyle">
|
||||
<a-radio-button value="default">默认</a-radio-button>
|
||||
<a-radio-button value="antd">Ant Design</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.pagetag')">
|
||||
<a-switch @change="changePageTagFlag" v-model:checked="formState.pageTagFlag" checked-children="显示" un-checked-children="隐藏" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.bread')">
|
||||
<a-switch @change="changeBreadCrumbFlag" v-model:checked="formState.breadCrumbFlag" checked-children="显示" un-checked-children="隐藏" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.footer')">
|
||||
<a-switch @change="changeFooterFlag" v-model:checked="formState.footerFlag" checked-children="显示" un-checked-children="隐藏" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.helpdoc')">
|
||||
<a-switch @change="changeHelpDocFlag" v-model:checked="formState.helpDocFlag" checked-children="显示" un-checked-children="隐藏" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.watermark')">
|
||||
<a-switch @change="changeWatermarkFlag" v-model:checked="formState.watermarkFlag" checked-children="显示" un-checked-children="隐藏" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.helpdoc')">
|
||||
<a-switch @change="changeHelpDocFlag" v-model:checked="formState.helpDocFlag" checked-children="显示" un-checked-children="隐藏" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.helpdoc.expand')" v-if="formState.helpDocFlag">
|
||||
<a-switch
|
||||
@change="changeHelpDocExpandFlag"
|
||||
v-model:checked="formState.helpDocExpandFlag"
|
||||
checked-children="默认展开"
|
||||
un-checked-children="默认不展开"
|
||||
/>
|
||||
</a-form-item>
|
||||
<br />
|
||||
<br />
|
||||
</a-form>
|
||||
|
||||
<div class="footer">
|
||||
<a-button style="margin-right: 8px" type="primary" @click="copy">复制配置信息</a-button>
|
||||
<a-button type="block" danger @click="reset">恢复默认配置 </a-button>
|
||||
@@ -176,12 +193,16 @@
|
||||
borderRadius: appConfigStore.borderRadius,
|
||||
// 标签页
|
||||
pageTagFlag: appConfigStore.pageTagFlag,
|
||||
// 标签页 样式
|
||||
pageTagStyle: appConfigStore.pageTagStyle,
|
||||
// 面包屑
|
||||
breadCrumbFlag: appConfigStore.breadCrumbFlag,
|
||||
// 页脚
|
||||
footerFlag: appConfigStore.footerFlag,
|
||||
// 帮助文档
|
||||
helpDocFlag: appConfigStore.helpDocFlag,
|
||||
// 帮助文档 默认展开
|
||||
helpDocExpandFlag: appConfigStore.helpDocExpandFlag,
|
||||
// 水印
|
||||
watermarkFlag: appConfigStore.watermarkFlag,
|
||||
};
|
||||
@@ -250,6 +271,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
function changePageTagStyle(e) {
|
||||
appConfigStore.$patch({
|
||||
pageTagStyle: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
function changeFooterFlag(e) {
|
||||
appConfigStore.$patch({
|
||||
footerFlag: e,
|
||||
@@ -262,6 +289,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
function changeHelpDocExpandFlag(e) {
|
||||
appConfigStore.$patch({
|
||||
helpDocExpandFlag: e,
|
||||
});
|
||||
}
|
||||
|
||||
function changeWatermarkFlag(e) {
|
||||
appConfigStore.$patch({
|
||||
watermarkFlag: e,
|
||||
@@ -281,9 +314,14 @@
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.color-container {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.color {
|
||||
margin-left: 8px;
|
||||
display: inline;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
display: flex;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!--
|
||||
* 头部一整行
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-09-06 20:18:20
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-09-06 20:18:20
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-space :size="10">
|
||||
@@ -34,9 +34,9 @@
|
||||
<HeaderAvatar />
|
||||
</div>
|
||||
<!---帮助文档--->
|
||||
<div class="user-space-item" @click="showHelpDoc" v-if="!showHelpDocFlag">
|
||||
<div class="user-space-item" @click="showHelpDoc" v-if="showHelpDocFlag">
|
||||
<span>帮助文档</span>
|
||||
<DoubleLeftOutlined v-if="!showHelpDocFlag" />
|
||||
<DoubleLeftOutlined v-if="!helpDocExpandFlag" />
|
||||
</div>
|
||||
|
||||
<HeaderSetting ref="headerSetting" />
|
||||
@@ -72,6 +72,10 @@
|
||||
return useAppConfigStore().helpDocFlag;
|
||||
});
|
||||
|
||||
const helpDocExpandFlag = computed(() => {
|
||||
return useAppConfigStore().helpDocExpandFlag;
|
||||
});
|
||||
|
||||
//搜索
|
||||
function search() {
|
||||
window.open('https://1024lab.net');
|
||||
@@ -100,7 +104,7 @@
|
||||
|
||||
.user-space-item:hover {
|
||||
color: v-bind('token.colorPrimary');
|
||||
background: @hover-bg-color;
|
||||
background-color: @hover-bg-color !important;
|
||||
}
|
||||
|
||||
.setting {
|
||||
|
||||
Reference in New Issue
Block a user