Commit 3214856b by 郑艺斌

fix: 新增消息中心模块

parent d8e6cfad
import request from "@/utils/httpRequest";
export default class Message {
// 消息列表
getMessagePage(data) {
return request({
url: `/message/pageList`,
method: "post",
data,
});
}
// 阅读
seeRead(id) {
return request({
url: `/message/read`,
method: "post",
params: { id: id },
});
}
// 全部已读
setReadAll(data) {
return request({
url: `/message/readAll`,
method: "post",
data,
});
}
// 获取消息类型未读数量
getMessageTypeCount(id) {
return request({
url: `/message/typeCount`,
method: "post",
params: { userId: id },
});
}
// 消息总未读数量
getMessageCount(id) {
return request({
url: `/message/count`,
method: "post",
params: { userId: id },
});
}
}
......@@ -2,104 +2,180 @@
* 全站路由配置
* 代码中路由统一使用path属性跳转
*/
import Vue from 'vue'
import Router from 'vue-router'
import {isURL} from '@/utils/validate'
import {clearLoginInfo} from '@/utils'
import Vue from "vue";
import Router from "vue-router";
import { isURL } from "@/utils/validate";
import { clearLoginInfo } from "@/utils";
Vue.use(Router)
Vue.use(Router);
const routerPush = Router.prototype.push
Router.prototype.push = function push (location) {
return routerPush.call(this, location).catch(error => error)
}
const routerPush = Router.prototype.push;
Router.prototype.push = function push(location) {
return routerPush.call(this, location).catch((error) => error);
};
// 开发环境不使用懒加载
const _import = require('./import-' + process.env.NODE_ENV)
const _import = require("./import-" + process.env.NODE_ENV);
// 全局路由
const globalRoutes = [
{path: '/login', component: _import('modules/sys/login/login'), name: 'login', meta: {title: '登录'}},
{path: '/casLogin', component: _import('common/CasLogin'), name: 'casLogin', meta: { title: 'CAS登录' }}
]
{
path: "/login",
component: _import("modules/sys/login/login"),
name: "login",
meta: { title: "登录" },
},
{
path: "/casLogin",
component: _import("common/CasLogin"),
name: "casLogin",
meta: { title: "CAS登录" },
},
];
// 主入口路由
const mainRoutes = {
path: '/',
component: _import('main'),
name: 'main',
redirect: {name: 'home'},
meta: {title: '整体布局'},
path: "/",
component: _import("main"),
name: "main",
redirect: { name: "home" },
meta: { title: "整体布局" },
children: [
{path: '/redirect/:path(.*)', component: _import('modules/redirect/index')},
{path: '/home', redirect: '/sys/dashboard/analysis/index', name: 'home'},
{path: '/flowable/task/TaskForm', component: _import('modules/flowable/task/TaskForm'), name: 'task-form', meta: {title: '流程表单'}},
{path: '/flowable/task/TaskFormEdit', component: _import('modules/flowable/task/TaskFormEdit'), name: 'task-form-edit', meta: {title: '流程表单'}},
{path: '/flowable/task/TaskFormDetail', component: _import('modules/flowable/task/TaskFormDetail'), name: 'task-form-detail', meta: {title: '流程表单详情'}},
{path: '/form/generateList', component: _import('modules/form/GenerateList'), name: 'form-preview-list', meta: {title: '列表'}},
{path: '/echarts/GenerateChart', component: _import('modules/echarts/GenerateChart'), name: 'echarts-generate', meta: {title: '预览图表'}},
{path: '/ureport/designer', component: null, name: 'ureport-designer', meta: {title: '预览报表', type: 'iframe', menuId: 'ureport-designer'}},
{path: '/ureport/preview', component: null, name: 'ureport-preview', meta: {title: '预览报表', type: 'iframe', menuId: 'ureport-preview'}},
{path: '/form/explorer', component: null, name: 'form-explorer', meta: {title: '浏览器', type: 'iframe'}},
{path: '/database/datatable/TableForm', component: _import('modules/database/datatable/TableForm'), name: 'table-form', meta: {title: '数据库表详情'}},
{path: '/404', component: _import('common/404'), name: '404', meta: {title: '404未找到'}}
]
}
{
path: "/redirect/:path(.*)",
component: _import("modules/redirect/index"),
},
{ path: "/home", redirect: "/sys/dashboard/analysis/index", name: "home" },
{
path: "/flowable/task/TaskForm",
component: _import("modules/flowable/task/TaskForm"),
name: "task-form",
meta: { title: "流程表单" },
},
{
path: "/flowable/task/TaskFormEdit",
component: _import("modules/flowable/task/TaskFormEdit"),
name: "task-form-edit",
meta: { title: "流程表单" },
},
{
path: "/flowable/task/TaskFormDetail",
component: _import("modules/flowable/task/TaskFormDetail"),
name: "task-form-detail",
meta: { title: "流程表单详情" },
},
{
path: "/form/generateList",
component: _import("modules/form/GenerateList"),
name: "form-preview-list",
meta: { title: "列表" },
},
{
path: "/message",
component: _import("modules/message/index"),
name: "message",
meta: { title: "消息中心" },
},
{
path: "/echarts/GenerateChart",
component: _import("modules/echarts/GenerateChart"),
name: "echarts-generate",
meta: { title: "预览图表" },
},
{
path: "/ureport/designer",
component: null,
name: "ureport-designer",
meta: { title: "预览报表", type: "iframe", menuId: "ureport-designer" },
},
{
path: "/ureport/preview",
component: null,
name: "ureport-preview",
meta: { title: "预览报表", type: "iframe", menuId: "ureport-preview" },
},
{
path: "/form/explorer",
component: null,
name: "form-explorer",
meta: { title: "浏览器", type: "iframe" },
},
{
path: "/database/datatable/TableForm",
component: _import("modules/database/datatable/TableForm"),
name: "table-form",
meta: { title: "数据库表详情" },
},
{
path: "/404",
component: _import("common/404"),
name: "404",
meta: { title: "404未找到" },
},
],
};
const router = new Router({
mode: 'hash',
scrollBehavior: () => ({y: 0}),
mode: "hash",
scrollBehavior: () => ({ y: 0 }),
isAddDynamicMenuRoutes: false, // 是否已经添加动态(菜单)路由
routes: globalRoutes.concat(mainRoutes)
})
routes: globalRoutes.concat(mainRoutes),
});
// 添加动态(菜单)路由
// 添加动态(菜单)路由
router.beforeEach((to, from, next) => {
let token = Vue.cookie.get('token')
if (!token || !/\S/.test(token)) { // token为空,跳转到login登录
clearLoginInfo()
if (process.env.VUE_APP_SSO_LOGIN === 'true') { // 如果是单点登录
if (to.name === 'casLogin') { // 单点登录跳转页面获取token
next()
let token = Vue.cookie.get("token");
if (!token || !/\S/.test(token)) {
// token为空,跳转到login登录
clearLoginInfo();
if (process.env.VUE_APP_SSO_LOGIN === "true") {
// 如果是单点登录
if (to.name === "casLogin") {
// 单点登录跳转页面获取token
next();
} else {
window.location.href = `${process.env.VUE_APP_CAS_SERVER}/login?service=${process.env.VUE_APP_CLIENT_LOGIN}`
window.location.href = `${process.env.VUE_APP_CAS_SERVER}/login?service=${process.env.VUE_APP_CLIENT_LOGIN}`;
}
} else {
if (fnCurrentRouteType(to, globalRoutes) === 'global') {
next()
if (fnCurrentRouteType(to, globalRoutes) === "global") {
next();
} else {
next({name: 'login'})
next({ name: "login" });
}
}
} else if (router.options.isAddDynamicMenuRoutes) { // 如果已经包含权限
next()
} else { // 请求权限
let routerList = localStorage.getItem('routerList')
} else if (router.options.isAddDynamicMenuRoutes) {
// 如果已经包含权限
next();
} else {
// 请求权限
let routerList = localStorage.getItem("routerList");
if (routerList) {
router.options.isAddDynamicMenuRoutes = true
fnAddDynamicMenuRoutes(JSON.parse(routerList), [])
next({...to, replace: true})
router.options.isAddDynamicMenuRoutes = true;
fnAddDynamicMenuRoutes(JSON.parse(routerList), []);
next({ ...to, replace: true });
} else {
clearLoginInfo()
next()
console.log(`请求菜单列表和权限失败,跳转至登录页!!`, 'color:blue')
clearLoginInfo();
next();
console.log(`请求菜单列表和权限失败,跳转至登录页!!`, "color:blue");
}
}
})
});
/**
* 判断当前路由类型, global: 全局路由, main: 主入口路由
* @param {*} route 当前路由
*/
function fnCurrentRouteType (route, globalRoutes = []) {
let temp = []
function fnCurrentRouteType(route, globalRoutes = []) {
let temp = [];
for (let i = 0; i < globalRoutes.length; i++) {
if (route.path === globalRoutes[i].path) {
return 'global'
} else if (globalRoutes[i].children && globalRoutes[i].children.length >= 1) {
temp = temp.concat(globalRoutes[i].children)
return "global";
} else if (
globalRoutes[i].children &&
globalRoutes[i].children.length >= 1
) {
temp = temp.concat(globalRoutes[i].children);
}
}
return temp.length >= 1 ? fnCurrentRouteType(route, temp) : 'main'
return temp.length >= 1 ? fnCurrentRouteType(route, temp) : "main";
}
/**
......@@ -108,65 +184,75 @@ function fnCurrentRouteType (route, globalRoutes = []) {
* @param {*} routes 递归创建的动态(菜单)路由
*/
// eslint-disable-next-line no-unused-vars
function fnAddDynamicMenuRoutes (menuList = [], routes = []) {
let temp = []
function fnAddDynamicMenuRoutes(menuList = [], routes = []) {
let temp = [];
for (let i = 0; i < menuList.length; i++) {
if (menuList[i].children && menuList[i].children.length >= 1) {
temp = temp.concat(menuList[i].children)
temp = temp.concat(menuList[i].children);
}
if (menuList[i].href && /\S/.test(menuList[i].href)) {
menuList[i].href = menuList[i].href.replace(/[/]$/, '')
menuList[i].href = menuList[i].href.replace(/[/]$/, "");
const route = {
path: menuList[i].href.split('?')[0],
path: menuList[i].href.split("?")[0],
component: null,
name: menuList[i].href.replace(/^\//g, '').replace(/[/]/g, '-').replace(/[?]/g, '-').replace(/&/g, '-').replace(/=/g, '-'),
name: menuList[i].href
.replace(/^\//g, "")
.replace(/[/]/g, "-")
.replace(/[?]/g, "-")
.replace(/&/g, "-")
.replace(/=/g, "-"),
meta: {
parentIds: menuList[i].parentIds,
menuId: menuList[i].id,
title: menuList[i].name,
isDynamic: true,
type: menuList[i].target,
affix: menuList[i].affix === '1',
iframeUrl: ''
}
}
affix: menuList[i].affix === "1",
iframeUrl: "",
},
};
// url以http[s]://开头, 通过iframe展示
if (menuList[i].target === 'iframe') {
route.path = '/' + route.meta.menuId
if (menuList[i].target === "iframe") {
route.path = "/" + route.meta.menuId;
if (isURL(menuList[i].href)) {
route['meta']['iframeUrl'] = menuList[i].href
route["meta"]["iframeUrl"] = menuList[i].href;
} else {
route['meta']['iframeUrl'] = `${process.env.VUE_APP_SERVER_URL}${menuList[i].href}`
route["meta"][
"iframeUrl"
] = `${process.env.VUE_APP_SERVER_URL}${menuList[i].href}`;
}
} else {
try {
if (menuList[i].href) {
route['component'] = _import(`modules${menuList[i].href.split('?')[0]}`) || null
route["component"] =
_import(`modules${menuList[i].href.split("?")[0]}`) || null;
}
} catch (e) {
console.log(e)
console.log(e);
}
}
let exist = routes.filter(r =>
r.path === route.path
).length === 0 && mainRoutes.children.filter(c =>
c.path === route.path
).length === 0
if (exist) { // 如果路由不存在则添加
routes.push(route)
let exist =
routes.filter((r) => r.path === route.path).length === 0 &&
mainRoutes.children.filter((c) => c.path === route.path).length === 0;
if (exist) {
// 如果路由不存在则添加
routes.push(route);
}
}
}
if (temp.length >= 1) {
fnAddDynamicMenuRoutes(temp, routes)
fnAddDynamicMenuRoutes(temp, routes);
} else {
mainRoutes.name = 'main-dynamic'
mainRoutes.children = routes
router.addRoute(mainRoutes)
router.addRoute({path: '*', redirect: {name: '404'}})
localStorage.setItem('dynamicMenuRoutes', JSON.stringify(mainRoutes.children || []))
mainRoutes.name = "main-dynamic";
mainRoutes.children = routes;
router.addRoute(mainRoutes);
router.addRoute({ path: "*", redirect: { name: "404" } });
localStorage.setItem(
"dynamicMenuRoutes",
JSON.stringify(mainRoutes.children || [])
);
}
}
export default router
export default router;
export default {
namespaced: true,
state: {
id: '',
name: '',
loginName: '',
no: '',
id: "",
name: "",
loginName: "",
no: "",
office: {
id: '',
name: ''
id: "",
name: "",
},
company: {
id: '',
name: ''
id: "",
name: "",
},
photo: ''
photo: "",
messageCount: {},
},
mutations: {
updateId (state, id) {
state.id = id
},
updateName (state, name) {
state.name = name
},
updateLoginName (state, loginName) {
state.loginName = loginName
},
updatePhoto (state, photo) {
state.photo = photo
},
updateUser (state, user) {
state.id = user.id
state.name = user.name
state.loginName = user.loginName
state.company = user.companyDTO
state.office = user.officeDTO
state.no = user.no
state.photo = user.photo
localStorage.setItem('user', JSON.stringify(user))
}
}
}
updateId(state, id) {
state.id = id;
},
updateName(state, name) {
state.name = name;
},
updateLoginName(state, loginName) {
state.loginName = loginName;
},
updatePhoto(state, photo) {
state.photo = photo;
},
updateUser(state, user) {
state.id = user.id;
state.name = user.name;
state.loginName = user.loginName;
state.company = user.companyDTO;
state.office = user.officeDTO;
state.no = user.no;
state.photo = user.photo;
localStorage.setItem("user", JSON.stringify(user));
},
updateMessageCount(state, messageCount) {
state.messageCount = messageCount;
},
},
};
......@@ -60,6 +60,12 @@
</el-menu-item>
<el-menu-item class="hide-sm">
<template slot="title">
<div class="noticeButton" @click="goMessage">
<el-badge v-if="messageCount.total != 0" :value="messageCount.total" class="badge">
<i class="fa fa-bell-o"></i>
</el-badge>
<i class="fa fa-bell-o" v-else></i>
</div>
<!-- <notice-icon class="action notice" :tabs="noticeTabs">
</notice-icon> -->
</template>
......@@ -96,6 +102,8 @@ import ColorPicker from '@/components/colors/ColorPicker'
import NotifyService from '@/api/notify/NotifyService'
import MailBoxService from '@/api/mail/MailBoxService'
import LoginService from '@/api/auth/LoginService'
import Message from '@/api/message/index'
export default {
data () {
return {
......@@ -123,7 +131,8 @@ export default {
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg'
}
],
breadcrumbs: []
breadcrumbs: [],
user: JSON.parse(localStorage.getItem('user')),
}
},
components: {
......@@ -140,6 +149,11 @@ export default {
this.loginService = new LoginService()
},
computed: {
messageCount: {
get () {
return this.$store.state.user.messageCount
},
},
navbarLayoutType () {
return this.$store.state.common.navbarLayoutType
},
......@@ -228,6 +242,7 @@ export default {
})
},
mounted () {
this.getMessageCount()
if (this.defaultLayout === 'top') {
this.fixTopMenu()
}
......@@ -291,6 +306,9 @@ export default {
}
},
methods: {
goMessage () {
this.$router.push({ name: "message" })
},
// 获取路由名字
getTitle (menus, id, obj) {
menus.forEach((menu) => {
......@@ -349,3 +367,16 @@ export default {
}
}
</script>
<style lang="scss" scoped>
.noticeButton {
width: 100%;
height: 100%;
padding: 0 12px;
display: flex;
align-items: center;
transition: all 0.3s;
}
</style>
<template>
<div class="jp-common-layout page">
<div class="jp-common-layout-left">
<el-row class="rowTabs">
<div v-for="item in tabs" :class="{ rowItem: true, rowActive: item.value == tabsActive }" :key="item.value"
@click="clickTabsItem(item)">
<div class="name">{{item.label}}</div>
<div class="number">{{item.total}}</div>
</div>
</el-row>
</div>
<div class="jp-common-layout-center jp-flex-main">
<div class="bg-white" style="height: 100%;">
<div style="height: calc(100% - 30px);" v-if="tableData.length">
<div class="list">
<div class="list-item" v-for="item in tableData">
<div class="item-left">
<div class="title" :title="item.title">{{item.title}}</div>
<div class="subTitle" :title="item.subTitle">{{item.subTitle}},</div>
<div class="content" :title="item.content">异常内容:{{item.content}}</div>
<div class="date">{{item.createDate}} - 系统发送</div>
</div>
<div class="item-right">
<div v-if="item.readFlag=='0'" @click="setRead(item)"><i class="el-icon-check"
style="margin-right: 2px;"></i>设置已读</div>
<div v-else style="color: #00AFAB;">已读</div>
</div>
</div>
</div>
<div class="footer">
<el-button type="primary" size="small" icon="el-icon-view" @click="seeReadAll">全部设置为已读</el-button>
<vxe-pager background size="small" :current-page="tablePage.currentPage" :page-size="tablePage.pageSize"
:total="tablePage.total" :page-sizes="[10, 20, 100, 1000, { label: '全量数据', value: 1000000 }]"
:layouts="['PrevPage', 'JumpNumber', 'NextPage', 'FullJump', 'Sizes', 'Total']"
@page-change="currentChangeHandle">
</vxe-pager>
</div>
</div>
<div v-else style="height: 100%;display: flex; align-items: center;justify-content: center;">
<el-empty :image-size="200"></el-empty>
</div>
</div>
</div>
</div>
</template>
<script>
import Message from '@/api/message/index'
export default {
Message: null,
name: '',
data () {
return {
searchForm: {
name: '',
},
tableData: [],
loading: false,
tablePage: {
total: 0,
currentPage: 1,
pageSize: 10,
},
tabsActive: '-1',
user: JSON.parse(localStorage.getItem('user')),
tabs: []
}
},
watch: {},
computed: {
},
methods: {
// 切换点击
clickTabsItem (item) {
this.tabsActive = item.value
this.getMessagePage()
},
// 获取列表
getMessagePage () {
this.loading = true
const can = {
userId: this.user.loginName,
type: this.tabsActive,
current: this.tablePage.currentPage,
size: this.tablePage.pageSize
}
this.Message.getMessagePage(can).then(({ data }) => {
this.tableData = data.records
this.tablePage.total = data.total
this.loading = false
})
},
// 分页
currentChangeHandle ({ currentPage, pageSize }) {
this.tablePage.currentPage = currentPage
this.tablePage.pageSize = pageSize
this.getMessagePage()
},
// 获取tabs列表
getMessageTypeCount () {
this.Message.getMessageTypeCount(this.user.loginName).then(({ data }) => {
this.tabs = data.body
this.$store.commit('user/updateMessageCount', data.body[0])
})
},
// 设置已读
setRead (item) {
this.Message.seeRead(item.id).then(({ data }) => {
this.$set(item, 'readFlag', '1')
})
},
// 设置全部已读
seeReadAll () {
const can = {
type: this.tabsActive,
userId: this.user.loginName,
}
this.Message.setReadAll(can).then(({ data }) => {
this.getMessageTypeCount()
this.getMessagePage()
})
}
},
created () {
this.Message = new Message()
},
mounted () {
this.getMessageTypeCount()
this.getMessagePage()
}
}
</script>
<style lang="less" scoped>
.rowTabs {
padding: 10px 0 10px 0;
.rowItem {
padding: 10px 15px 10px 15px;
background: #fff;
letter-spacing: 2px;
display: flex;
justify-content: space-between;
align-items: center;
}
.rowActive {
color: #fff;
background: #00AFAB;
}
.number {
height: 18px;
line-height: 18px;
text-align: center;
padding: 0 6px;
background-color: #F56C6C;
color: #fff;
border-radius: 10px;
font-size: 12px;
}
}
.list {
height: 100%;
overflow: auto;
.list-item {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #ccc;
padding: 10px 20px 10px 20px;
.item-left {
width: 80%;
.title {
font-weight: bold;
margin-bottom: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.subTitle {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.content {
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
word-break: break-all;
}
.date {
margin-top: 10px;
color: #ccc;
font-size: 15px;
}
}
.item-right {
div {
cursor: pointer;
}
}
}
}
.footer {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment