mirror of
https://github.com/dataease/dataease.git
synced 2025-02-24 11:32:57 +08:00
feat: 插件管理 消息管理 优化
This commit is contained in:
parent
a0b92c91ec
commit
1403504e2a
@ -34,7 +34,7 @@ export default {
|
||||
return backPath || backName || backTo
|
||||
},
|
||||
needInnerPadding() {
|
||||
return ['sys-task-email', 'system-dept', 'system-dept-form', 'system-auth', 'sys-appearance', 'system-param', 'system-template', "sys-task-dataset"].includes(this.$route.name)
|
||||
return ['sys-task-email', 'system-dept', 'system-dept-form', 'system-auth', 'sys-appearance', 'system-param', 'system-template', "sys-task-dataset", "sys-msg-web-all", "system-plugin"].includes(this.$route.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { log } from '@antv/g2plot/lib/utils';
|
||||
import tableBody from "./tableBody";
|
||||
export default {
|
||||
components: { tableBody },
|
||||
|
@ -2169,7 +2169,7 @@ export default {
|
||||
i18n_msg_type_ds_invalid: '数据源失效',
|
||||
i18n_msg_type_all: '全部类型',
|
||||
channel_inner_msg: '站内消息',
|
||||
channel_email_msg: '邮件'
|
||||
channel_email_msg: '邮件提醒'
|
||||
},
|
||||
denumberrange: {
|
||||
label: '数值区间',
|
||||
|
@ -1,191 +1,328 @@
|
||||
<template>
|
||||
<layout-content v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
<de-layout-content
|
||||
:header="$t('消息列表')"
|
||||
v-loading="$store.getters.loadingMap[$store.getters.currentPath]"
|
||||
>
|
||||
<div class="organization">
|
||||
<el-tabs v-model="tabActive" @tab-click="changeTab">
|
||||
<el-tab-pane :label="$t('未读消息')" name="unread"> </el-tab-pane>
|
||||
<el-tab-pane :label="$t('已读消息')" name="readed"> </el-tab-pane>
|
||||
<el-tab-pane :label="$t('全部消息')" name="allMsg"> </el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="tabs-container">
|
||||
<div class="msg-cont">
|
||||
<el-row class="top-operate">
|
||||
<el-col :span="12">
|
||||
<template v-if="tabActive === 'unread'">
|
||||
<deBtn secondary @click="allMarkReaded">{{
|
||||
$t("webmsg.all_mark_readed")
|
||||
}}</deBtn>
|
||||
<deBtn
|
||||
secondary
|
||||
:disabled="multipleSelection.length === 0"
|
||||
@click="markReaded"
|
||||
>{{ $t("webmsg.mark_readed") }}</deBtn
|
||||
>
|
||||
</template>
|
||||
|
||||
<deBtn
|
||||
v-if="tabActive === 'readed'"
|
||||
secondary
|
||||
:disabled="multipleSelection.length === 0"
|
||||
@click="deleteBatch"
|
||||
>{{ $t("commons.delete") }}</deBtn
|
||||
>
|
||||
|
||||
</el-col>
|
||||
<el-col class="right-user" :span="12">
|
||||
<el-select
|
||||
class="name-email-search"
|
||||
v-model="selectType"
|
||||
size="small"
|
||||
@change="typeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in $store.getters.msgTypes.filter(
|
||||
(type) => type.pid <= 0
|
||||
)"
|
||||
:key="index"
|
||||
:label="$t('webmsg.' + item.typeName)"
|
||||
:value="item.msgTypeId"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="table-container" :key="tabActive">
|
||||
<grid-table
|
||||
:key="tabActive"
|
||||
:tableData="data"
|
||||
:multipleSelection="multipleSelection"
|
||||
:columns="[]"
|
||||
:pagination="paginationConfig"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChange"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
|
||||
<el-radio-group v-model="selectType" style="margin-bottom: 15px;" @change="typeChange">
|
||||
<el-radio-button v-for="(item,index) in $store.getters.msgTypes.filter(type => type.pid <= 0)" :key="index" class="de-msg-radio-class" :label="item.msgTypeId">{{ $t('webmsg.' + item.typeName) }}</el-radio-button>
|
||||
<el-table-column prop="content" :label="$t('webmsg.content')">
|
||||
<template slot-scope="scope">
|
||||
<span style="display: flex; flex: 1">
|
||||
<span>
|
||||
<svg-icon
|
||||
v-if="!scope.row.status"
|
||||
icon-class="unread-msg"
|
||||
style="color: red"
|
||||
/>
|
||||
<svg-icon v-else icon-class="readed-msg" />
|
||||
</span>
|
||||
<span
|
||||
style="margin-left: 6px"
|
||||
class="de-msg-a"
|
||||
@click="toDetail(scope.row)"
|
||||
>
|
||||
{{ scope.row.content }}
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-radio-group>
|
||||
<complex-table
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:pagination-config="paginationConfig"
|
||||
@select="select"
|
||||
@search="search"
|
||||
@sort-change="sortChange"
|
||||
>
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
sortable="custom"
|
||||
:label="$t('webmsg.sned_time')"
|
||||
width="180"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="content" :label="$t('webmsg.content')">
|
||||
<template slot-scope="scope">
|
||||
|
||||
<span style="display: flex;flex: 1;">
|
||||
<span>
|
||||
<svg-icon v-if="!scope.row.status" icon-class="unread-msg" style="color: red;" />
|
||||
<svg-icon v-else icon-class="readed-msg" />
|
||||
</span>
|
||||
<span style="margin-left: 6px;" class="de-msg-a" @click="toDetail(scope.row)">
|
||||
{{ scope.row.content }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="createTime" sortable="custom" :label="$t('webmsg.sned_time')" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="typeId" sortable="custom" :label="$t('webmsg.type')" width="140">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getTypeName(scope.row.typeId) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</complex-table>
|
||||
|
||||
</layout-content>
|
||||
<el-table-column
|
||||
prop="typeId"
|
||||
sortable="custom"
|
||||
:label="$t('webmsg.type')"
|
||||
width="140"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getTypeName(scope.row.typeId) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</grid-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</de-layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import ComplexTable from '@/components/business/complex-table'
|
||||
import { query, updateStatus } from '@/api/system/msg'
|
||||
import { msgTypes, getTypeName, loadMsgTypes } from '@/utils/webMsg'
|
||||
import bus from '@/utils/bus'
|
||||
import { addOrder, formatOrders } from '@/utils/index'
|
||||
import { mapGetters } from 'vuex'
|
||||
import DeLayoutContent from "@/components/business/DeLayoutContent";
|
||||
import GridTable from "@/components/gridTable/index.vue";
|
||||
import { query, updateStatus, batchRead, allRead, batchDelete } from '@/api/system/msg'
|
||||
import { msgTypes, getTypeName, loadMsgTypes } from "@/utils/webMsg";
|
||||
import bus from "@/utils/bus";
|
||||
import { addOrder, formatOrders } from "@/utils/index";
|
||||
import msgCfm from "@/components/msgCfm/index";
|
||||
import { mapGetters } from "vuex";
|
||||
export default {
|
||||
components: {
|
||||
LayoutContent,
|
||||
ComplexTable
|
||||
DeLayoutContent,
|
||||
GridTable,
|
||||
},
|
||||
mixins: [msgCfm],
|
||||
data() {
|
||||
return {
|
||||
multipleSelection: [],
|
||||
tabActive: "unread",
|
||||
selectType: -1,
|
||||
msgTypes: msgTypes,
|
||||
data: [],
|
||||
allTypes: [{ name: 'mysql', type: 'jdbc' }, { name: 'sqlServer', type: 'jdbc' }],
|
||||
allTypes: [
|
||||
{ name: "mysql", type: "jdbc" },
|
||||
{ name: "sqlServer", type: "jdbc" },
|
||||
],
|
||||
|
||||
columns: [],
|
||||
|
||||
paginationConfig: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
total: 0,
|
||||
},
|
||||
orderConditions: []
|
||||
}
|
||||
orderConditions: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'permission_routes'
|
||||
])
|
||||
...mapGetters(["permission_routes"]),
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.search();
|
||||
},
|
||||
created() {
|
||||
// 先加载消息类型
|
||||
loadMsgTypes()
|
||||
loadMsgTypes();
|
||||
},
|
||||
methods: {
|
||||
select(selection) {
|
||||
changeTab(val) {
|
||||
this.initSearch();
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
handleSizeChange(pageSize) {
|
||||
this.paginationConfig.currentPage = 1;
|
||||
this.paginationConfig.pageSize = pageSize;
|
||||
this.search();
|
||||
},
|
||||
handleCurrentChange(currentPage) {
|
||||
this.paginationConfig.currentPage = currentPage;
|
||||
this.search();
|
||||
},
|
||||
initSearch() {
|
||||
this.handleCurrentChange(1);
|
||||
},
|
||||
allMarkReaded() {
|
||||
allRead().then(res => {
|
||||
this.openMessageSuccess('webmsg.mark_success');
|
||||
bus.$emit('refresh-top-notification')
|
||||
this.initSearch()
|
||||
})
|
||||
},
|
||||
markReaded() {
|
||||
const param = this.multipleSelection.map(item => item.msgId)
|
||||
batchRead(param).then(res => {
|
||||
this.openMessageSuccess('webmsg.mark_success');
|
||||
bus.$emit('refresh-top-notification')
|
||||
this.initSearch()
|
||||
})
|
||||
},
|
||||
deleteBatch() {
|
||||
const param = this.multipleSelection.map(item => item.msgId)
|
||||
batchDelete(param).then(res => {
|
||||
this.openMessageSuccess('commons.delete_success');
|
||||
this.initSearch()
|
||||
})
|
||||
},
|
||||
|
||||
search() {
|
||||
const param = {}
|
||||
const param = {};
|
||||
|
||||
if (this.selectType >= 0) {
|
||||
param.type = this.selectType
|
||||
param.type = this.selectType;
|
||||
}
|
||||
|
||||
if (this.orderConditions.length === 0) {
|
||||
param.orders = ['create_time desc ']
|
||||
param.orders = ["create_time desc "];
|
||||
} else {
|
||||
param.orders = formatOrders(this.orderConditions)
|
||||
param.orders = formatOrders(this.orderConditions);
|
||||
}
|
||||
|
||||
const { currentPage, pageSize } = this.paginationConfig
|
||||
query(currentPage, pageSize, param).then(response => {
|
||||
this.data = response.data.listObject
|
||||
this.paginationConfig.total = response.data.itemCount
|
||||
})
|
||||
if (this.tabActive !== "allMsg") {
|
||||
param.status = this.tabActive === "readed";
|
||||
}
|
||||
|
||||
const { currentPage, pageSize } = this.paginationConfig;
|
||||
query(currentPage, pageSize, param).then((response) => {
|
||||
this.data = response.data.listObject;
|
||||
this.paginationConfig.total = response.data.itemCount;
|
||||
});
|
||||
},
|
||||
getTypeName(value) {
|
||||
return this.$t('webmsg.' + getTypeName(value))
|
||||
return this.$t("webmsg." + getTypeName(value));
|
||||
},
|
||||
typeChange(value) {
|
||||
this.search()
|
||||
typeChange() {
|
||||
this.initSearch();
|
||||
},
|
||||
toDetail(row) {
|
||||
const param = { ...{ msgNotification: true, msgType: row.typeId, sourceParam: row.param }}
|
||||
const param = {
|
||||
...{
|
||||
msgNotification: true,
|
||||
msgType: row.typeId,
|
||||
sourceParam: row.param,
|
||||
},
|
||||
};
|
||||
if (this.hasPermissionRoute(row.router)) {
|
||||
this.$router.push({ name: row.router, params: param })
|
||||
row.status || this.setReaded(row)
|
||||
return
|
||||
this.$router.push({ name: row.router, params: param });
|
||||
row.status || this.setReaded(row);
|
||||
return;
|
||||
}
|
||||
this.$warning(this.$t('commons.no_target_permission'))
|
||||
this.$warning(this.$t("commons.no_target_permission"));
|
||||
},
|
||||
hasPermissionRoute(name, permission_routes) {
|
||||
permission_routes = permission_routes || this.permission_routes
|
||||
permission_routes = permission_routes || this.permission_routes;
|
||||
for (let index = 0; index < permission_routes.length; index++) {
|
||||
const route = permission_routes[index]
|
||||
if (route.name && route.name === name) return true
|
||||
if (route.children && this.hasPermissionRoute(name, route.children)) return true
|
||||
const route = permission_routes[index];
|
||||
if (route.name && route.name === name) return true;
|
||||
if (route.children && this.hasPermissionRoute(name, route.children))
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
},
|
||||
// 设置已读
|
||||
setReaded(row) {
|
||||
updateStatus(row.msgId).then(res => {
|
||||
bus.$emit('refresh-top-notification')
|
||||
this.search()
|
||||
})
|
||||
updateStatus(row.msgId).then((res) => {
|
||||
bus.$emit("refresh-top-notification");
|
||||
this.search();
|
||||
});
|
||||
},
|
||||
sortChange({ column, prop, order }) {
|
||||
this.orderConditions = []
|
||||
this.orderConditions = [];
|
||||
if (!order) {
|
||||
this.search()
|
||||
return
|
||||
this.search();
|
||||
return;
|
||||
}
|
||||
if (prop === 'createTime') {
|
||||
prop = 'create_time'
|
||||
if (prop === "createTime") {
|
||||
prop = "create_time";
|
||||
}
|
||||
if (prop === 'typeId') {
|
||||
prop = 'type_id'
|
||||
if (prop === "typeId") {
|
||||
prop = "type_id";
|
||||
}
|
||||
addOrder({ field: prop, value: order }, this.orderConditions)
|
||||
this.search()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
addOrder({ field: prop, value: order }, this.orderConditions);
|
||||
this.search();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.de-msg-radio-class {
|
||||
padding: 0 5px;
|
||||
::v-deep .el-radio-button__inner {
|
||||
border-radius: 4px 4px 4px 4px !important;
|
||||
border-left: 1px solid #dcdfe6 !important;
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
::v-deep .el-radio-button__orig-radio:checked+.el-radio-button__inner {
|
||||
color: #fff;
|
||||
// background-color: #0a7be0;
|
||||
// border-color: #0a7be0;
|
||||
-webkit-box-shadow: 0px 0 0 0 #0a7be0;
|
||||
box-shadow: 0px 0 0 0 #0a7be0;
|
||||
}
|
||||
}
|
||||
.de-msg-a:hover {
|
||||
text-decoration: underline !important;
|
||||
color: #0a7be0 !important;
|
||||
cursor: pointer !important;
|
||||
|
||||
text-decoration: underline !important;
|
||||
color: #0a7be0 !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
.top-operate {
|
||||
margin-bottom: 16px;
|
||||
.right-user {
|
||||
text-align: right;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.name-email-search {
|
||||
width: 240px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
.organization {
|
||||
height: 100%;
|
||||
background-color: var(--MainBG, #f5f6f7);
|
||||
|
||||
.tabs-container {
|
||||
height: calc(100% - 48px);
|
||||
background: var(--ContentBG, #ffffff);
|
||||
overflow-x: auto;
|
||||
|
||||
.msg-cont {
|
||||
padding: 24px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,221 +0,0 @@
|
||||
<template>
|
||||
<layout-content v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
|
||||
<el-radio-group v-model="selectType" style="margin-bottom: 15px;" @change="typeChange">
|
||||
<el-radio-button v-for="(item,index) in $store.getters.msgTypes.filter(type => type.pid <= 0)" :key="index" class="de-msg-radio-class" :label="item.msgTypeId">{{ $t('webmsg.' + item.typeName) }}</el-radio-button>
|
||||
|
||||
</el-radio-group>
|
||||
<complex-table
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:hide-columns="true"
|
||||
:pagination-config="paginationConfig"
|
||||
:search-config="searchConfig"
|
||||
@select="select"
|
||||
@search="search"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChange"
|
||||
>
|
||||
<template #toolbar>
|
||||
<el-button :disabled="multipleSelection.length === 0" @click="deleteBatch">{{ $t('commons.delete') }}</el-button>
|
||||
</template>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
/>
|
||||
<el-table-column prop="content" :label="$t('webmsg.content')">
|
||||
<template slot-scope="scope">
|
||||
|
||||
<span style="display: flex;flex: 1;">
|
||||
<span>
|
||||
<svg-icon v-if="!scope.row.status" icon-class="unread-msg" style="color: red;" />
|
||||
<svg-icon v-else icon-class="readed-msg" />
|
||||
</span>
|
||||
<span style="margin-left: 6px;" class="de-msg-a" @click="toDetail(scope.row)">
|
||||
{{ scope.row.content }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="createTime" sortable="custom" :label="$t('webmsg.sned_time')" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="readTime" sortable="custom" :label="$t('webmsg.read_time')" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.readTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="typeId" sortable="custom" :label="$t('webmsg.type')" width="140">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getTypeName(scope.row.typeId) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</complex-table>
|
||||
|
||||
</layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import ComplexTable from '@/components/business/complex-table'
|
||||
import { query, batchDelete } from '@/api/system/msg'
|
||||
import { msgTypes, getTypeName, loadMsgTypes } from '@/utils/webMsg'
|
||||
import { addOrder, formatOrders } from '@/utils/index'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
components: {
|
||||
LayoutContent,
|
||||
ComplexTable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectType: -1,
|
||||
msgTypes: msgTypes,
|
||||
data: [],
|
||||
allTypes: [{ name: 'mysql', type: 'jdbc' }, { name: 'sqlServer', type: 'jdbc' }],
|
||||
|
||||
columns: [],
|
||||
orderConditions: [],
|
||||
|
||||
paginationConfig: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
},
|
||||
multipleSelection: [],
|
||||
searchConfig: {
|
||||
useQuickSearch: false,
|
||||
useComplexSearch: false
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'permission_routes'
|
||||
])
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
},
|
||||
created() {
|
||||
// 先加载消息类型
|
||||
loadMsgTypes()
|
||||
},
|
||||
methods: {
|
||||
select(selection) {
|
||||
},
|
||||
|
||||
search() {
|
||||
const param = {}
|
||||
param.status = true
|
||||
if (this.selectType >= 0) {
|
||||
param.type = this.selectType
|
||||
}
|
||||
|
||||
if (this.orderConditions.length === 0) {
|
||||
param.orders = [' create_time desc ']
|
||||
} else {
|
||||
param.orders = formatOrders(this.orderConditions)
|
||||
}
|
||||
|
||||
const { currentPage, pageSize } = this.paginationConfig
|
||||
query(currentPage, pageSize, param).then(response => {
|
||||
this.data = response.data.listObject
|
||||
this.paginationConfig.total = response.data.itemCount
|
||||
})
|
||||
},
|
||||
getTypeName(value) {
|
||||
return this.$t('webmsg.' + getTypeName(value))
|
||||
},
|
||||
typeChange(value) {
|
||||
this.search()
|
||||
},
|
||||
toDetail(row) {
|
||||
const param = { ...{ msgNotification: true, msgType: row.typeId, sourceParam: row.param }}
|
||||
// this.$router.push({ name: row.router, params: param })
|
||||
if (this.hasPermissionRoute(row.router)) {
|
||||
this.$router.push({ name: row.router, params: param })
|
||||
return
|
||||
}
|
||||
this.$warning(this.$t('commons.no_target_permission'))
|
||||
},
|
||||
hasPermissionRoute(name, permission_routes) {
|
||||
permission_routes = permission_routes || this.permission_routes
|
||||
for (let index = 0; index < permission_routes.length; index++) {
|
||||
const route = permission_routes[index]
|
||||
if (route.name && route.name === name) return true
|
||||
if (route.children && this.hasPermissionRoute(name, route.children)) return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
sortChange({ column, prop, order }) {
|
||||
this.orderConditions = []
|
||||
if (!order) {
|
||||
this.search()
|
||||
return
|
||||
}
|
||||
if (prop === 'createTime') {
|
||||
prop = 'create_time'
|
||||
}
|
||||
if (prop === 'readTime') {
|
||||
prop = 'read_time'
|
||||
}
|
||||
if (prop === 'typeId') {
|
||||
prop = 'type_id'
|
||||
}
|
||||
addOrder({ field: prop, value: order }, this.orderConditions)
|
||||
this.search()
|
||||
},
|
||||
deleteBatch() {
|
||||
if (this.multipleSelection.length === 0) {
|
||||
this.$warning(this.$t('webmsg.please_select'))
|
||||
return
|
||||
}
|
||||
const param = this.multipleSelection.map(item => item.msgId)
|
||||
batchDelete(param).then(res => {
|
||||
this.$success(this.$t('commons.delete_success'))
|
||||
this.search()
|
||||
})
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.de-msg-radio-class {
|
||||
padding: 0 5px;
|
||||
::v-deep .el-radio-button__inner {
|
||||
border-radius: 4px 4px 4px 4px !important;
|
||||
border-left: 1px solid #dcdfe6 !important;
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
::v-deep .el-radio-button__orig-radio:checked+.el-radio-button__inner {
|
||||
color: #fff;
|
||||
/* background-color: #0a7be0;
|
||||
border-color: #0a7be0; */
|
||||
-webkit-box-shadow: 0px 0 0 0 #0a7be0;
|
||||
box-shadow: 0px 0 0 0 #0a7be0;
|
||||
}
|
||||
}
|
||||
.de-msg-a:hover {
|
||||
text-decoration: underline !important;
|
||||
color: #0a7be0 !important;
|
||||
cursor: pointer !important;
|
||||
|
||||
}
|
||||
|
||||
</style>
|
@ -1,13 +1,19 @@
|
||||
<template xmlns:el-col="http://www.w3.org/1999/html">
|
||||
<layout-content :header="$t('webmsg.receive_manage')">
|
||||
<de-layout-content :header="$t('消息接收管理')">
|
||||
<el-col>
|
||||
<el-row class="tree-head">
|
||||
<span style="float: left;padding-left: 10px">{{ $t('webmsg.type') }}</span>
|
||||
<span v-for="channel in msg_channels" :key="channel.msgChannelId" class="auth-span">
|
||||
<span style="float: left;">{{
|
||||
$t("webmsg.type")
|
||||
}}</span>
|
||||
<span
|
||||
v-for="channel in msg_channels"
|
||||
:key="channel.msgChannelId"
|
||||
class="auth-span"
|
||||
>
|
||||
{{ $t(channel.channelName) }}
|
||||
</span>
|
||||
</el-row>
|
||||
<el-row style="margin-top: 5px">
|
||||
<el-row class="msg-setting" style="margin-top: 5px">
|
||||
<el-tree
|
||||
:props="defaultProps"
|
||||
:data="treeData"
|
||||
@ -18,235 +24,281 @@
|
||||
>
|
||||
<span slot-scope="{ node, data }" class="custom-tree-node">
|
||||
<span>
|
||||
<span style="margin-left: 6px">{{ $t('webmsg.' + data.name) }}</span>
|
||||
<span style="margin-left: 6px">{{
|
||||
$t("webmsg." + data.name)
|
||||
}}</span>
|
||||
</span>
|
||||
<span @click.stop>
|
||||
|
||||
<div>
|
||||
<span v-for="channel in msg_channels" :key="channel.msgChannelId" class="auth-span">
|
||||
|
||||
<el-checkbox v-if="data.children && data.children.length > 0" v-model="data.check_all_map[channel.msgChannelId]" :indeterminate="data.indeterminate_map[channel.msgChannelId]" @change="parentBoxChange(node, channel)" />
|
||||
<el-checkbox v-else v-model="data.check_map[channel.msgChannelId]" @change="childBoxChange(node, channel)" />
|
||||
|
||||
</span>
|
||||
</div></span>
|
||||
<span
|
||||
v-for="channel in msg_channels"
|
||||
:key="channel.msgChannelId"
|
||||
class="auth-span-check"
|
||||
>
|
||||
<el-checkbox
|
||||
v-if="data.children && data.children.length > 0"
|
||||
v-model="data.check_all_map[channel.msgChannelId]"
|
||||
:indeterminate="
|
||||
data.indeterminate_map[channel.msgChannelId]
|
||||
"
|
||||
@change="parentBoxChange(node, channel)"
|
||||
/>
|
||||
<el-checkbox
|
||||
v-else
|
||||
v-model="data.check_map[channel.msgChannelId]"
|
||||
@change="childBoxChange(node, channel)"
|
||||
/>
|
||||
</span></div
|
||||
></span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</layout-content>
|
||||
</de-layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import { treeList, channelList, settingList, updateSetting, batchUpdate } from '@/api/system/msg'
|
||||
import DeLayoutContent from "@/components/business/DeLayoutContent";
|
||||
import {
|
||||
treeList,
|
||||
channelList,
|
||||
settingList,
|
||||
updateSetting,
|
||||
batchUpdate,
|
||||
} from "@/api/system/msg";
|
||||
export default {
|
||||
name: 'LazyTree',
|
||||
components: { LayoutContent },
|
||||
|
||||
name: "LazyTree",
|
||||
components: { DeLayoutContent },
|
||||
data() {
|
||||
return {
|
||||
treeData: [],
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
id: 'id'
|
||||
children: "children",
|
||||
label: "name",
|
||||
id: "id",
|
||||
},
|
||||
highlightCurrent: true,
|
||||
|
||||
msg_channels: [],
|
||||
setting_data: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
setting_data: {},
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
mounted() {},
|
||||
beforeCreate() {
|
||||
// this.loadChannelData()
|
||||
|
||||
channelList().then(res => {
|
||||
this.msg_channels = res.data
|
||||
})
|
||||
channelList().then((res) => {
|
||||
this.msg_channels = res.data;
|
||||
});
|
||||
},
|
||||
created() {
|
||||
this.loadSettingData(this.loadTreeData)
|
||||
this.loadSettingData(this.loadTreeData);
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 加载树节点数据
|
||||
loadTreeData() {
|
||||
treeList().then(res => {
|
||||
const datas = res.data
|
||||
datas.forEach(data => this.formatTreeNode(data))
|
||||
this.treeData = datas
|
||||
})
|
||||
treeList().then((res) => {
|
||||
const datas = res.data;
|
||||
datas.forEach((data) => this.formatTreeNode(data));
|
||||
this.treeData = datas;
|
||||
});
|
||||
},
|
||||
formatTreeNode(node) {
|
||||
if (node.children && node.children.length > 0) {
|
||||
node.check_all_map = {}
|
||||
node.indeterminate_map = {}
|
||||
node.indeterminate_number_map = {}
|
||||
const kidSize = node.children.length
|
||||
node.children.forEach(kid => {
|
||||
this.formatTreeNode(kid)
|
||||
const isLeaf = !kid.children || kid.children.length === 0
|
||||
const tempMap = isLeaf ? kid.check_map : kid.indeterminate_map
|
||||
node.check_all_map = {};
|
||||
node.indeterminate_map = {};
|
||||
node.indeterminate_number_map = {};
|
||||
const kidSize = node.children.length;
|
||||
node.children.forEach((kid) => {
|
||||
this.formatTreeNode(kid);
|
||||
const isLeaf = !kid.children || kid.children.length === 0;
|
||||
const tempMap = isLeaf ? kid.check_map : kid.indeterminate_map;
|
||||
for (const key in tempMap) {
|
||||
if (Object.hasOwnProperty.call(tempMap, key)) {
|
||||
const element = tempMap[key]
|
||||
node.indeterminate_number_map[key] = node.indeterminate_number_map[key] || 0
|
||||
const element = tempMap[key];
|
||||
node.indeterminate_number_map[key] =
|
||||
node.indeterminate_number_map[key] || 0;
|
||||
if (element) {
|
||||
node.indeterminate_number_map[key]++
|
||||
node.indeterminate_number_map[key]++;
|
||||
}
|
||||
|
||||
if (node.indeterminate_number_map[key] === kidSize && (isLeaf || kid.check_all_map[key])) {
|
||||
node.check_all_map[key] = true
|
||||
node.indeterminate_map[key] = false
|
||||
if (
|
||||
node.indeterminate_number_map[key] === kidSize &&
|
||||
(isLeaf || kid.check_all_map[key])
|
||||
) {
|
||||
node.check_all_map[key] = true;
|
||||
node.indeterminate_map[key] = false;
|
||||
} else if (node.indeterminate_number_map[key] > 0) {
|
||||
node.check_all_map[key] = false
|
||||
node.indeterminate_map[key] = true
|
||||
node.check_all_map[key] = false;
|
||||
node.indeterminate_map[key] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
node.check_map = {}
|
||||
this.msg_channels.forEach(channel => {
|
||||
node.check_map[channel.msgChannelId] = this.checkBoxStatus(node, channel)
|
||||
})
|
||||
node.check_map = {};
|
||||
this.msg_channels.forEach((channel) => {
|
||||
node.check_map[channel.msgChannelId] = this.checkBoxStatus(
|
||||
node,
|
||||
channel
|
||||
);
|
||||
});
|
||||
// this.checkBoxStatus(node, )
|
||||
}
|
||||
},
|
||||
// 加载消息渠道
|
||||
loadChannelData() {
|
||||
channelList().then(res => {
|
||||
this.msg_channels = res.data
|
||||
})
|
||||
channelList().then((res) => {
|
||||
this.msg_channels = res.data;
|
||||
});
|
||||
},
|
||||
// 加载用户设置信息
|
||||
loadSettingData(callBack) {
|
||||
// this.setting_data = {}
|
||||
const temp_setting_data = {}
|
||||
settingList().then(res => {
|
||||
const lists = res.data
|
||||
lists.forEach(item => {
|
||||
const key = item.typeId + ''
|
||||
const temp_setting_data = {};
|
||||
settingList().then((res) => {
|
||||
const lists = res.data;
|
||||
lists.forEach((item) => {
|
||||
const key = item.typeId + "";
|
||||
if (!Object.keys(temp_setting_data).includes(key)) {
|
||||
temp_setting_data[key] = []
|
||||
temp_setting_data[key] = [];
|
||||
}
|
||||
temp_setting_data[key].push(item)
|
||||
})
|
||||
this.setting_data = temp_setting_data
|
||||
callBack && callBack()
|
||||
})
|
||||
temp_setting_data[key].push(item);
|
||||
});
|
||||
this.setting_data = temp_setting_data;
|
||||
callBack && callBack();
|
||||
});
|
||||
},
|
||||
checkBoxStatus(node, channel) {
|
||||
// const nodeId = node.data.id
|
||||
const nodeId = node.id
|
||||
return this.setting_data[nodeId] && this.setting_data[nodeId].some(item => item.channelId === channel.msgChannelId && item.enable)
|
||||
const nodeId = node.id;
|
||||
return (
|
||||
this.setting_data[nodeId] &&
|
||||
this.setting_data[nodeId].some(
|
||||
(item) => item.channelId === channel.msgChannelId && item.enable
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
nodeClick(data, node) {
|
||||
},
|
||||
nodeClick(data, node) {},
|
||||
getAllKidId(node, ids) {
|
||||
if (node.children && node.children.length > 0) {
|
||||
node.children.forEach(item => this.getAllKidId(item, ids))
|
||||
node.children.forEach((item) => this.getAllKidId(item, ids));
|
||||
} else {
|
||||
ids.push(node.id)
|
||||
ids.push(node.id);
|
||||
}
|
||||
},
|
||||
parentBoxChange(node, channel) {
|
||||
const typeIds = []
|
||||
this.getAllKidId(node.data, typeIds)
|
||||
const channelId = channel.msgChannelId
|
||||
const typeIds = [];
|
||||
this.getAllKidId(node.data, typeIds);
|
||||
const channelId = channel.msgChannelId;
|
||||
|
||||
const data = node.data
|
||||
const enable = data.check_all_map && data.check_all_map[channelId]
|
||||
node.data.check_all_map[channelId] = enable
|
||||
node.data.indeterminate_map[channelId] = false
|
||||
node.data.children.forEach(item => {
|
||||
item.check_map = item.check_map || {}
|
||||
item.check_map[channelId] = enable
|
||||
})
|
||||
const data = node.data;
|
||||
const enable = data.check_all_map && data.check_all_map[channelId];
|
||||
node.data.check_all_map[channelId] = enable;
|
||||
node.data.indeterminate_map[channelId] = false;
|
||||
node.data.children.forEach((item) => {
|
||||
item.check_map = item.check_map || {};
|
||||
item.check_map[channelId] = enable;
|
||||
});
|
||||
|
||||
const param = {
|
||||
typeIds: typeIds,
|
||||
channelId: channelId,
|
||||
enable
|
||||
}
|
||||
batchUpdate(param).then(res => {
|
||||
this.loadSettingData(this.loadTreeData)
|
||||
})
|
||||
enable,
|
||||
};
|
||||
batchUpdate(param).then((res) => {
|
||||
this.loadSettingData(this.loadTreeData);
|
||||
});
|
||||
},
|
||||
childBoxChange(node, channel) {
|
||||
const channelId = channel.msgChannelId
|
||||
const parent = node.parent
|
||||
const channelId = channel.msgChannelId;
|
||||
const parent = node.parent;
|
||||
if (parent) {
|
||||
const data = parent.data
|
||||
const kids = data.children
|
||||
const kidSize = kids.length
|
||||
let index = 0
|
||||
kids.forEach(kid => {
|
||||
const data = parent.data;
|
||||
const kids = data.children;
|
||||
const kidSize = kids.length;
|
||||
let index = 0;
|
||||
kids.forEach((kid) => {
|
||||
if (kid.check_map[channelId]) {
|
||||
index++
|
||||
index++;
|
||||
}
|
||||
})
|
||||
});
|
||||
if (index === kidSize) {
|
||||
node.parent.data.check_all_map[channelId] = true
|
||||
node.parent.data.indeterminate_map[channelId] = false
|
||||
node.parent.data.check_all_map[channelId] = true;
|
||||
node.parent.data.indeterminate_map[channelId] = false;
|
||||
} else if (index > 0) {
|
||||
node.parent.data.check_all_map[channelId] = false
|
||||
node.parent.data.indeterminate_map[channelId] = true
|
||||
node.parent.data.check_all_map[channelId] = false;
|
||||
node.parent.data.indeterminate_map[channelId] = true;
|
||||
} else {
|
||||
node.parent.data.check_all_map[channelId] = false
|
||||
node.parent.data.indeterminate_map[channelId] = false
|
||||
node.parent.data.check_all_map[channelId] = false;
|
||||
node.parent.data.indeterminate_map[channelId] = false;
|
||||
}
|
||||
// this.formatTreeNode(node.parent.data)
|
||||
}
|
||||
|
||||
const param = {
|
||||
typeId: node.data.id,
|
||||
channelId: channelId
|
||||
channelId: channelId,
|
||||
};
|
||||
updateSetting(param).then((res) => {
|
||||
this.loadSettingData(this.loadTreeData);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-tree-node {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
padding-left: 8px;
|
||||
padding-right: 32px;
|
||||
}
|
||||
.tree-main {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.tree-head {
|
||||
height: 46px;
|
||||
line-height: 46px;
|
||||
border-bottom: 1px solid var(--TableBorderColor, #e6e6e6);
|
||||
border-top: 1px solid var(--TableBorderColor, #e6e6e6);
|
||||
background-color: var(--SiderBG, #f7f8fa);
|
||||
font-size: 12px;
|
||||
color: var(--TableColor, #3d4d66);
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
padding: 0 12px
|
||||
}
|
||||
|
||||
.auth-span {
|
||||
float: right;
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
.auth-span-check {
|
||||
float: right;
|
||||
margin-left: 64px;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.msg-setting {
|
||||
.el-tree-node__content {
|
||||
height: 46px;
|
||||
border-bottom: 1px solid rgba(31, 35, 41, 0.15);
|
||||
&:hover {
|
||||
background-color: var(--deWhiteHover, #3370ff) !important;
|
||||
.custom-tree-node {
|
||||
color: var(--primary, #3370ff);
|
||||
}
|
||||
updateSetting(param).then(res => {
|
||||
this.loadSettingData(this.loadTreeData)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.custom-tree-node {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
.tree-main{
|
||||
overflow-y: auto;
|
||||
}
|
||||
.tree-head{
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
border-bottom: 1px solid var(--TableBorderColor, #e6e6e6);
|
||||
background-color: var(--SiderBG, #f7f8fa);
|
||||
font-size: 12px;
|
||||
color: var(--TableColor, #3d4d66) ;
|
||||
}
|
||||
|
||||
.auth-span{
|
||||
float: right;
|
||||
width:50px;
|
||||
margin-right: 30px
|
||||
}
|
||||
.highlights-text {
|
||||
color: #faaa39 !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
@ -1,229 +0,0 @@
|
||||
<template>
|
||||
<layout-content v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
|
||||
<el-radio-group v-model="selectType" style="margin-bottom: 15px;" @change="typeChange">
|
||||
<el-radio-button v-for="(item,index) in $store.getters.msgTypes.filter(type => type.pid <= 0)" :key="index" class="de-msg-radio-class" :label="item.msgTypeId">{{ $t('webmsg.' + item.typeName) }}</el-radio-button>
|
||||
|
||||
</el-radio-group>
|
||||
<complex-table
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:hide-columns="true"
|
||||
:pagination-config="paginationConfig"
|
||||
:search-config="searchConfig"
|
||||
@select="select"
|
||||
@search="search"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChange"
|
||||
>
|
||||
<template #toolbar>
|
||||
<el-button :disabled="multipleSelection.length === 0" @click="markReaded">{{ $t('webmsg.mark_readed') }}</el-button>
|
||||
<el-button @click="allMarkReaded">{{ $t('webmsg.all_mark_readed') }}</el-button>
|
||||
</template>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
/>
|
||||
<el-table-column prop="content" :label="$t('webmsg.content')">
|
||||
<template slot-scope="scope">
|
||||
|
||||
<span style="display: flex;flex: 1;">
|
||||
<span>
|
||||
<svg-icon v-if="!scope.row.status" icon-class="unread-msg" style="color: red;" />
|
||||
<svg-icon v-else icon-class="readed-msg" />
|
||||
</span>
|
||||
<span style="margin-left: 6px;" class="de-msg-a" @click="toDetail(scope.row)">
|
||||
{{ scope.row.content }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="createTime" sortable="custom" :label="$t('webmsg.sned_time')" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="typeId" sortable="custom" :label="$t('webmsg.type')" width="140">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getTypeName(scope.row.typeId) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</complex-table>
|
||||
|
||||
</layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import ComplexTable from '@/components/business/complex-table'
|
||||
import { query, updateStatus, batchRead, allRead } from '@/api/system/msg'
|
||||
import { msgTypes, getTypeName, loadMsgTypes } from '@/utils/webMsg'
|
||||
import bus from '@/utils/bus'
|
||||
import { addOrder, formatOrders } from '@/utils/index'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
components: {
|
||||
LayoutContent,
|
||||
ComplexTable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectType: -1,
|
||||
msgTypes: msgTypes,
|
||||
data: [],
|
||||
allTypes: [{ name: 'mysql', type: 'jdbc' }, { name: 'sqlServer', type: 'jdbc' }],
|
||||
|
||||
columns: [],
|
||||
|
||||
paginationConfig: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
},
|
||||
searchConfig: {
|
||||
useQuickSearch: false,
|
||||
useComplexSearch: false
|
||||
},
|
||||
multipleSelection: [],
|
||||
orderConditions: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'permission_routes'
|
||||
])
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
},
|
||||
created() {
|
||||
// 先加载消息类型
|
||||
loadMsgTypes()
|
||||
},
|
||||
methods: {
|
||||
select(selection) {
|
||||
},
|
||||
|
||||
search() {
|
||||
const param = {}
|
||||
param.status = false
|
||||
if (this.selectType >= 0) {
|
||||
param.type = this.selectType
|
||||
}
|
||||
|
||||
if (this.orderConditions.length === 0) {
|
||||
param.orders = [' create_time desc ']
|
||||
} else {
|
||||
param.orders = formatOrders(this.orderConditions)
|
||||
}
|
||||
|
||||
const { currentPage, pageSize } = this.paginationConfig
|
||||
query(currentPage, pageSize, param).then(response => {
|
||||
this.data = response.data.listObject
|
||||
this.paginationConfig.total = response.data.itemCount
|
||||
})
|
||||
},
|
||||
getTypeName(value) {
|
||||
return this.$t('webmsg.' + getTypeName(value))
|
||||
},
|
||||
typeChange(value) {
|
||||
this.search()
|
||||
},
|
||||
toDetail(row) {
|
||||
const param = { ...{ msgNotification: true, msgType: row.typeId, sourceParam: row.param }}
|
||||
if (this.hasPermissionRoute(row.router)) {
|
||||
this.$router.push({ name: row.router, params: param })
|
||||
this.setReaded(row)
|
||||
return
|
||||
}
|
||||
this.$warning(this.$t('commons.no_target_permission'))
|
||||
},
|
||||
hasPermissionRoute(name, permission_routes) {
|
||||
permission_routes = permission_routes || this.permission_routes
|
||||
for (let index = 0; index < permission_routes.length; index++) {
|
||||
const route = permission_routes[index]
|
||||
if (route.name && route.name === name) return true
|
||||
if (route.children && this.hasPermissionRoute(name, route.children)) return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
// 设置已读
|
||||
setReaded(row) {
|
||||
updateStatus(row.msgId).then(res => {
|
||||
bus.$emit('refresh-top-notification')
|
||||
this.search()
|
||||
})
|
||||
},
|
||||
allMarkReaded() {
|
||||
allRead().then(res => {
|
||||
this.$success(this.$t('webmsg.mark_success'))
|
||||
bus.$emit('refresh-top-notification')
|
||||
this.search()
|
||||
})
|
||||
},
|
||||
markReaded() {
|
||||
if (this.multipleSelection.length === 0) {
|
||||
this.$warning(this.$t('webmsg.please_select'))
|
||||
return
|
||||
}
|
||||
const param = this.multipleSelection.map(item => item.msgId)
|
||||
batchRead(param).then(res => {
|
||||
this.$success(this.$t('webmsg.mark_success'))
|
||||
bus.$emit('refresh-top-notification')
|
||||
this.search()
|
||||
})
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val
|
||||
},
|
||||
sortChange({ column, prop, order }) {
|
||||
this.orderConditions = []
|
||||
if (!order) {
|
||||
this.search()
|
||||
return
|
||||
}
|
||||
if (prop === 'createTime') {
|
||||
prop = 'create_time'
|
||||
}
|
||||
if (prop === 'typeId') {
|
||||
prop = 'type_id'
|
||||
}
|
||||
addOrder({ field: prop, value: order }, this.orderConditions)
|
||||
this.search()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.de-msg-radio-class {
|
||||
padding: 0 5px;
|
||||
::v-deep .el-radio-button__inner {
|
||||
border-radius: 4px 4px 4px 4px !important;
|
||||
border-left: 1px solid #dcdfe6 !important;
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
::v-deep .el-radio-button__orig-radio:checked+.el-radio-button__inner {
|
||||
color: #fff;
|
||||
/* background-color: #0a7be0;
|
||||
border-color: #0a7be0; */
|
||||
-webkit-box-shadow: 0px 0 0 0 #0a7be0;
|
||||
box-shadow: 0px 0 0 0 #0a7be0;
|
||||
}
|
||||
}
|
||||
.de-msg-a:hover {
|
||||
text-decoration: underline !important;
|
||||
color: #0a7be0 !important;
|
||||
cursor: pointer !important;
|
||||
|
||||
}
|
||||
|
||||
</style>
|
@ -1,165 +1,361 @@
|
||||
<template>
|
||||
<layout-content v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
<complex-table
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:search-config="searchConfig"
|
||||
:pagination-config="paginationConfig"
|
||||
@search="search"
|
||||
>
|
||||
<template #toolbar>
|
||||
<el-upload
|
||||
v-permission="['plugin:upload']"
|
||||
:action="baseUrl+'api/plugin/upload'"
|
||||
:multiple="false"
|
||||
:show-file-list="false"
|
||||
:file-list="fileList"
|
||||
accept=".zip"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="uploadSuccess"
|
||||
:on-error="uploadFail"
|
||||
name="file"
|
||||
:headers="headers"
|
||||
<de-layout-content
|
||||
v-loading="$store.getters.loadingMap[$store.getters.currentPath]"
|
||||
>
|
||||
<div class="top-install">
|
||||
<el-input
|
||||
placeholder="通过插件名称搜索"
|
||||
size="small"
|
||||
prefix-icon="el-icon-search"
|
||||
v-model="name"
|
||||
clearable
|
||||
@blur="search"
|
||||
>
|
||||
</el-input>
|
||||
<el-upload
|
||||
v-permission="['plugin:upload']"
|
||||
:action="baseUrl + 'api/plugin/upload'"
|
||||
:multiple="false"
|
||||
:show-file-list="false"
|
||||
:file-list="fileList"
|
||||
accept=".zip"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="uploadSuccess"
|
||||
:on-error="uploadFail"
|
||||
name="file"
|
||||
:headers="headers"
|
||||
>
|
||||
<deBtn
|
||||
:icon="!uploading ? 'el-icon-upload2' : 'el-icon-loading'"
|
||||
type="primary"
|
||||
:disabled="uploading"
|
||||
>
|
||||
<el-button size="mini" type="primary" :disabled="uploading">
|
||||
<span v-if="!uploading" style="font-size: 12px;">{{ $t('plugin.local_install') }}</span>
|
||||
<span v-if="uploading" style="font-size: 12px;"><i class="el-icon-loading" /> {{ $t('dataset.uploading') }}</span>
|
||||
</el-button>
|
||||
</el-upload>
|
||||
</template>
|
||||
|
||||
<el-table-column prop="name" :label="$t('plugin.name')" />
|
||||
<!-- <el-table-column prop="free" :label="$t('plugin.free')">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.free ? '是' : '否' }}</span>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column prop="cost" :label="$t('plugin.cost')" />
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" prop="descript" :label="$t('plugin.descript')" />
|
||||
<el-table-column prop="version" :label="$t('plugin.version')" />
|
||||
<el-table-column prop="creator" :label="$t('plugin.creator')" />
|
||||
|
||||
<el-table-column prop="installTime" :label="$t('plugin.install_time')">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.installTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations :buttons="buttons" :label="$t('commons.operating')" fix />
|
||||
</complex-table>
|
||||
|
||||
</layout-content>
|
||||
{{ $t(!uploading ? "plugin.local_install" : "dataset.uploading") }}
|
||||
</deBtn>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div v-if="!data.length" class="plugin-cont">
|
||||
<el-empty style="width: 100%" description="没有找到相关内容"></el-empty>
|
||||
</div>
|
||||
<div v-else class="plugin-cont">
|
||||
<div v-for="ele in data" :key="ele.pluginId" class="de-card-plugin">
|
||||
<div class="card-info">
|
||||
<div class="info-top">
|
||||
<img
|
||||
src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"
|
||||
alt=""
|
||||
/>
|
||||
<p class="title">{{ ele.descript }}</p>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
:content="ele.descript"
|
||||
placement="top"
|
||||
>
|
||||
<p class="tips">{{ ele.name }}</p>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="info-left">
|
||||
<p class="list name" v-for="item in listName" :key="item">
|
||||
{{ item }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="info-right">
|
||||
<p class="list value" v-for="item in listValue" :key="item">
|
||||
<template v-if="item === 'cost' && !ele.cost">
|
||||
<el-tag size="mini" type="success">免费</el-tag>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ ele[item] }}
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-method">
|
||||
<el-upload
|
||||
v-permission="['plugin:upload']"
|
||||
:action="baseUrl + 'api/plugin/upload'"
|
||||
:multiple="false"
|
||||
:show-file-list="false"
|
||||
:file-list="fileList"
|
||||
accept=".zip"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="uploadSuccess"
|
||||
:on-error="uploadFail"
|
||||
name="file"
|
||||
:headers="headers"
|
||||
>
|
||||
<div class="btn-plugin"><i class="el-icon-more"></i>更新</div>
|
||||
</el-upload>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<div
|
||||
:class="[{ 'is-disable': btnDisabled(ele) }]"
|
||||
v-show="checkPermission(['plugin:uninstall'])"
|
||||
@click="del(ele)"
|
||||
class="btn-plugin"
|
||||
>
|
||||
<i class="el-icon-more"></i>卸载
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</de-layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import ComplexTable from '@/components/business/complex-table'
|
||||
import DeLayoutContent from "@/components/business/DeLayoutContent";
|
||||
|
||||
import { checkPermission } from '@/utils/permission'
|
||||
import { formatCondition, formatQuickCondition } from '@/utils/index'
|
||||
import { pluginLists, uninstall } from '@/api/system/plugin'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { checkPermission } from "@/utils/permission";
|
||||
import { formatCondition, formatQuickCondition } from "@/utils/index";
|
||||
import { pluginLists, uninstall } from "@/api/system/plugin";
|
||||
import { getToken } from "@/utils/auth";
|
||||
import msgCfm from "@/components/msgCfm/index";
|
||||
export default {
|
||||
|
||||
components: { ComplexTable, LayoutContent },
|
||||
components: { DeLayoutContent },
|
||||
mixins: [msgCfm],
|
||||
data() {
|
||||
return {
|
||||
header: '',
|
||||
columns: [],
|
||||
buttons: [
|
||||
// {
|
||||
// label: this.$t('commons.delete'), icon: 'el-icon-delete', type: 'danger', click: this.del,
|
||||
// show: checkPermission(['user:del'])
|
||||
// }
|
||||
{
|
||||
label: this.$t('plugin.un_install'), icon: 'el-icon-delete', type: 'danger', click: this.del,
|
||||
show: checkPermission(['plugin:uninstall']),
|
||||
disabled: this.btnDisabled
|
||||
}
|
||||
],
|
||||
searchConfig: {
|
||||
useQuickSearch: true,
|
||||
quickPlaceholder: this.$t('role.search_by_name'),
|
||||
components: [
|
||||
{ field: 'name', label: this.$t('plugin.name'), component: 'DeComplexInput' }
|
||||
]
|
||||
},
|
||||
paginationConfig: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
},
|
||||
listName: ["费用", "开发者", "版本", "安装时间"],
|
||||
name: "",
|
||||
listValue: ["cost", "creator", "version", "installTime"],
|
||||
data: [],
|
||||
uploading: false,
|
||||
baseUrl: process.env.VUE_APP_BASE_API,
|
||||
fileList: [],
|
||||
headers: { Authorization: getToken() }
|
||||
|
||||
}
|
||||
headers: { Authorization: getToken() },
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.search()
|
||||
this.search();
|
||||
this.bindKey();
|
||||
},
|
||||
destroyed() {
|
||||
this.unBindKey();
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
search(condition) {
|
||||
condition = formatQuickCondition(condition, 'name')
|
||||
const temp = formatCondition(condition)
|
||||
const param = temp || {}
|
||||
const { currentPage, pageSize } = this.paginationConfig
|
||||
pluginLists(currentPage, pageSize, param).then(response => {
|
||||
this.data = response.data.listObject
|
||||
this.paginationConfig.total = response.data.itemCount
|
||||
})
|
||||
entryKey(event) {
|
||||
const keyCode = event.keyCode;
|
||||
if (keyCode === 13) {
|
||||
this.search();
|
||||
}
|
||||
},
|
||||
bindKey() {
|
||||
document.addEventListener("keypress", this.entryKey);
|
||||
},
|
||||
unBindKey() {
|
||||
document.removeEventListener("keypress", this.entryKey);
|
||||
},
|
||||
search() {
|
||||
const param = {};
|
||||
if (this.name) {
|
||||
param.conditions = [
|
||||
{
|
||||
field: "name",
|
||||
operator: "like",
|
||||
value: this.name,
|
||||
},
|
||||
];
|
||||
}
|
||||
pluginLists(0, 0, param).then((response) => {
|
||||
this.data = response.data.listObject;
|
||||
this.data.forEach((ele) => {
|
||||
if (ele.installTime) {
|
||||
ele.installTime = new Date(ele.installTime).format(
|
||||
"yyyy-MM-dd hh:mm:ss"
|
||||
);
|
||||
}
|
||||
if (ele.cost) {
|
||||
ele.cost = ele.cost.toLocaleString();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
beforeUpload(file) {
|
||||
this.uploading = true
|
||||
this.uploading = true;
|
||||
},
|
||||
uploadFail(response, file, fileList) {
|
||||
const msg = response && response.message || '安装失败'
|
||||
const msg = (response && response.message) || "安装失败";
|
||||
try {
|
||||
const result = JSON.parse(msg)
|
||||
const result = JSON.parse(msg);
|
||||
if (result && result.message) {
|
||||
this.$error(result.message)
|
||||
this.uploading = false
|
||||
this.$error(result.message);
|
||||
this.uploading = false;
|
||||
}
|
||||
return
|
||||
return;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
this.$error(msg)
|
||||
this.uploading = false
|
||||
this.$error(msg);
|
||||
this.uploading = false;
|
||||
},
|
||||
uploadSuccess(response, file, fileList) {
|
||||
this.uploading = false
|
||||
this.search()
|
||||
this.uploading = false;
|
||||
this.search();
|
||||
},
|
||||
|
||||
del(row) {
|
||||
this.$confirm(this.$t('plugin.uninstall_confirm'), '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
cancelButtonText: this.$t('commons.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
uninstall(row.pluginId).then(res => {
|
||||
this.search()
|
||||
this.$success(this.$t('plugin.un_install_success'))
|
||||
}).catch(() => {
|
||||
this.$error(this.$t('plugin.un_install_error'))
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$info(this.$t('plugin.uninstall_cancel'))
|
||||
})
|
||||
const options = {
|
||||
title: "确定卸载该插件?",
|
||||
content: "卸载并重启服务器之后才能生效",
|
||||
confirmButtonText: this.$t('卸载'),
|
||||
type: "primary",
|
||||
cb: () => {
|
||||
uninstall(row.pluginId)
|
||||
.then((res) => {
|
||||
this.search();
|
||||
this.openMessageSuccess("plugin.un_install_success");
|
||||
})
|
||||
.catch(() => {
|
||||
this.$error(this.$t("plugin.un_install_error"));
|
||||
});
|
||||
},
|
||||
};
|
||||
this.handlerConfirm(options);
|
||||
},
|
||||
btnDisabled(row) {
|
||||
return row.pluginId < 4
|
||||
}
|
||||
|
||||
return row.pluginId < 4;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.top-install {
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
right: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.el-input {
|
||||
margin-right: 12px;
|
||||
}
|
||||
.el-input__inner {
|
||||
background: #ffffff !important;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.plugin-cont {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background-color: var(--MainBG, #f5f6f7);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.de-card-plugin {
|
||||
width: 270px;
|
||||
height: 230px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #dee0e3;
|
||||
border-radius: 4px;
|
||||
margin: 0 24px 24px 0;
|
||||
&:hover {
|
||||
box-shadow: 0px 6px 24px rgba(31, 35, 41, 0.08);
|
||||
}
|
||||
.card-method {
|
||||
border-top: 1px solid #dee0e3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 9px 30px 10px 30px;
|
||||
width: 100%;
|
||||
justify-content: space-around;
|
||||
box-sizing: border-box;
|
||||
|
||||
.btn-plugin {
|
||||
font-family: "PingFang SC";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
/* identical to box height, or 157% */
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
letter-spacing: -0.1px;
|
||||
|
||||
/* Neutral/600 */
|
||||
|
||||
color: #646a73;
|
||||
i {
|
||||
font-size: 13px;
|
||||
margin-right: 5.33px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-info {
|
||||
width: 100%;
|
||||
height: 188px;
|
||||
padding: 12px;
|
||||
padding-bottom: 4px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.info-top {
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
img {
|
||||
float: left;
|
||||
box-sizing: border-box;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #dee0e3;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 190px;
|
||||
height: 22px;
|
||||
float: left;
|
||||
font-family: "PingFang SC";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #000000;
|
||||
margin: -2px 0 0 6px;
|
||||
}
|
||||
|
||||
.tips {
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
float: left;
|
||||
height: 20px;
|
||||
font-family: "PingFang SC";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
color: #646a73;
|
||||
margin: 2px 0 0 6px;
|
||||
}
|
||||
}
|
||||
.list {
|
||||
padding-bottom: 8px;
|
||||
font-family: "PingFang SC";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
margin: 0;
|
||||
color: #646a73;
|
||||
}
|
||||
|
||||
.info-left {
|
||||
display: inline-block;
|
||||
|
||||
.name {
|
||||
color: #646a73;
|
||||
}
|
||||
}
|
||||
.info-right {
|
||||
display: inline-block;
|
||||
margin-left: 12px;
|
||||
.value {
|
||||
color: #1f2329;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user