diff options
Diffstat (limited to 'nezha-fronted/src')
33 files changed, 2551 insertions, 3155 deletions
diff --git a/nezha-fronted/src/assets/css/common/tableCommon.scss b/nezha-fronted/src/assets/css/common/tableCommon.scss index ffb150403..0016d7fe4 100644 --- a/nezha-fronted/src/assets/css/common/tableCommon.scss +++ b/nezha-fronted/src/assets/css/common/tableCommon.scss @@ -24,18 +24,32 @@ display: flex; align-items : center; position: relative; - flex-direction: row-reverse; - padding: 14px 20px 14px 0; + justify-content: space-between; + padding: 14px 20px; .top-tool-main-right { display: flex; } + .top-tool-main-left { + display: flex; + } + .top-tool-btn-group { + display: flex; + + .top-tool-btn:first-of-type { + border-radius: $--button-border-radius 0 0 $--button-border-radius; + } + .top-tool-btn:last-of-type { + border-radius: 0 $--button-border-radius $--button-border-radius 0; + border-left: none; + } + } .top-tool-btn { height: 32px; width: 36px; border: 1px solid #DEDEDE; outline: none; - border-radius: 2px; + border-radius: $--button-border-radius; background-color: $--button-gray-background-color; transition: background-color linear .1s; @@ -117,7 +131,7 @@ .table-operation-item { display: flex; height: 22px; - border-radius: 2px; + border-radius: $--button-border-radius; outline: none; } >.table-operation-item { @@ -126,7 +140,7 @@ width: 40px; margin-right: 10px; border: none; - border-radius: 2px; + border-radius: $--button-border-radius; background-color: $--button-primary-background-color; opacity: .8; cursor: pointer; diff --git a/nezha-fronted/src/assets/css/theme.scss b/nezha-fronted/src/assets/css/theme.scss index 0676b6082..02902d698 100644 --- a/nezha-fronted/src/assets/css/theme.scss +++ b/nezha-fronted/src/assets/css/theme.scss @@ -4,6 +4,8 @@ $--theme-color: var(--theme-color); // 主题色 /* 按钮 */ +$--button-border-radius: 2px; // 按钮圆角 + $--button-primary-color: #FFF; // 普通按钮字色 $--button-primary-background-color: var(--theme-color); // 普通按钮背景色 $--button-hover-tint-percent: 20%; // 非灰色按钮在鼠标hover时背景色变浅的幅度 diff --git a/nezha-fronted/src/assets/stylus/main.scss b/nezha-fronted/src/assets/stylus/main.scss index e90d99288..00f21e164 100644 --- a/nezha-fronted/src/assets/stylus/main.scss +++ b/nezha-fronted/src/assets/stylus/main.scss @@ -747,6 +747,7 @@ li{ border-top: 1px solid #DCDFE6; border-bottom: 1px solid #E4E7ED; margin: 0 -6px; + padding-right: 80px; background-color: $content-right-background-color; margin-bottom: 10px; } @@ -756,6 +757,9 @@ li{ .sub-top-tools .top-tool-search { width: 260px; margin: -1px 0 0 0; + .select_input input { + background-color: white; + } } .sub-top-tools .top-tool-btn-txt .nz-icon{ display: inline-block; @@ -2098,88 +2102,6 @@ li{ } -/*export相关*/ -.export-dropdown-btn { - position: relative; -} -.endpoint-query-dropdown { - position: absolute; - right: 0; - top: 31px; -} -.export-dropdown { - width: 90px; - right: 0; - left: unset !important; - top: 27px; -} -.endpoint-query-dropdown::after, .export-dropdown::after { - content: ''; - display: block; - width:0; - height:0; - overflow: hidden; - font-size: 0; - line-height: 0; - border: 5px; - border-style: dashed dashed solid dashed; - border-color: transparent transparent #fff transparent; - position: absolute; - right: 3px; - bottom: 0; - -} -.export-dropdown::after { - transform: translate(-50%, -54px); -} -.endpoint-query-dropdown::after { - transform: translate(-50%, -45px); -} -/*.dropdownBtn .el-dropdown__caret-button{ - top:0px !important; - left: -1px; -}*/ -.export-xlsx .el-dialog__body{ - padding: 10px 20px 20px 20px; -} -.export-xlsx .el-button:focus, .export-xlsx .el-button:hover { - color: unset; - border-color: unset; - background-color:unset; -} -.dropdownBtn .el-button--primary{ - top:2px; - padding: 0 8px; - background-image: linear-gradient(180deg, #fff 0%, #E0E0E0 100%); - border: 0px; - color: #666; - -webkit-box-shadow: 0 0 1px 1px rgba(162,162,162,0.5); - box-shadow: 0 0 1px 1px rgba(162,162,162,0.5); - letter-spacing: 0; - background-color: unset; -} -.dropdownBtn .el-button--primary:hover{ - background-image: linear-gradient(180deg, #F0F0F0 0%, #D8D8D8 99%) !important; -} -.dropdownBtn .el-button--mini{ - font-size: 12px; - height: 24px; -} -.dropdownBtn .el-button--mini:first-of-type { - right: 3px; -} -.el-dropdown .el-button-group{ - display: block; - position: relative; - top:-2px; -} -.export-xlsx .el-dropdown .el-dropdown__caret-button { - padding-left: 5px; - padding-right: 5px; - border-left: none; - top:0px; - left: -1px; -} .footer:before{ /*content: '';*/ /*clear:both;*/ diff --git a/nezha-fronted/src/components/common/bottomBox/bottomBox.vue b/nezha-fronted/src/components/common/bottomBox/bottomBox.vue index f73d74ad8..b9dd894b0 100644 --- a/nezha-fronted/src/components/common/bottomBox/bottomBox.vue +++ b/nezha-fronted/src/components/common/bottomBox/bottomBox.vue @@ -18,24 +18,27 @@ <!------TAB区------> <!--机柜--> - <cabinet-tab v-if="from === $CONSTANTS.fromRoute.dc && targetTab === 'cabinet'" v-show="subResizeShow" :obj="obj" @changeTab="changeTab"></cabinet-tab> + <cabinet-tab v-if="from === fromRoute.dc && targetTab === 'cabinet'" v-show="subResizeShow" :obj="obj" @changeTab="changeTab"></cabinet-tab> <!--告警信息--> - <alert-message-tab v-if="((from === $CONSTANTS.fromRoute.rule || from === $CONSTANTS.fromRoute.asset || from === $CONSTANTS.fromRoute.endpoint) && targetTab === 'alertMessage')" v-show="subResizeShow" :from="from" :obj="obj" @changeTab="changeTab"></alert-message-tab> + <alert-message-tab v-if="((from === fromRoute.rule || from === fromRoute.asset || from === fromRoute.endpoint) && targetTab === 'alertMessage')" v-show="subResizeShow" :from="from" :obj="obj" @changeTab="changeTab"></alert-message-tab> <!--asset页的endpoint列表--> - <endpoint-tab v-if="from === $CONSTANTS.fromRoute.asset && targetTab === $CONSTANTS.fromRoute.endpoint" v-show="subResizeShow" :from="from" :obj="obj" @changeTab="changeTab"></endpoint-tab> + <endpoint-tab v-if="from === fromRoute.asset && targetTab === fromRoute.endpoint" v-show="subResizeShow" :from="from" :obj="obj" @changeTab="changeTab"></endpoint-tab> <!--endpoint-query--> - <endpoint-query-tab v-if="(from === $CONSTANTS.fromRoute.endpoint && targetTab === 'endpointQuery')" v-show="subResizeShow" ref="endpointQuery" :from="from" :obj="obj" @changeTab="changeTab"></endpoint-query-tab> + <endpoint-query-tab v-if="(from === fromRoute.endpoint && targetTab === 'endpointQuery')" v-show="subResizeShow" ref="endpointQuery" :from="from" :obj="obj" @changeTab="changeTab"></endpoint-query-tab> <!-- model-panel/asset-detail/project-overview的panel--> - <panel-tab v-if="(from === $CONSTANTS.fromRoute.model || from === $CONSTANTS.fromRoute.asset || from === $CONSTANTS.fromRoute.project || from === $CONSTANTS.fromRoute.rule || from === $CONSTANTS.fromRoute.endpoint) && targetTab === 'panel'" v-show="subResizeShow" ref="panelTab" :from="from" :obj="obj" + <panel-tab v-if="(from === fromRoute.model || from === fromRoute.asset || from === fromRoute.project || from === fromRoute.rule || from === fromRoute.endpoint) && targetTab === 'panel'" v-show="subResizeShow" ref="panelTab" :from="from" :obj="obj" @changeTab="changeTab" :targetTab.sync="targetTab" :detail="detail"></panel-tab> <!--terminal-log的记录和回放--> - <terminal-log-cmd-tab v-if="from === $CONSTANTS.fromRoute.terminalLog && targetTab === 'cmd'" ref="reminalLogCMDTab" :from="from" :obj="obj" @changeTab="changeTab"></terminal-log-cmd-tab> - <terminal-log-record-tab v-if="from === $CONSTANTS.fromRoute.terminalLog && targetTab === 'record'" ref="reminalLogRecordTab" :from="from" :obj="obj" @changeTab="changeTab"></terminal-log-record-tab> + <terminal-log-cmd-tab v-if="from === fromRoute.terminalLog && targetTab === 'cmd'" ref="reminalLogCMDTab" :from="from" :obj="obj" @changeTab="changeTab"></terminal-log-cmd-tab> + <terminal-log-record-tab v-if="from === fromRoute.terminalLog && targetTab === 'record'" ref="reminalLogRecordTab" :from="from" :obj="obj" @changeTab="changeTab"></terminal-log-record-tab> - <terminal-log-monitor-tab v-if="from === $CONSTANTS.fromRoute.terminalLog && targetTab === 'monitor'" ref="reminalLogRecordTab" :from="from" :obj="obj" @changeTab="changeTab" @exit="closeSubList"></terminal-log-monitor-tab> + <terminal-log-monitor-tab v-if="from === fromRoute.terminalLog && targetTab === 'monitor'" ref="reminalLogRecordTab" :from="from" :obj="obj" @changeTab="changeTab" @exit="closeSubList"></terminal-log-monitor-tab> + <!--user列表的两个日志--> + <operation-log-tab v-if="from === fromRoute.account && targetTab === 'operationLogTab'" :from="from" :obj="obj" @changeTab="changeTab"></operation-log-tab> + <terminal-log-tab v-if="from === fromRoute.account && targetTab === 'terminalLogTab'" :from="from" :obj="obj" @changeTab="changeTab"></terminal-log-tab> </div> </div> </template> @@ -49,18 +52,23 @@ import panelTab from './tabs/panelTab' import terminalLogRecordTab from './tabs/terminalLogRecordTab' import terminalLogMonitorTab from './tabs/terminalLogMonitorTab' import terminalLogCMDTab from './tabs/terminalLogCMDTab' +import operationLogTab from './tabs/operationLogTab' +import terminalLogTab from './tabs/terminalLogTab' +import { fromRoute } from '@/components/common/js/constants' export default { name: 'bottomBox', components: { - 'cabinet-tab': cabinetTab, - 'alert-message-tab': alertMessageTab, - 'endpoint-query-tab': endpointQueryTab, - 'endpoint-tab': endpointTab, - 'panel-tab': panelTab, + cabinetTab, + alertMessageTab, + endpointQueryTab, + endpointTab, + panelTab, terminalLogRecordTab, - 'terminal-log-cmd-tab': terminalLogCMDTab, - terminalLogMonitorTab + terminalLogMonitorTab, + operationLogTab, + terminalLogTab, + 'terminal-log-cmd-tab': terminalLogCMDTab }, props: { isFullScreen: Boolean, // 是否全屏 @@ -75,7 +83,9 @@ export default { assetDetail: Object // endpoint页的asset详情 }, data () { - return {} + return { + fromRoute: fromRoute + } }, methods: { exitFullScreen () { @@ -97,9 +107,9 @@ export default { this.$emit('update:targetTab', tab) }, afterResize () { - if (this.from === this.$CONSTANTS.fromRoute.endpoint && this.targetTab === 'endpointQuery') { + if (this.from === this.fromRoute.endpoint && this.targetTab === 'endpointQuery') { this.$refs.endpointQuery.tableReload() - } else if (this.from === this.$CONSTANTS.fromRoute.terminalLog && this.targetTab === 'record') { + } else if (this.from === this.fromRoute.terminalLog && this.targetTab === 'record') { setTimeout(() => { this.$refs.reminalLogRecordTab.consoleResize() }, 600) diff --git a/nezha-fronted/src/components/common/bottomBox/tabs/operationLogTab.vue b/nezha-fronted/src/components/common/bottomBox/tabs/operationLogTab.vue new file mode 100644 index 000000000..ea10ddf5b --- /dev/null +++ b/nezha-fronted/src/components/common/bottomBox/tabs/operationLogTab.vue @@ -0,0 +1,206 @@ +<template> + <div style="height: 100%"> + <div class="sub-top-tools"> + <div class="sub-list-tabs"> + <div class="sub-list-tab-title">{{obj.id}}</div><div + id="endpoint-tab-change-panel" class="sub-list-tab sub-list-tab-active">{{$t("config.operationlog.operationlog")}}</div><div + id="endpoint-tab-change-alertmsg" class="sub-list-tab" @click="changeTab('terminalLogTab')">{{$t("config.terminallog.terminallog")}}</div> + </div> + <div class="top-tool-right"> + <div class="top-tool-search"> + <search-input :searchMsg="searchMsg" position="endpoint-bottom" @search="search"></search-input> + </div> + </div> + </div> + <el-table + id="role-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" + > + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> + <template slot-scope="scope" :column="item"> + <span v-if="item.prop === 'time'"> + {{scope.row[item.prop]}} ms + </span> + <span v-else-if="item.prop === 'username'">{{formatUsername(scope.row)}}</span> + <span v-else-if="item.prop === 'createDate'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> + <span v-else>{{scope.row[item.prop]}}</span> + </template> + </el-table-column> + </el-table> + </div> +</template> + +<script> +import tableMixin from '@/components/common/mixin/table' +export default { + name: 'operationLogTab', + mixins: [tableMixin], + data () { + return { + tableId: 'operationLogTable', // 需要分页的table的id,用于记录每页数量 + tableTitle: [ + { + label: this.$t('config.operationlog.id'), + prop: 'id', + show: true, + width: 80 + }, { + label: this.$t('config.operationlog.username'), + prop: 'username', + show: true + }, + { + label: this.$t('config.operationlog.ip'), + prop: 'ip', + show: true + }, + { + label: this.$t('config.operationlog.operation'), + prop: 'operation', + show: true + }, + { + label: this.$t('config.operationlog.type'), + prop: 'type', + show: true + }, + { + label: this.$t('config.operationlog.state'), + prop: 'state', + show: true + }, + // { + // label: this.$t('config.operationlog.userId'), + // prop: 'userId', + // show: false, + // }, + { + label: this.$t('config.operationlog.operaId'), + prop: 'operaId', + show: false + }, + { + label: this.$t('config.operationlog.createDate'), + prop: 'createDate', + show: true + }, + { + label: this.$t('config.operationlog.time'), + prop: 'time', + show: false + }, + { + label: this.$t('config.operationlog.params'), + prop: 'params', + show: false + }, + { + label: this.$t('config.operationlog.response'), + prop: 'response', + show: false + } + ], + searchMsg: { // 给搜索框子组件传递的信息 + zheze_none: true, + searchLabelList: [ + { + id: 11, + name: this.$t('config.operationlog.type'), + type: 'input', + label: 'type', + disabled: false + }, { + id: 12, + name: this.$t('config.operationlog.username'), + type: 'input', + label: 'username', + disabled: false + }, { + id: 13, + name: this.$t('config.operationlog.operation'), + type: 'selectString', + label: 'operation', + disabled: false + } + ] + } + } + }, + props: { + obj: Object // 关联的实体对象 + }, + methods: { + // 切换tab + changeTab (tab) { + this.$emit('changeTab', tab) + }, + messageStyle (e) { + if (e.column.label === this.$t('config.operationlog.state')) { + if (e.row.state === 'success') { + return 'success' + } else { + return 'danger' + } + } + return '' + }, + getTableData () { + this.$set(this.searchLabel, 'pageNo', this.pageObj.pageNo) + this.$set(this.searchLabel, 'pageSize', this.pageObj.pageSize) + this.tools.loading = true + this.$get('sys/log/list', this.searchLabel).then(response => { + this.tools.loading = false + if (response.code === 200) { + this.tableData = response.data.list + this.pageObj.total = response.data.total + if (!this.scrollbarWrap) { + this.$nextTick(() => { + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper + this.toTopBtnHandler(this.scrollbarWrap) + }) + } + } + }) + }, + formatUsername (row) { + if (row.username) { + return row.username + } else if (row.operation === 'login' && !row.username) { // 如果是登录 且登录失败 + return JSON.parse(row.params).username + } else { + return '-' + } + } + } +} +</script> diff --git a/nezha-fronted/src/components/common/bottomBox/tabs/terminalLogTab.vue b/nezha-fronted/src/components/common/bottomBox/tabs/terminalLogTab.vue new file mode 100644 index 000000000..065848041 --- /dev/null +++ b/nezha-fronted/src/components/common/bottomBox/tabs/terminalLogTab.vue @@ -0,0 +1,291 @@ +<template> + <div style="height: 100%"> + <div class="sub-top-tools"> + <div class="sub-list-tabs"> + <div class="sub-list-tab-title">{{obj.id}}</div><div + id="endpoint-tab-change-panel" class="sub-list-tab" @click="changeTab('operationLogTab')">{{$t("config.operationlog.operationlog")}}</div><div + id="endpoint-tab-change-alertmsg" class="sub-list-tab sub-list-tab-active">{{$t("config.terminallog.terminallog")}}</div> + </div> + <div class="top-tool-right"> + <div class="top-tool-search"> + <search-input :searchMsg="searchMsg" position="endpoint-bottom" @search="search"></search-input> + </div> + </div> + </div> + <el-table + id="terminal-log-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" + > + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> + <template slot-scope="scope" :column="item"> + <span v-if="item.prop === 'time'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> + <template v-else-if="item.prop === 'status'"> + <span>{{getStatusText(scope.row.status)}}</span> + </template> + <template v-else-if="item.prop === 'uuid'"> + <span>{{scope.row.uuid.substring(0, 8).toUpperCase()}}</span> + </template> + <template v-else-if="item.prop === 'remote'"> + <span>{{getRemoteText(scope.row)}}</span> + </template> + <template v-else-if="item.prop === 'duration'"> + <el-tooltip :disabled="!scope.row.status" effect="light" placement="right"> + <div slot="content"> + {{$t('config.terminallog.endTime')}}<br/> + {{scope.row.endTime}} + </div> + <span>{{getDuration(scope.row)}}</span> + </el-tooltip> + </template> + <template v-else-if="item.prop === 'authType'"> + <span v-if="scope.row.authType == 1">{{$t('config.terminallog.password')}}</span> + <span v-else-if="scope.row.authType == 2">{{$t('config.terminallog.key')}}</span> + </template> + <span v-else>{{scope.row[item.prop]}}</span> + </template> + </el-table-column> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <template v-if="scope.row.status == 0"> + <button :title="$t('config.terminallog.monitor.monitor')" class="table-operation-item" @click="$refs.dataList.showBottomBox('monitor', scope.row)"><i class="nz-icon nz-icon-JC"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['shutdown', scope.row]"><i class="nz-icon nz-icon-ZD"></i><span class="operation-dropdown-text">Kill</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + </template> + <template v-else> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('cmd', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['record', scope.row]"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('config.terminallog.record.record')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + </template> + </div> + </el-table-column> + </el-table> + </div> +</template> + +<script> +import tableMixin from '@/components/common/mixin/table' +import { terminalLog } from '@/components/common/js/constants' +import { calcDurationByStringTimeB } from '@/components/common/js/tools' + +export default { + name: 'terminalLogTab', + mixins: [tableMixin], + data () { + return { + tableId: 'terminalLogTable', // 需要分页的table的id,用于记录每页数量 + + tableTitle: [ + { + label: this.$t('config.terminallog.id'), + prop: 'id', + show: true, + width: 80 + }, { + label: 'Session ID', + prop: 'uuid', + show: true + }, { + label: 'Username', + prop: 'username', + show: true + }, + { + label: this.$t('config.terminallog.source'), + prop: 'remoteAddr', + show: true + }, + { + label: this.$t('config.terminallog.remote'), + prop: 'remote', + show: true + }, + { + label: this.$t('config.terminallog.protocol'), + prop: 'protocol', + show: true + }, + { + label: this.$t('config.terminallog.startTime'), + prop: 'startTime', + show: true + }, + { + label: this.$t('config.terminallog.duration'), + prop: 'duration', + show: true + }, + { + label: 'AuthType', + prop: 'authType', + show: false + }, + { + label: this.$t('config.terminallog.status'), // killusername鼠标悬停形式 + prop: 'status', + show: true, + width: 100 + } + ], + searchMsg: { // 给搜索框子组件传递的信息 + zheze_none: true, + searchLabelList: [ + { + id: 11, + name: this.$t('config.terminallog.host'), + type: 'input', + label: 'host', + disabled: false + }, { + id: 12, + name: this.$t('config.terminallog.user'), + type: 'input', + label: 'username', + disabled: false + } + ] + }, + nowTime: '' + } + }, + computed: { + getStatusText () { + return function (status) { + return terminalLog.status[status] + } + }, + getRemoteText () { + return function (record) { + return `${record.loginUser}@${record.host}:${record.port}` + } + }, + getDuration () { + return function (record) { + if (record.endTime) { + return calcDurationByStringTimeB(record.startTime, record.endTime) + } + return calcDurationByStringTimeB(record.startTime, this.nowTime) + } + } + }, + props: { + obj: Object // 关联的实体对象 + }, + methods: { + // 切换tab + changeTab (tab) { + this.$emit('changeTab', tab) + }, + tableOperation ([command, row]) { + switch (command) { + case 'shutdown': { + this.shutdown(row) + break + } + default: + this.$refs.dataList.showBottomBox(command, row) + break + } + }, + getTableData () { + const params = { + ...this.searchLabel, + pageNo: this.pageObj.pageNo, + pageSize: this.pageObj.pageSize + } + this.$get('terminal/session', params).then(response => { + this.tools.loading = false + if (response.code === 200) { + this.tableData = response.data.list + this.nowTime = this.utcTimeToTimezoneStr(response.time) + this.pageObj.total = response.data.total + if (!this.scrollbarWrap) { + this.$nextTick(() => { + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper + this.toTopBtnHandler(this.scrollbarWrap) + }) + } + } + }) + }, + shutdown (record) { + this.$confirm(this.$t('tip.killTerm'), { + confirmButtonText: this.$t('tip.yes'), + cancelButtonText: this.$t('tip.no'), + type: 'warning' + }).then(() => { + this.$put('/terminal/kill', { uuid: record.uuid }).then(res => { + if (res.code === 200) { + this.$message.success(this.$t('config.terminallog.success')) + this.bottomBox.showSubList = false + this.getTableData() + } else { + this.$message.error(this.$t('config.terminallog.killErrorTip')) + } + }) + }) + }, + messageStyle (e) { + if (e.column.label == this.$t('config.terminallog.status')) { + if (e.row.status == '0') { + return 'success' + } else if (e.row.status == '1') { + return 'warning' + } else if (e.row.status == '2') { + return 'suspended' + } else if (e.row.status == '3') { + return 'danger' + } else if (e.row.status == '4') { + return 'danger' + } + } + return '' + } + } +} +</script> diff --git a/nezha-fronted/src/components/common/exportXLSX.vue b/nezha-fronted/src/components/common/exportXLSX.vue index 2a54387a7..48ff11154 100644 --- a/nezha-fronted/src/components/common/exportXLSX.vue +++ b/nezha-fronted/src/components/common/exportXLSX.vue @@ -1,10 +1,11 @@ <template> <div class="export-xlsx"> - <div class="nz-btn-group nz-btn-group-size-normal nz-btn-group-light"> - <slot name="optionZone"></slot><button @mouseenter="exportMenuHandler(true)" @mouseleave="exportMenuHandler(false)" class="nz-btn nz-btn-size-normal nz-btn-style-light export-dropdown-btn" id="browser-go" style="padding: 0" v-has="[permissions.import, permissions.export]"> - <i class="nz-icon nz-icon-arrow-down"></i> + <div class="top-tool-btn-group"> + <slot name="optionZone"></slot> + <button id="browser-go" v-has="[permissions.import, permissions.export]" class="top-tool-btn" style="position: relative" @mouseenter="exportMenuHandler(true)" @mouseleave="exportMenuHandler(false)"> + <i class="nz-icon nz-icon-arrow-down" style="font-size: 12px;"></i> <transition name="el-zoom-in-top"> - <ul class="el-dropdown-menu el-popper el-dropdown-menu--mini export-dropdown" style="z-index: 101" v-show="exportShow"> + <ul v-show="exportShow" class="el-dropdown-menu el-popper el-dropdown-menu--mini export-dropdown"> <li @click="showImportBox(1)" class="el-dropdown-menu__item dropdown-content" v-has="permissions.import" :id="id+'-xlsx-import'"><i class="nz-icon nz-icon-upload"></i>{{$t('overall.importExcel')}}</li> <li @click="showImportBox(2)" class="el-dropdown-menu__item dropdown-content" v-has="permissions.export" :id="id+'-xlsx-export'"><i class="nz-icon nz-icon-download1"></i>{{$t('overall.exportExcel')}}</li> </ul> @@ -26,13 +27,13 @@ </div> <div slot="footer" class="footer"> <div class="el-message-box__btns" style="text-align: right;"> - <button @click="downloadTemplate" class="el-button el-button--default el-button--small" :id="id+'-xlsx-import-template'"> + <button :id="id+'-xlsx-import-template'" class="el-button el-button--default el-button--small" @click="downloadTemplate"> <span>{{$t('overall.template')}}</span> </button> - <button @click="importExcel" class="nz-btn el-button el-button--default el-button--small" :disabled="prevent_opt.import" :class="{'nz-btn-disabled':prevent_opt.import}" :id="id+'-xlsx-import-add'"> + <button :id="id+'-xlsx-import-add'" :class="{'nz-btn-disabled':prevent_opt.import}" :disabled="prevent_opt.import" class="nz-btn el-button el-button--default el-button--small" @click="importExcel"> <span>{{$t('overall.importExcel')}}</span> </button> - <button @click="closeDialog" class="el-button el-button--default el-button--small" :id="id+'-xlsx-import-esc'"> + <button :id="id+'-xlsx-import-esc'" class="el-button el-button--default el-button--small" @click="closeDialog"> <span>{{$t('overall.cancel')}}</span> </button> </div> @@ -366,4 +367,82 @@ export default { .import-result-item .line-num{ width: 55px; } + + .export-dropdown-btn { + position: relative; + } + .endpoint-query-dropdown { + position: absolute; + right: 0; + top: 31px; + } + .export-dropdown { + width: 90px; + right: 0; + left: unset !important; + top: 35px; + } + .endpoint-query-dropdown::after, .export-dropdown::after { + content: ''; + display: block; + width:0; + height:0; + overflow: hidden; + font-size: 0; + line-height: 0; + border: 5px; + border-style: dashed dashed solid dashed; + border-color: transparent transparent #fff transparent; + position: absolute; + right: 3px; + bottom: 0; + + } + .export-dropdown::after { + transform: translate(-50%, -54px); + } + .endpoint-query-dropdown::after { + transform: translate(-50%, -45px); + } + .export-xlsx .el-dialog__body{ + padding: 10px 20px 20px 20px; + } + .export-xlsx .el-button:focus, .export-xlsx .el-button:hover { + color: unset; + border-color: unset; + background-color:unset; + } + .dropdownBtn .el-button--primary{ + top:2px; + padding: 0 8px; + background-image: linear-gradient(180deg, #fff 0%, #E0E0E0 100%); + border: 0px; + color: #666; + -webkit-box-shadow: 0 0 1px 1px rgba(162,162,162,0.5); + box-shadow: 0 0 1px 1px rgba(162,162,162,0.5); + letter-spacing: 0; + background-color: unset; + } + .dropdownBtn .el-button--primary:hover{ + background-image: linear-gradient(180deg, #F0F0F0 0%, #D8D8D8 99%) !important; + } + .dropdownBtn .el-button--mini{ + font-size: 12px; + height: 24px; + } + .dropdownBtn .el-button--mini:first-of-type { + right: 3px; + } + .el-dropdown .el-button-group{ + display: block; + position: relative; + top:-2px; + } + .export-xlsx .el-dropdown .el-dropdown__caret-button { + padding-left: 5px; + padding-right: 5px; + border-left: none; + top: 0; + left: -1px; + } </style> diff --git a/nezha-fronted/src/components/common/header.vue b/nezha-fronted/src/components/common/header.vue index 5df9db7b0..459ae481b 100644 --- a/nezha-fronted/src/components/common/header.vue +++ b/nezha-fronted/src/components/common/header.vue @@ -418,7 +418,7 @@ export default { }, getUserData () { return new Promise(resolve => { - this.$get('sys/user/list', { pageSize: -1, pageNo: 1 }).then(response => { + this.$get('sys/user', { pageSize: -1, pageNo: 1 }).then(response => { if (response.code === 200) { this.userData = response.data.list } diff --git a/nezha-fronted/src/components/common/js/constants.js b/nezha-fronted/src/components/common/js/constants.js index eda5853b0..e9cc3ecf0 100644 --- a/nezha-fronted/src/components/common/js/constants.js +++ b/nezha-fronted/src/components/common/js/constants.js @@ -182,10 +182,18 @@ export const fromRoute = { message: 'message', rule: 'rule', model: 'model', + mib: 'mib', asset: 'asset', + assetType: 'assetType', + assetState: 'assetState', + expressionTemplate: 'expressionTemplate', + account: 'account', + promServer: 'promServer', dc: 'dc', + role: 'role', endpoint: 'endpoint', project: 'project', endpointQuery: 'endpointQuery', - terminalLog: 'terminal' + terminalLog: 'terminalLog', + operationLog: 'operationLog' } diff --git a/nezha-fronted/src/components/common/js/tools.js b/nezha-fronted/src/components/common/js/tools.js index 5d2050944..aebb5da49 100644 --- a/nezha-fronted/src/components/common/js/tools.js +++ b/nezha-fronted/src/components/common/js/tools.js @@ -242,7 +242,7 @@ export const bottomBoxWindow = { vm.tools.toTopBtnTop = vm.$tableHeight.toTopBtnTop vm.bottomBox.isFullScreen = false // 移动分页组件的位置 - const paginationTop = document.querySelector('.pagination-top') + /* const paginationTop = document.querySelector('.pagination-top') const paginationBottom = document.querySelector('.pagination-bottom') paginationTop.classList.remove('display-none') if (paginationTop.classList.contains('pagination-top-show')) { @@ -254,7 +254,7 @@ export const bottomBoxWindow = { setTimeout(() => { paginationTop.classList.add('display-none') paginationBottom.appendChild(paginationTop.removeChild(document.querySelector('.pagination'))) - }, 210) + }, 210) */ // 主列表恢复全屏 vm.bottomBox.mainResizeShow = vm.bottomBox.subResizeShow = true @@ -265,7 +265,7 @@ export const bottomBoxWindow = { vm.mainTableHeight = vm.$tableHeight.openSubList.mainList // 重置table高度 vm.tools.toTopBtnTop = vm.$tableHeight.openSubList.toTopBtnTop // 移动分页组件的位置 - const paginationTop = document.querySelector('.pagination-top') + /* const paginationTop = document.querySelector('.pagination-top') paginationTop.appendChild(document.querySelector('.pagination-bottom').removeChild(document.querySelector('.pagination'))) paginationTop.classList.remove('display-none') setTimeout(() => { @@ -275,7 +275,7 @@ export const bottomBoxWindow = { if (!paginationTop.classList.contains('pagination-top-show')) { paginationTop.classList.add('pagination-top-show') } - }, 210) + }, 210) */ } } } diff --git a/nezha-fronted/src/components/common/language/cn.js b/nezha-fronted/src/components/common/language/cn.js index 8d0293300..84917d151 100644 --- a/nezha-fronted/src/components/common/language/cn.js +++ b/nezha-fronted/src/components/common/language/cn.js @@ -48,6 +48,7 @@ const cn = { createAlertRule: '新增告警规则', createAccount: '新增用户名', createRole: '新增角色', + createTemplate: '新增模板', createPrometheusServer: '新增prometheus服务', createDatacenter: '新增数据中心', active: '活跃', @@ -641,12 +642,17 @@ const cn = { account: { accountList: '用户列表', account: '用户', + name: '姓名', // "用户" + username: '登录名', // 登录名 roles: '角色', language: '语言', receiver: '接收人', createTime: '创建时间', enable: '可用', option: '操作', + lastLoginTime: '最后登录时间', // 最后登录时间 + lastLoginIp: '最后登录IP', // 最后登录IP + source: '来源', accountId: '用户ID', createAccount: '新增用户', editAccount: '编辑用户', @@ -1000,6 +1006,7 @@ const cn = { exprTempImport: 'expression模板导入', exprTempExport: 'expression模板导出', exprTempImportCancel: 'expression模板导入撤销', + copy: '复制', name: '名称', gname: '组名', expression: '表达式', diff --git a/nezha-fronted/src/components/common/language/en.js b/nezha-fronted/src/components/common/language/en.js index 7a10f11ee..0700845bb 100644 --- a/nezha-fronted/src/components/common/language/en.js +++ b/nezha-fronted/src/components/common/language/en.js @@ -63,6 +63,7 @@ const en = { createMib: 'Create MIB', createAssetType: 'Create asset type', createAssetState: 'Create asset state', + createTemplate: 'Create template', exportExcel: 'Export', importExcel: 'Import', importExcelLower: 'import', @@ -640,19 +641,24 @@ const en = { config: { config: 'Settings', // "设置" account: { - accountList: 'Account list', // "用户列表" + accountList: 'User list', // "用户列表" + account: 'User', // 列表表头 - account: 'Account', // "用户" + name: 'Name', // "用户" + username: 'Username', // 登录名 roles: 'Role', language: 'Language', // "语言" receiver: 'Receiver', // "用户组" createTime: 'Create time', // "创建时间" enable: 'Enable', // "可用" option: 'Operation', // "操作" + lastLoginTime: 'Last login time', // 最后登录时间 + lastLoginIp: 'Last login IP', // 最后登录IP + source: 'Source', // 侧滑框// - accountId: 'Account ID', // "用户ID" - createAccount: 'New account', // "新增用户" - editAccount: 'Edit account', // "编辑用户" + accountId: 'User ID', // "用户ID" + createAccount: 'New user', // "新增用户" + editAccount: 'Edit user', // "编辑用户" notCurrentlySupport: 'Not available', // '暂不支持' password: 'Password', // '密码' oldPwd: 'Old password', @@ -1010,6 +1016,7 @@ const en = { exprTempImport: 'expression template import', exprTempExport: 'expression template export', exprTempImportCancel: 'expression template import rollback', + copy: 'Copy', name: 'Name', gname: 'Group', expression: 'Expression', diff --git a/nezha-fronted/src/components/common/mixin/table.js b/nezha-fronted/src/components/common/mixin/table.js index 00bf3ecb7..eaacb6287 100644 --- a/nezha-fronted/src/components/common/mixin/table.js +++ b/nezha-fronted/src/components/common/mixin/table.js @@ -1,12 +1,19 @@ import bus from '@/libs/bus' +import { tableSet } from '@/components/common/js/tools' +import { fromRoute } from '@/components/common/js/constants' export default { data () { return { + fromRoute: fromRoute, // 侧滑 rightBox: { show: false }, - + pageObj: { // 分页对象 + pageNo: 1, + pageSize: this.$CONSTANTS.defaultPageSize, + total: 0 + }, /* 工具参数 */ tools: { loading: false, // 是否显示table加载动画 @@ -19,24 +26,51 @@ export default { tableData: [], searchLabel: {}, // 搜索参数 scrollbarWrap: null, - delFlag: false + delFlag: false, + + operationWidth: "165" // 操作列宽 } }, methods: { - tableOperation ([command, row]) { + sortableShow: tableSet.sortableShow, + propTitle: tableSet.propTitle, + asce: tableSet.asce, + desc: tableSet.desc, + strTodate: tableSet.strTodate, + tableOperation ([command, row, url]) { switch (command) { case 'edit': { this.edit(row) break } case 'delete': { - this.del(row) + this.del(row, url) break } default: break } }, + isBuildIn (row) { + return (row.buildIn && row.buildIn == 1) || (row.builtIn && row.builtIn == 1) + }, + del (row, url) { + this.$confirm(this.$t('tip.confirmDelete'), { + confirmButtonText: this.$t('tip.yes'), + cancelButtonText: this.$t('tip.no'), + type: 'warning' + }).then(() => { + this.$delete(url).then(response => { + if (response.code === 200) { + this.delFlag = true + this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') }) + this.getTableData() + } else { + this.$message.error(response.msg) + } + }) + }) + }, newObject () { return JSON.parse(JSON.stringify(this.blankObject)) }, @@ -156,5 +190,10 @@ export default { : this.tableTitle this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) this.getTableData() + }, + beforeDestroy () { + if (this.scrollbarWrap) { + this.scrollbarWrap.removeEventListener('scroll', bus.debounce) + } } } diff --git a/nezha-fronted/src/components/common/popBox/selectAssetMetaGroup.vue b/nezha-fronted/src/components/common/popBox/selectAssetMetaGroup.vue new file mode 100644 index 000000000..43460c3ac --- /dev/null +++ b/nezha-fronted/src/components/common/popBox/selectAssetMetaGroup.vue @@ -0,0 +1,152 @@ +<template> + <el-popover ref="selectAssetMetaGroupPopBox" v-model="popBox.show" :placement="placement" popper-class="nz-pop nz-pop-select-panel" transition="slide" width="300"> + <div> + <div class="pop-item-wider"> + + <slot name="header"></slot> + + <div class="select-panel-tree"> + <el-tree + ref="tree" + :data="objectData" + :expand-on-click-node="false" + :filter-node-method="filterNode" + :props="{label: 'name', children: 'children'}" + check-on-click-node + check-strictly + default-expand-all + highlight-current + node-key="id" + @node-click="selectObject"> + <div slot-scope="{ node, data }" class="tree--node"> + <span>{{ node.label }}</span> + <span class="tree--operation"> + <span class="panel-dropdown-btn panel-dropdown-btn-delete" @click.stop="del(data)"><i class="nz-icon nz-icon-delete"></i></span> + <span class="panel-dropdown-btn" @click.stop="edit(data)"><i class="nz-icon nz-icon-edit"></i></span> + </span> + </div> + </el-tree> + </div> + </div> + </div> + <div slot="reference"> + <slot name="trigger"></slot> + </div> + </el-popover> +</template> + +<script> +export default { + name: 'selectAssetMetaGroup', + props: { + placement: { type: String }, + isEdit: { type: Boolean, default: true }, + objectData: { type: Array }, + showObject: { type: Object }, + filterObject: { type: String } + }, + mounted () { + this.$refs.tree.setCurrentKey(this.object) + }, + watch: { + filterObject: { + immediate: true, + handler (n) { + this.$refs.tree && this.$refs.tree.filter(n) + } + }, + showObject: { + immediate: true, + handler (n) { + if (n) { + this.object = JSON.parse(JSON.stringify(n)) + } + } + } + }, + data () { + return { + popBox: { show: false }, + object: { id: 0, name: '' } + } + }, + methods: { + filterNode (value, data) { + if (!value) return true + return data.name.indexOf(value) !== -1 + }, + del (data) { + this.$emit('del', data) + }, + edit (data) { + this.$emit('edit', data) + }, + esc () { + this.popBox.show = false + }, + // 确认选择某个节点,与父组件交互 + selectObject (data, checked, child) { + this.$emit('selectObject', data) + this.$refs.tree.setCurrentKey(data) + this.esc() + } + } +} +</script> + +<style lang="scss"> +.movable { + .el-tree-node__content { + cursor: move; + .tree--node>span:first-of-type { + cursor: pointer; + } + .tree--node>span:last-of-type>span { + cursor: pointer; + } + } +} +.tree--node>span:last-of-type>span>i { + font-weight: normal !important; +} +.select-panel-tree { + height: 350px; + overflow: auto; +} +.select-panel-tree .el-tree-node__content { + height: 34px; + line-height: 34px; +} +.select-panel-tree .el-tree-node__content:hover { + color: $global-text-color-active; +} +.select-panel-tree .el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content { + background-color: #F5F7FA; + font-weight: bold; + color: $global-text-color-active; +} +.tree--node { + display: flex; + justify-content: space-between; + width: calc(100% - 28px); +} +.tree--operation { + opacity: 0; +} +.tree--node:hover .tree--operation { + opacity: 1; +} +.panel-dropdown-btn { + color: #60BEFF; +} +.panel-dropdown-btn:hover { + color: #409EFF; +} +.panel-dropdown-btn-delete { + color: #F98D9A; +} + +.panel-dropdown-btn-delete:hover { + color: #D96D7A; +} +</style> diff --git a/nezha-fronted/src/components/common/rightBox/accountBox.vue b/nezha-fronted/src/components/common/rightBox/accountBox.vue index 620676836..debfb5b72 100644 --- a/nezha-fronted/src/components/common/rightBox/accountBox.vue +++ b/nezha-fronted/src/components/common/rightBox/accountBox.vue @@ -5,7 +5,7 @@ $--input-focus-border: red; <div class="right-box right-box-account" v-clickoutside="{obj:editUser,func:clickOutside}"> <!-- begin--顶部按钮--> <div class="right-box-top-btns right-box-form-delete"> - <button @click="del" type="button" v-has="'account_delete'" v-if="editUser.userId&&editUser.userId!==1" + <button v-if="editUser.id&&editUser.id!==1" v-has="'account_delete'" type="button" @click="del" class="nz-btn nz-btn-size-normal nz-btn-size-alien" id="account-edit-del"> <span class="right-box-top-btn-icon"><i class="nz-icon nz-icon-delete"></i></span> @@ -15,16 +15,16 @@ $--input-focus-border: red; <!-- end--顶部按钮--> <!-- begin--标题--> - <div class="right-box-title">{{editUser.userId ? ($t("config.account.editAccount") + " ID:" + editUser.userId) : $t("config.account.createAccount")}}</div> + <div class="right-box-title">{{editUser.id ? ($t("config.account.editAccount") + " ID:" + editUser.id) : $t("config.account.createAccount")}}</div> <!-- end--标题--> <!-- begin--表单--> <div class="right-box-form-box"> - <el-form :model="editUser" :rules="editUser.userId ? rules2 : rules" class="right-box-form right-box-form-left" label-position = "top" label-width="120px" ref="accountForm"> + <el-form ref="accountForm" :model="editUser" :rules="editUser.id ? rules2 : rules" class="right-box-form right-box-form-left" label-position = "top" label-width="120px"> <!--username--> <el-form-item :label="$t('config.account.account')" prop="username"> <el-input autocomplete="new-password" type="text" placeholder="" id="account-input-username" - v-model="editUser.username" maxlength="64" show-word-limit size="small" :disabled="editUser.username==='admin' && editUser.userId==1"></el-input> + v-model="editUser.username" :disabled="editUser.username==='admin' && editUser.id==1" maxlength="64" show-word-limit size="small"></el-input> </el-form-item> <!--password--> <el-form-item :label="$t('config.account.password')" prop="pin"> @@ -42,19 +42,19 @@ $--input-focus-border: red; </el-form-item> <!--enable--> <el-form-item :label="$t('config.account.enable')"> - <el-switch v-model="editUser.status" active-color="#ee9d3f" :disabled="isCurrentUser(editUser.username) || (editUser.username==='admin' && editUser.userId==1) " active-value="1" id="account-input-status" + <el-switch id="account-input-status" v-model="editUser.status" :disabled="isCurrentUser(editUser.username) || (editUser.username==='admin' && editUser.id==1) " active-color="#ee9d3f" active-value="1" inactive-value="0"> </el-switch> </el-form-item> <!--roles--> <el-form-item :label="$t('config.account.roles')" prop="roleIds"> - <el-select @change="()=>{this.$forceUpdate()}" clearable collapse-tags placeholder="" popper-class="config-dropdown" size="small" v-model="editUser.roleIds" :disabled="(editUser.username==='admin') && editUser.userId==1" id="account-input-roleIds"> + <el-select id="account-input-roleIds" v-model="editUser.roleIds" :disabled="(editUser.username==='admin') && editUser.id==1" clearable collapse-tags placeholder="" popper-class="config-dropdown" size="small" @change="()=>{this.$forceUpdate()}"> <template v-for="role in roles"> <el-option :key="role.id" :label="role.i18n?$t(role.i18n):role.name" :value="role.id"></el-option> </template> </el-select> </el-form-item> - <el-form-item :label="$t('config.account.createTime')" v-if="editUser.userId"> + <el-form-item v-if="editUser.id" :label="$t('config.account.createTime')"> <div class="right-box-form-content-txt">{{editUser.createTime}}</div> </el-form-item> @@ -180,8 +180,8 @@ export default { if (valid) { const editUser = JSON.parse(JSON.stringify(this.editUser)) editUser.roleIds = [editUser.roleIds] - if (this.editUser.userId) { - this.$put('sys/user/update', editUser).then(response => { + if (this.editUser.id) { + this.$put('sys/user', editUser).then(response => { this.prevent_opt.save = false if (response.code === 200) { this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') }) @@ -192,7 +192,7 @@ export default { }) } else { editUser.roleIds = this.roles.find(t => t.name == 'common').id - this.$post('sys/user/save', editUser).then(response => { + this.$post('sys/user', editUser).then(response => { this.prevent_opt.save = false if (response.code === 200) { this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') }) @@ -217,7 +217,7 @@ export default { cancelButtonText: this.$t('tip.no'), type: 'warning' }).then(() => { - this.$delete('sys/user/delete?userIds=' + this.editUser.userId).then(response => { + this.$delete('sys/user?ids=' + this.editUser.id).then(response => { if (response.code === 200) { this.$message({ duration: 1000, type: 'success', message: this.$t('tip.deleteSuccess') }) this.esc(true) diff --git a/nezha-fronted/src/components/common/table/nzDataList.vue b/nezha-fronted/src/components/common/table/nzDataList.vue index 36bd68362..0b45fef0b 100644 --- a/nezha-fronted/src/components/common/table/nzDataList.vue +++ b/nezha-fronted/src/components/common/table/nzDataList.vue @@ -5,11 +5,14 @@ <!-- 顶部工具栏 --> <div class="main-modal"></div> <div v-show="bottomBox.mainResizeShow" class="top-tools"> + <div class="top-tool-main-left" style="width: 300px"> + <slot name="top-tool-left"></slot> + </div> <div :class="{'top-tool-main-right-to-left': bottomBox.showSubList}" class="top-tool-main-right"> <div v-if="components.indexOf('searchInput') > -1" class="top-tool-search"> <search-input ref="searchInput" :inTransform="bottomBox.inTransform" :searchMsg="searchMsg" @search="search"></search-input> </div> - <slot name="top-tool"></slot> + <slot name="top-tool-right"></slot> <button v-if="components.indexOf('elementSet') > -1" id="account-column-setting" class="top-tool-btn margin-l-10" type="button" @click="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)"> <i class="nz-icon-gear nz-icon"></i> @@ -33,7 +36,7 @@ <div v-show="bottomBox.mainResizeShow" class="nz-table2"> <slot v-bind:mainResizeShow="bottomBox.mainResizeShow"></slot> </div> - <div v-show="!bottomBox.showSubList" class="pagination-bottom"> + <div class="pagination-bottom"> <slot name="pagination"></slot> </div> </div> @@ -45,16 +48,23 @@ :obj="bottomBox.object" :sub-resize-show="bottomBox.subResizeShow" :target-tab.sync="bottomBox.targetTab" - @closeSubList="bottomBox.showSubList = false" @exitFullScreen="exitFullScreen" @fullScreen="fullScreen" @listResize="listResize" ></bottom-box> + @closeSubList="bottomBox.showSubList = false" + @exitFullScreen="exitFullScreen" + @fullScreen="fullScreen" + @listResize="listResize" ></bottom-box> </transition> </div> </template> <script> +import bottomBox from '@/components/common/bottomBox/bottomBox' import { bottomBoxWindow } from '@/components/common/js/tools' export default { name: 'nzDataList', + components: { + bottomBox + }, props: { from: { type: String, diff --git a/nezha-fronted/src/components/layout/header.vue b/nezha-fronted/src/components/layout/header.vue index 04decdadb..879ffa3d7 100644 --- a/nezha-fronted/src/components/layout/header.vue +++ b/nezha-fronted/src/components/layout/header.vue @@ -343,7 +343,7 @@ export default { }, getUserData () { return new Promise(resolve => { - this.$get('sys/user/list', { pageSize: -1, pageNo: 1 }).then(response => { + this.$get('sys/user', { pageSize: -1, pageNo: 1 }).then(response => { if (response.code === 200) { this.userData = response.data.list } diff --git a/nezha-fronted/src/components/page/config/account2.vue b/nezha-fronted/src/components/page/config/account2.vue index aaa8121dc..d593777e7 100644 --- a/nezha-fronted/src/components/page/config/account2.vue +++ b/nezha-fronted/src/components/page/config/account2.vue @@ -7,13 +7,13 @@ :search-msg="searchMsg" :table-id="tableId" :table-title="tableTitle" - from="account"> - <template v-slot:top-tool> + :from="fromRoute.account"> + <template v-slot:top-tool-right> <button id="account-add" v-has="'account_toAdd'" :title="$t('overall.createAccount')" class="top-tool-btn margin-l-20" type="button" @click="add"> <i class="nz-icon-create-square nz-icon"></i> </button> - <delete-button id="account-list-batch-delete" v-has="'account_delete'" :delete-objs="batchDeleteObjs" :filter-function="(arr)=>{return '?userIds='+arr.map(t=>t.userId).join(',')}" api="sys/user/delete" @after="getTableData" @before="delFlag=true"></delete-button> + <delete-button id="account-list-batch-delete" v-has="'account_delete'" :delete-objs="batchDeleteObjs" api="sys/user" @after="getTableData" @before="delFlag=true"></delete-button> </template> <template v-slot:default="slotProps"> <el-table @@ -43,14 +43,12 @@ :resizable="true" :sort-orders="['ascending', 'descending']" :width="`${item.width}`" + :min-width="`${item.minWidth}`" class="data-column" > <template slot="header"> - <span v-if="item.type == 'tag'" :title="item.label" class="tag-header"><span class="tag-value">{{item.label}}</span><span class="tag-mark"> [Tag]</span></span> - <span v-else> - <span>{{item.label}}</span> - <div class="col-resize-area"></div> - </span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> </template> <template slot-scope="scope" :column="item"> <template v-if="item.prop === 'roles'"> @@ -63,35 +61,34 @@ <span>-</span> </template> </template> - <template v-else-if="item.prop == 'status'"> + <template v-else-if="item.prop === 'status'"> <el-switch v-model="scope.row.status" - :disabled="isCurrentUser(scope.row.username) || !hasButton('account_toEdit') || !hasButton('account_toAdd') || (scope.row.username==='admin' && scope.row.userId==1)" + :disabled="isCurrentUser(scope.row.username) || !hasButton('account_toEdit') || !hasButton('account_toAdd') || (scope.row.username==='admin' && scope.row.id==1)" active-color="#ee9d3f" active-value="1" inactive-value="0" @change="(val)=>{statusChange(scope.row)}"> </el-switch> </template> - <span v-else-if="item.prop == 'tags'">{{filterTags(item, scope)}}</span> - <span v-else-if="item.prop == 'createTime'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> + <span v-else-if="item.prop === 'createTime'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> <span v-else>{{scope.row[item.prop]}}</span> </template> </el-table-column> <el-table-column :resizable="false" fixed="right" - width="165"> + :width="operationWidth"> <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> <div slot-scope="scope" class="table-operation-items"> - <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLogTab', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> <el-dropdown size="medium" trigger="hover" @command="tableOperation"> <div class="table-operation-item table-operation-item--more"> <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> </div> <el-dropdown-menu slot="dropdown"> - <el-dropdown-item :command="['edit', scope.row]" ><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> - <el-dropdown-item :command="['delete', scope.row]" ><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + <el-dropdown-item :command="['edit', scope.row]"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `sys/user?ids=${scope.row.id}`]" :disabled="scope.row.id === 1"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> </el-dropdown-menu> </el-dropdown> </div> @@ -111,10 +108,9 @@ </div> </template> <script> -import deleteButton from '../../common/deleteButton' -import accountBox from '../../common/rightBox/accountBox' +import deleteButton from '@/components/common/deleteButton' +import accountBox from '@/components/common/rightBox/accountBox' import nzDataList from '@/components/common/table/nzDataList' -import bus from '../../../libs/bus' import tableMixin from '@/components/common/mixin/table' export default { name: 'account', @@ -128,7 +124,8 @@ export default { return { tableId: 'accountTable', // 需要分页的table的id,用于记录每页数量 blankObject: { // 空白对象 - userId: '', + id: '', + name: '', username: '', email: '', status: '1', @@ -139,37 +136,48 @@ export default { lang: '', notifications: [] }, - pageObj: { // 分页对象 - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, tableTitle: [ // 原table列 { label: 'ID', - prop: 'userId', + prop: 'id', show: true, width: 80 }, { - label: this.$t('config.account.account'), + label: this.$t('config.account.name'), + prop: 'name', + show: true, + width: 150 + }, { + label: this.$t('config.account.username'), prop: 'username', show: true, - width: 200 + width: 150 }, { label: this.$t('config.account.roles'), prop: 'roles', show: true, - width: 200 + width: 150 }, { label: 'E-mail', prop: 'email', - show: true + show: true, + minWidth: 150 }, { - label: this.$t('config.account.createTime'), - prop: 'createTime', + label: this.$t('config.account.lastLoginTime'), + prop: 'lastLoginTime', show: true, width: 200 }, { + label: this.$t('config.account.lastLoginIp'), + prop: 'lastLoginIp', + show: true, + width: 150 + }, { + label: this.$t('config.account.source'), + prop: 'source', + show: true, + width: 150 + }, { label: this.$t('config.account.enable'), prop: 'status', show: true, @@ -190,24 +198,6 @@ export default { } }, methods: { - del (u) { - if (u.userId == 1 && u.username === 'admin') { return } - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('sys/user/delete?userIds=' + u.userId).then(response => { - if (response.code === 200) { - this.delFlag = true - this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getTableData() - } else { - this.$message.error(response.msg) - } - }) - }) - }, getTableData () { if (!this.hasButton('account_view')) { this.$message.error(this.$t('tip.noAccess')) @@ -216,7 +206,7 @@ export default { this.$set(this.searchLabel, 'pageNo', this.pageObj.pageNo) this.$set(this.searchLabel, 'pageSize', this.pageObj.pageSize) this.tools.loading = true - this.$get('sys/user/list', this.searchLabel).then(response => { + this.$get('sys/user', this.searchLabel).then(response => { this.tools.loading = false if (response.code === 200) { for (let i = 0; i < response.data.list.length; i++) { @@ -233,25 +223,11 @@ export default { } }) }, - /* add () { - this.object = this.newObject() - if (!this.user.userId) { - this.user.roleIds = this.roles.find(t => t.name == 'common').id - } - this.rightBox.show = true - }, - edit (u) { - this.object = JSON.parse(JSON.stringify(u)) - if (!this.object.userId) { - this.object.roleIds = this.roles.find(t => t.name == 'common').id - } - this.rightBox.show = true - }, */ statusChange (user) { if (user.roles) { user.roleIds = user.roles.map(t => t.id) } - this.$put('sys/user/update', user).then(response => { + this.$put('sys/user', user).then(response => { if (response.code === 200) { this.rightBox.show = false this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') }) @@ -291,7 +267,7 @@ export default { result = result.concat(keepTags).concat(newTags) this.tools.customTableTitle = JSON.parse(JSON.stringify(result)) }) - }, + }/* , filterTags (head, scope) { if (scope.row.notifications) { const notification = scope.row.notifications.find(item => { @@ -301,12 +277,7 @@ export default { return notification.account } } - } - }, - beforeDestroy () { - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) - } + } */ }, computed: { isCurrentUser () { @@ -315,44 +286,9 @@ export default { } } }, - /*watch: { - 'bottomBox.showSubList': function (n) { - const vm = this - this.$bottomBoxWindow.showSubListWatch(vm, n) - }, - tableData: { - deep: true, - handler (n) { - if (n.length === 0 && this.pageObj.pageNo > 1) { - this.pageNo(this.pageObj.pageNo - 1) - } - - if (!this.delFlag) { // 不是删除时回到顶部 - this.$refs.dataTable.bodyWrapper.scrollTop = 0 - } else { - this.delFlag = false - } - } - } - },*/ - created () { - // 是否存在分页缓存 - /*const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize - }*/ - }, mounted () { this.getRoles() this.resetTableTitle() - // 初始化表头 - /*this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - - this.resetTableTitle() - this.getTableData()*/ } } </script> diff --git a/nezha-fronted/src/components/page/config/assetMeta.vue b/nezha-fronted/src/components/page/config/assetMeta.vue index cbce0524e..82f8f423b 100644 --- a/nezha-fronted/src/components/page/config/assetMeta.vue +++ b/nezha-fronted/src/components/page/config/assetMeta.vue @@ -1,129 +1,74 @@ <template> - <div class="main-list main-and-sub-transition" :class="{'main-list-with-sub': bottomBox.showSubList}"> - <!--工具组--> - <div class="top-tools" v-show="bottomBox.mainResizeShow"> - <div class="top-tool-main-right" :class="{'top-tool-main-right-to-left': bottomBox.showSubList}"> - <div class="top-tool-search margin-r-20"> - <search-input :searchMsg="searchMsg" @search="search" - :inTransform="bottomBox.inTransform" :single="true"></search-input> - </div> - <button :title="$t('overall.exportExcelLower')" @click="addMeta" type="button" v-has="'expr_temp_save'" - class="nz-btn nz-btn-size-normal nz-btn-style-light" id="meta-add-meta"> + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.role" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:top-tool-left> + <select-group ref="selectGroup" :filter-object="filterGroup" :object-data="groupData" :placement="'bottom-start'" + :show-object="showGroup" style="width: 300px;" @del="delGroup" @edit="editGroup" @selectObject="groupChange"> + <template v-slot:header> + <div class="panel-select-header"> + <el-input id="panel-list-search" v-model="filterGroup" :placeholder="$t('overall.search')" clearable size="mini" style="width: 240px; margin-right: 5px;"></el-input> + <span id="panel-list-toadd" v-has="'panel_toAdd'" :title='$t("dashboard.panel.createPanelTitleSec")' class="panel-select-add" @click="addGroup"><i class="nz-icon nz-icon-plus"></i></span> + </div> + </template> + <template v-slot:trigger> + <el-input v-model="showGroup.name" class="panel-name" placeholder="" readonly="readonly" size="small"></el-input> + </template> + </select-group> + </template> + <template v-slot:top-tool-right> + <button id="meta-add-meta" v-has="'expr_temp_save'" :title="$t('overall.exportExcelLower')" class="top-tool-btn margin-l-20" + type="button" @click="add"> <i class="nz-icon nz-icon-create-square"></i> </button> - - <delete-button :delete-objs="batchDeleteObjs" @after="getAssetMeta" + <delete-button :delete-objs="batchDeleteObjs" @after="getTableData" :api="'asset/field/meta'" v-has="'expr_temp_delete'" id="meta-msg-batch-delete"></delete-button> - </div> - <div class="pagination-top pagination-top-hide display-none"></div> - </div> - <!-- content --> - <div class="content"> - <div class="asset-meta-group"> - <div class="group-title"> - <span> - <button @click="addGroup" type="button" v-has="'asset:fieldgroup:add'" :disabled="metaGroupLock" - :class="{'nz-btn-disabled' : metaGroupLock}" - class="nz-btn nz-btn-size-normal nz-btn-style-light" id="meta-list-export"> - <i class="nz-icon nz-icon-create-square"></i> - </button> - <button @click="metaGroupLock=!metaGroupLock" class="nz-btn nz-btn-size-normal nz-btn-style-light" type="button" id="panel-lock"><i :class="{'nz-icon nz-icon-lock':metaGroupLock,'nz-icon nz-icon-unlock':!metaGroupLock}"></i></button> - </span> - </div> - <el-tree - :data="groupData" - :props="defaultProps" - :node-key="'id'" - @node-click="changeGroup" - ref="groupTree" - check-on-click-node - check-strictly - > - <div class="meta-group" slot-scope="{ node, data }"> - <div> - <i class="nz-icon nz-icon-reading" v-if="!data.children"></i> - <i class="el-icon-folder-opened" v-if="data.children"></i> - {{ node.label }} - </div> - <div v-if="!data.children&&!metaGroupLock" class="icon-box"> - <span :id="'asset-group-edit-'+node.id" :title="$t('overall.edit')" @click.stop="editGroup(data)" - class="content-right-option" v-has="'asset:fieldgroup:update'"> - <i class="nz-icon nz-icon-edit"></i> - </span> - <span - :id="'asset-group-del-'+node.id" - :title="$t('overall.delete')" - @click.stop="delGroup(data)" - class="content-right-option" - v-has="'asset:fieldgroup:delete'"> - <i class="nz-icon nz-icon-delete"></i> - </span> - </div> - </div> - </el-tree> - </div> - <div class="asset-meta-table"> - <!--表格开始--> - <transition name="el-zoom-in-top"> - <element-set - id="meta-rule-element-set" - v-if="tools.showCustomTableTitle" - @close="tools.showCustomTableTitle = false" - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - ref="customTableTitle" - ></element-set> - </transition> + </template> + <template v-slot:default="slotProps"> <el-table - id="meta-rule-table" - class="nz-table" + id="role-list-table" + ref="dataTable" + v-loading="tools.loading" :data="tableData" - border - v-show="bottomBox.mainResizeShow" - ref="assetMetaTable" - tooltip-effect="light" :height="mainTableHeight" - v-loading="tools.loading" - style="width: 100%;" + border + @header-dragend="dragend" @sort-change="tableDataSort" - @selection-change="(selection)=>{this.batchDeleteObjs=selection}" + @selection-change="(selection)=>{batchDeleteObjs=selection}" > <el-table-column :resizable="false" + align="center" type="selection" - width="40" - align="center"> + width="55"> </el-table-column> - <el-table-column - :resizable="true" v-for="(item, index) in tools.customTableTitle" v-if="item.show" :key="`col-${index}`" + :fixed="item.fixed" :label="item.label" - :show-overflow-tooltip="item.prop!=='matchers'" + :prop="item.prop" + :resizable="true" :sort-orders="['ascending', 'descending']" - :sortable="$tableSet.sortableShow(item.prop,'assetMeta')" - :prop="$tableSet.propTitle(item.prop,'assetMeta')" - :width="item.width" + :width="`${item.width}`" + class="data-column" > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> <template slot-scope="scope" :column="item"> - <div v-if="item.prop === 'option'" class="content-right-options"> - <span :id="'meta-edit-'+scope.row.id" :title="$t('overall.edit')" @click.stop="edit(scope.row)" - class="content-right-option" v-has="'expr_temp_update'"> - <i class="nz-icon nz-icon-edit"></i> - </span> - <span - :id="'meta-del-'+scope.row.id" - :title="$t('overall.delete')" - @click="del(scope.row)" - class="content-right-option" - v-has="'expr_temp_delete'"> - <i class="nz-icon nz-icon-delete"></i> - </span> - </div> - <div v-else-if=" item.prop === 'group' "> - {{scope.row[item.prop]?scope.row[item.prop].name:'-'}} + <div v-if="item.prop === 'group'"> + {{scope.row[item.prop] ? scope.row[item.prop].name : '-'}} </div> <div v-else-if=" item.prop === 'display' "> <el-switch @@ -147,51 +92,63 @@ <template v-else>-</template> </template> </el-table-column> - - <el-table-column width="28" :resizable="false"> - <template slot="header"> - <span @mousedown.stop="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)" - class="nz-table-gear"> - <i class="nz-icon nz-icon-gear"></i> - </span> - </template> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['edit', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `asset/field/meta?ids=${scope.row.id}`]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + </div> </el-table-column> </el-table> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" - @click="toTop(scrollbarWrap)" class="to-top" v-show="tools.showTopBtn && bottomBox.mainResizeShow" - id="meta-rule-toTop"><i class="nz-icon nz-icon-top"></i></button> - <!--表格结束--> - <!--分页部分--> - <div class="pagination-bottom" v-show="!bottomBox.showSubList"> - <Pagination :tableId="tableId" :pageObj="pageObj" @pageNo='pageNo' @pageSize='pageSize' - ref="Pagination"></Pagination> - </div> - </div> - </div> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> <!--侧滑--> <transition name="right-box"> - <assetMetaBox v-if="rightBox.metaShow" :assetMeta="assetMeta" @close="closeRightBox" - ref="assetMetaBox"></assetMetaBox> + <assetMetaBox v-if="rightBox.metaShow" ref="assetMetaBox" :asset-meta="object" + @close="closeRightBox"></assetMetaBox> </transition> <transition name="right-box"> <assetMetaGroup v-if="rightBox.groupShow" :metaGroup="metaGroup" @close="closeRightBox" - ref="assetMetaBox"></assetMetaGroup> + ref="assetMetaBox"></assetMetaGroup> </transition> </div> </template> <script> -import deleteButton from '../../common/deleteButton' -import assetMetaGroup from '../../common/rightBox/assetMetaGroup' -import assetMetaBox from '../../common/rightBox/assetMetaBox' +import deleteButton from '@/components/common/deleteButton' +import assetMetaGroup from '@/components/common/rightBox/assetMetaGroup' +import assetMetaBox from '@/components/common/rightBox/assetMetaBox' +import selectGroup from '@/components/common/popBox/selectAssetMetaGroup' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' export default { name: 'assetMeta', components: { - 'delete-button': deleteButton, + deleteButton, assetMetaGroup, - assetMetaBox + assetMetaBox, + selectGroup, + nzDataList }, + mixins: [tableMixin], data () { return { tableId: 'assetMeta', @@ -200,7 +157,6 @@ export default { metaShow: false, groupShow: false }, - metaGroupLock: true, tableTitle: [ { label: 'ID', @@ -251,31 +207,6 @@ export default { children: 'children', label: 'name' }, - tableData: [], - /* 二级列表相关 */ - mainTableHeight: this.$tableHeight.normal, // 主列表table高度 - /* 二级页面相关 */ - bottomBox: { - tabList: [], // 二级列表的标签 - tabDetailList: [], // 多个详情 - mainResizeShow: true, // dom高度改变时是否展示|隐藏 - subResizeShow: true, - isFullScreen: false, // 全屏状态 - showSubList: false, // 是否显示二级列表 - targetTab: '', // 显示二级列表中的哪个页签 - inTransform: false // 搜索框相关,搜索条件下拉框是否在transform里 - }, - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - /* 批量删除相关 */ - batchDeleteObjs: [], /* 搜素相关 */ searchMsg: { // 给搜索框子组件传递的信息 zheze_none: true, @@ -295,14 +226,8 @@ export default { } ] }, - searchLabel: {}, // 搜索参数 - pageObj: { - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, // 创建修改相关 - blackAssetMeta: { + blankObject: { id: '', name: '', metaKey: '', @@ -313,44 +238,33 @@ export default { param: {}, remark: '' }, - assetMeta: { - - }, - blackMetaGroup: { + object: {}, + blankMetaGroup: { id: '', name: '', remark: '' }, - activeGroupId: -1, - metaGroup: { - - } + filterGroup: '', + showGroup: { name: '' }, + metaGroup: {} } }, mounted () { - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - this.initEvent() + this.getGroup() + this.showGroup = this.groupData[0] }, methods: { - initEvent () { - this.$refs.groupTree.setCurrentKey(this.activeGroupId) - this.getGroup() - this.getAssetMeta() - }, getGroup () { this.$get('asset/field/group', { pageSize: -1 }).then(response => { this.tools.loading = false if (response.code == 200) { - this.groupData[0].children = response.data.list + this.groupData = [this.groupData[0]] + this.groupData = this.groupData.concat(response.data.list) this.$forceUpdate() } }) }, - getAssetMeta () { + getTableData () { this.$set(this.searchLabel, 'pageNo', this.pageObj.pageNo) this.$set(this.searchLabel, 'pageSize', this.pageObj.pageSize) this.tools.loading = true @@ -363,60 +277,21 @@ export default { this.tableData = response.data.list this.pageObj.total = response.data.total this.nowTime = this.utcTimeToTimezoneStr(response.time) - // console.info(this.$refs.assetMetaTable) + // console.info(this.$refs.dataTable) if (!this.scrollbarWrap) { this.$nextTick(() => { - this.scrollbarWrap = this.$refs.assetMetaTable.bodyWrapper + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper this.toTopBtnHandler(this.scrollbarWrap) }) } } }) }, - pageNo (val) { - this.pageObj.pageNo = val - this.getAssetMeta() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getAssetMeta() - }, - search (searchObj) { - let orderBy = '' - if (this.searchLabel.orderBy) { - orderBy = this.searchLabel.orderBy - } - this.searchLabel = {} - this.pageObj.pageNo = 1 - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (orderBy) { - this.$set(this.searchLabel, 'orderBy', orderBy) - } - this.$refs.assetMetaTable.bodyWrapper.scrollTop = 0 - this.getAssetMeta() - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getAssetMeta() - }, afterTableListChange () { - this.getAssetMeta() + this.getTableData() }, addGroup () { - this.metaGroup = JSON.parse(JSON.stringify(this.blackMetaGroup)) + this.metaGroup = JSON.parse(JSON.stringify(this.blankMetaGroup)) this.rightBox.groupShow = true }, editGroup (group) { @@ -424,11 +299,10 @@ export default { this.rightBox.groupShow = true }, delGroup (group) { - const selectKey = this.$refs.groupTree.getCurrentKey() + const selectKey = this.$refs.selectGroup.$refs.tree.getCurrentKey() if (this.prevent_opt.save) { return } - ; this.prevent_opt.save = true this.$confirm(this.$t('tip.confirmDelete'), { confirmButtonText: this.$t('tip.yes'), @@ -442,10 +316,10 @@ export default { this.getGroup() if (selectKey === group.id) { - this.activeGroupId = -1 + this.showGroup = -1 this.searchLabel.groupId = '' - this.getAssetMeta() - this.$refs.groupTree.setCurrentKey(this.activeGroupId) + this.getTableData() + this.$refs.selectGroup.$refs.tree.setCurrentKey(this.showGroup) } } else { this.$message.error(response.msg) @@ -455,13 +329,13 @@ export default { this.prevent_opt.save = false }) }, - changeGroup (item) { - this.activeGroupId = item.id + groupChange (item) { + this.showGroup = item this.searchLabel.groupId = item.id !== -1 ? item.id : '' - this.getAssetMeta() + this.getTableData() }, - addMeta () { - this.assetMeta = JSON.parse(JSON.stringify(this.blackAssetMeta)) + add () { + this.assetMeta = JSON.parse(JSON.stringify(this.blankObject)) this.rightBox.metaShow = true }, edit (row) { @@ -479,31 +353,7 @@ export default { } else { this.$message.error(response.msg) } - this.getAssetMeta() - }) - }, - del (row) { - if (this.prevent_opt.save) { - return - } - ; - this.prevent_opt.save = true - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('asset/field/meta?ids=' + row.id).then(response => { - this.prevent_opt.save = false - if (response.code === 200) { - this.$message({ type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getAssetMeta() - } else { - this.$message.error(response.msg) - } - }) - }).catch(() => { - this.prevent_opt.save = false + this.getTableData() }) }, closeRightBox (refresh) { @@ -511,7 +361,7 @@ export default { this.rightBox.groupShow = false if (refresh) { this.delFlag = true - this.getAssetMeta() + this.getTableData() this.getGroup() } } @@ -571,4 +421,8 @@ export default { .meta-group:hover .icon-box{ display: inline-block; } + + .panel-select-header { + padding: 0 0 10px 16px; + } </style> diff --git a/nezha-fronted/src/components/page/config/assetState.vue b/nezha-fronted/src/components/page/config/assetState.vue index d23903796..d1a135a14 100644 --- a/nezha-fronted/src/components/page/config/assetState.vue +++ b/nezha-fronted/src/components/page/config/assetState.vue @@ -1,175 +1,141 @@ -<style scoped> - .asset-state { - height: 100%; - } -</style> <template> - <div class="asset-state"> - <!-- 主页面 --> - <div :class="{'main-list-with-sub': bottomBox.showSubList}" class="main-list"> - <!-- 顶部工具栏 --> - <div class="main-modal"></div> - <div class="top-tools" v-show="bottomBox.mainResizeShow"> - <div :class="{'top-tool-main-right-to-left': bottomBox.showSubList}" class="top-tool-main-right"> - <div class="top-tool-search"> - <search-input :inTransform="bottomBox.inTransform" :searchMsg="searchMsg" @search="search" ref="searchInput"></search-input> - </div> - <button :title="$t('overall.createassetState')" @click="add" class="nz-btn nz-btn-size-normal nz-btn-style-light margin-l-20" id="assetState-add" - type="button" v-has="'assetState_toAdd'"> - <i class="nz-icon-create-square nz-icon"></i> - </button> - <delete-button :delete-objs="batchDeleteObjs" :filter-function="(arr)=>{return '?ids='+arr.map(t=>t.id).join(',')}" @after="getTableData" @before="delFlag=true" api="/asset/stateConf" id="asset-state-list-batch-delete" v-has="'assetState_delete'"></delete-button> - </div> - <!-- 顶部分页组件,当打开底部上滑框时出现 --> - <div class="pagination-top pagination-top-hide display-none"></div> - </div> - <!-- 自定义table列 --> - <transition name="el-zoom-in-top"> - <element-set - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - @close="tools.showCustomTableTitle = false" - id="assetStateList" - ref="customTableTitle" - v-if="tools.showCustomTableTitle" - ></element-set> - </transition> - <el-table - :data="tableData" - :height="mainTableHeight" - :id="tableId" - @selection-change="(selection)=>{this.batchDeleteObjs=selection}" - @sort-change="tableDataSort" - border - class="nz-table" - ref="assetStateTable" - style="width: 100%;" - v-loading="tools.loading" - v-show="bottomBox.mainResizeShow" - > - <el-table-column - :resizable="false" - align="center" - type="selection" - width="40"> - </el-table-column> - <el-table-column - :fixed="item.fixed" - :key="`col-${index}`" - :label="item.label" - :prop="item.prop" - :resizable="true" - :sort-orders="['ascending', 'descending']" - v-for="(item, index) in tools.customTableTitle" - v-if="item.show" + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.assetState" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:top-tool-right> + <button id="assetState-add" v-has="'assetState_toAdd'" :title="$t('overall.createAssetState')" class="top-tool-btn margin-l-20" + type="button" @click="add"> + <i class="nz-icon-create-square nz-icon"></i> + </button> + <delete-button id="asset-state-list-batch-delete" v-has="'assetState_delete'" :delete-objs="batchDeleteObjs" api="/asset/stateConf" @after="getTableData" @before="delFlag=true"></delete-button> + </template> + <template v-slot:default="slotProps"> + <el-table + id="role-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" > - <template :column="item" slot-scope="scope"> - <el-switch - :active-value="1" - :disabled="!hasButton('assetState_toEdit')" - :inactive-value="0" - @change="(val)=>{statusChange(scope.row)}" - active-color="#ee9d3f" - v-if="item.prop == 'ping'" - v-model="scope.row.ping"> - </el-switch> - <el-switch - :active-value="1" - :disabled="!hasButton('assetState_toEdit')" - :inactive-value="0" - @change="(val)=>{statusChange(scope.row)}" - active-color="#ee9d3f" - v-else-if="item.prop == 'monitor'" - v-model="scope.row.monitor"> - </el-switch> - <el-switch - :active-value="1" - :disabled="!hasButton('assetState_toEdit')" - :inactive-value="0" - @change="(val)=>{statusChange(scope.row)}" - active-color="#ee9d3f" - v-else-if="item.prop == 'alert'" - v-model="scope.row.alert"> - </el-switch> - <div class="content-right-options" v-if="item.prop == 'option'"> - <span :id="'assetState-edit-'+scope.row.id" :title="$t('overall.edit')" @click="edit(scope.row)" class="content-right-option" v-has="'assetState_toEdit'"><i class="nz-icon nz-icon-edit"></i></span> - - <span :id="'assetState-del-'+scope.row.id" :title="$t('overall.delete')" @click="del(scope.row)" class="content-right-option" v-has="'assetState_delete'"><i class="nz-icon nz-icon-delete"></i></span> + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> + <template slot-scope="scope" :column="item"> + <el-switch + v-if="item.prop === 'ping'" + v-model="scope.row.ping" + :active-value="1" + :disabled="!hasButton('assetState_toEdit')" + :inactive-value="0" + active-color="#ee9d3f" + @change="(val)=>{statusChange(scope.row)}"> + </el-switch> + <el-switch + v-else-if="item.prop === 'monitor'" + v-model="scope.row.monitor" + :active-value="1" + :disabled="!hasButton('assetState_toEdit')" + :inactive-value="0" + active-color="#ee9d3f" + @change="(val)=>{statusChange(scope.row)}"> + </el-switch> + <el-switch + v-else-if="item.prop === 'alert'" + v-model="scope.row.alert" + :active-value="1" + :disabled="!hasButton('assetState_toEdit')" + :inactive-value="0" + active-color="#ee9d3f" + @change="(val)=>{statusChange(scope.row)}"> + </el-switch> + <span v-else>{{scope.row[item.prop]}}</span> + </template> + </el-table-column> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['edit', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `/asset/stateConf?ids=${scope.row.id}`]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> </div> - <span v-else>{{scope.row[item.prop]}}</span> - </template> - </el-table-column> - <el-table-column fixed="right" width="28"> - <template slot="header" :resizable="false"> - <span @mousedown.stop="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)" class="nz-table-gear"> - <i class="nz-icon nz-icon-gear"></i> - </span> - </template> - </el-table-column> - </el-table> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" @click="toTop(scrollbarWrap)" class="to-top" id="assetState-list-totop" v-show="tools.showTopBtn && bottomBox.mainResizeShow"><i class="nz-icon nz-icon-top"></i></button> - <div class="pagination-bottom" v-show="!bottomBox.showSubList"> - <Pagination :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"></Pagination> - </div> - </div> - + </el-table-column> + </el-table> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> <transition name="right-box"> - <asset-state-box :asset-state="assetState" :asset-state-data="assetStateData" @close="closeRightBox" v-if="rightBox.show"></asset-state-box> + <asset-state-box v-if="rightBox.show" :asset-state="object" :asset-state-data="assetStateData" @close="closeRightBox"></asset-state-box> </transition> </div> </template> <script> -import deleteButton from '../../common/deleteButton' -import assetStateBox from '../../common/rightBox/assetStateBox' -import bus from '../../../libs/bus' +import assetStateBox from '@/components/common/rightBox/assetStateBox' +import deleteButton from '@/components/common/deleteButton' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' export default { name: 'asset-state-list', components: { - 'delete-button': deleteButton, - 'asset-state-box': assetStateBox + deleteButton, + assetStateBox, + nzDataList }, + mixins: [tableMixin], data () { return { - // 侧滑 - rightBox: { - show: false - }, - /* 二级页面相关 */ - bottomBox: { - assetStateDetail: {}, - assetState: {}, - mainResizeShow: true, // dom高度改变时是否展示|隐藏 - subResizeShow: true, - isFullScreen: false, // 全屏状态 - showSubList: false, // 是否显示二级列表 - targetTab: '', // 显示二级列表中的哪个页签 - inTransform: false // 搜索框相关,搜索条件下拉框是否在transform里 - }, - - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - mainTableHeight: this.$tableHeight.normal, // 主列表table高度 - batchDeleteObjs: [], - assetState: {}, assetStateData: [], tableId: 'assetStateTable', // 需要分页的table的id,用于记录每页数量 - blankAssetState: { // 空白对象 + blankObject: { // 空白对象 id: '', name: '', ping: 0, monitor: 0, alert: 0, remark: '' }, - pageObj: { // 分页对象 - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, tableTitle: [ // 原table列 { label: 'ID', @@ -200,15 +166,8 @@ export default { label: this.$t('overall.remark'), prop: 'remark', show: true - }, { - label: this.$t('overall.option'), - prop: 'option', - show: true, - width: 120, - fixed: 'right' } ], - tableData: [], searchMsg: { // 给搜索框子组件传递的信息 zheze_none: true, searchLabelList: [{ @@ -218,61 +177,10 @@ export default { label: 'name', disabled: false }] - }, - searchLabel: {}, // 搜索参数 - scrollbarWrap: null, - delFlag: false + } } }, methods: { - // 全屏 - /* fullScreen() { - let vm = this; - this.$bottomBoxWindow.fullScreen(vm); - }, */ - // 退出全屏 - /* exitFullScreen() { - let vm = this; - this.$bottomBoxWindow.exitFullScreen(vm); - }, */ - // 鼠标拖动二级列表 - /* listResize(e) { - let vm = this; - this.$bottomBoxWindow.listResize(vm, e); - }, */ - closeRightBox (refresh) { - this.rightBox.show = false - if (refresh) { - this.delFlag = true - this.getTableData() - } - }, - edit (u) { - this.assetState = JSON.parse(JSON.stringify(u)) - this.rightBox.show = true - }, - /* detail(u) { - this.bottomBox.assetState = JSON.parse(JSON.stringify(u)); - this.bottomBox.targetTab = "detail"; - this.bottomBox.showSubList = true; - }, */ - del (u) { - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('/asset/stateConf?ids=' + u.id).then(response => { - if (response.code === 200) { - this.delFlag = true - this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getTableData() - } else { - this.$message.error(response.msg) - } - }) - }) - }, statusChange (obj) { this.$nextTick(() => { this.$put('/asset/stateConf', obj).then(response => { @@ -312,92 +220,7 @@ export default { } } }) - }, - add () { - this.assetState = this.newAssetState() - this.rightBox.show = true - }, - esc () { - this.rightBox.show = false - }, - newAssetState () { - return JSON.parse(JSON.stringify(this.blankAssetState)) - }, - pageNo (val) { - this.pageObj.pageNo = val - this.getTableData() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getTableData() - }, - search (searchObj) { - this.searchLabel = {} - this.pageObj.pageNo = 1 - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (this.$refs.assetStateTable) { - this.$refs.assetStateTable.bodyWrapper.scrollTop = 0 - } - this.getTableData() - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getTableData() - } - }, - beforeDestroy () { - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) } - }, - watch: { - 'bottomBox.showSubList': function (n) { - const vm = this - this.$bottomBoxWindow.showSubListWatch(vm, n) - }, - tableData: { - deep: true, - handler (n) { - if (n.length === 0 && this.pageObj.pageNo > 1) { - this.pageNo(this.pageObj.pageNo - 1) - } - - if (!this.delFlag) { // 不是删除时回到顶部 - this.$refs.assetStateTable.bodyWrapper.scrollTop = 0 - } else { - this.delFlag = false - } - } - } - }, - created () { - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize - } - }, - mounted () { - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - - this.getTableData() } } </script> diff --git a/nezha-fronted/src/components/page/config/assetType.vue b/nezha-fronted/src/components/page/config/assetType.vue index b1818229c..c92ce94e5 100644 --- a/nezha-fronted/src/components/page/config/assetType.vue +++ b/nezha-fronted/src/components/page/config/assetType.vue @@ -1,184 +1,150 @@ -<style scoped> - .asset-type { - height: 100%; - } -</style> <template> - <div class="asset-type"> - <!-- 主页面 --> - <div :class="{'main-list-with-sub': bottomBox.showSubList}" class="main-list"> - <!-- 顶部工具栏 --> - <div class="main-modal"></div> - <div class="top-tools" v-show="bottomBox.mainResizeShow"> - <div :class="{'top-tool-main-right-to-left': bottomBox.showSubList}" class="top-tool-main-right"> - <div class="top-tool-search"> - <search-input :inTransform="bottomBox.inTransform" :searchMsg="searchMsg" @search="search" ref="searchInput"></search-input> - </div> - <button :title="$t('overall.createAssetType')" @click="add" class="nz-btn nz-btn-size-normal nz-btn-style-light margin-l-20" id="assetType-add" - type="button" v-has="'assetType_toAdd'"> - <i class="nz-icon-create-square nz-icon"></i> - </button> - <delete-button :delete-objs="batchDeleteObjs" :filter-function="(arr)=>{return '?ids='+arr.map(t=>t.id).join(',')}" @after="getTableData" @before="delFlag=true" api="/asset/typeConf" id="asset-type-list-batch-delete" v-has="'assetType_delete'"></delete-button> - </div> - <!-- 顶部分页组件,当打开底部上滑框时出现 --> - <div class="pagination-top pagination-top-hide display-none"></div> - </div> - <!-- 自定义table列 --> - <transition name="el-zoom-in-top"> - <element-set - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - @close="tools.showCustomTableTitle = false" - id="assetTypeList" - ref="customTableTitle" - v-if="tools.showCustomTableTitle" - ></element-set> - </transition> - <el-table - :data="tableData" - :height="mainTableHeight" - :id="tableId" - @selection-change="(selection)=>{this.batchDeleteObjs=selection}" - @sort-change="tableDataSort" - border - class="nz-table" - ref="assetTypeTable" - style="width: 100%;" - v-loading="tools.loading" - v-show="bottomBox.mainResizeShow" - > - <el-table-column - :resizable="false" - align="center" - type="selection" - width="40"> - </el-table-column> - <el-table-column - :fixed="item.fixed" - :key="`col-${index}`" - :label="item.label" - :prop="item.prop" - :resizable="true" - :sort-orders="['ascending', 'descending']" - v-for="(item, index) in tools.customTableTitle" - v-if="item.show" + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.assetType" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:top-tool-right> + <button id="assetType-add" v-has="'assetType_toAdd'" :title="$t('overall.createAssetType')" class="top-tool-btn margin-l-20" + type="button" @click="add"> + <i class="nz-icon-create-square nz-icon"></i> + </button> + <delete-button id="asset-type-list-batch-delete" v-has="'assetType_delete'" :delete-objs="batchDeleteObjs" api="asset/typeConf" @after="getTableData" @before="delFlag=true"></delete-button> + </template> + <template v-slot:default="slotProps"> + <el-table + id="role-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" > - <template :column="item" slot-scope="scope"> - <el-switch - :active-value="1" - :disabled="scope.row.buildIn == 1 || !hasButton('assetType_toEdit')" - :inactive-value="0" - @change="(val)=>{statusChange(scope.row)}" - active-color="#ee9d3f" - v-if="item.prop == 'vm'" - v-model="scope.row.vm"> - </el-switch> - <el-switch - :active-value="1" - :disabled="scope.row.buildIn == 1 || !hasButton('assetType_toEdit')" - :inactive-value="0" - @change="(val)=>{statusChange(scope.row)}" - active-color="#ee9d3f" - v-else-if="item.prop == 'vmh'" - v-model="scope.row.vmh"> - </el-switch> - <el-switch - :active-value="1" - :disabled="scope.row.buildIn == 1 || !hasButton('assetType_toEdit')" - :inactive-value="0" - @change="(val)=>{statusChange(scope.row)}" - active-color="#ee9d3f" - v-else-if="item.prop == 'ssh'" - v-model="scope.row.ssh"> - </el-switch> - <el-switch - :active-value="1" - :disabled="scope.row.buildIn == 1 || !hasButton('assetType_toEdit')" - :inactive-value="0" - @change="(val)=>{statusChange(scope.row)}" - active-color="#ee9d3f" - v-else-if="item.prop == 'telnet'" - v-model="scope.row.telnet"> - </el-switch> - <div class="content-right-options" v-else-if="item.prop == 'option' && scope.row.buildIn != 1"> - <span :id="'assetType-edit-'+scope.row.id" :title="$t('overall.edit')" @click="edit(scope.row)" class="content-right-option" v-has="'assetType_toEdit'"><i class="nz-icon nz-icon-edit"></i></span> - - <span :id="'assetType-del-'+scope.row.id" :title="$t('overall.delete')" @click="del(scope.row)" class="content-right-option" v-has="'assetType_delete'"><i class="nz-icon nz-icon-delete"></i></span> + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> + <template slot-scope="scope" :column="item"> + <el-switch + v-if="item.prop === 'vm'" + v-model="scope.row.vm" + :active-value="1" + :disabled="scope.row.buildIn === 1 || !hasButton('assetType_toEdit')" + :inactive-value="0" + active-color="#ee9d3f" + @change="(val)=>{statusChange(scope.row)}"> + </el-switch> + <el-switch + v-else-if="item.prop === 'vmh'" + v-model="scope.row.vmh" + :active-value="1" + :disabled="scope.row.buildIn === 1 || !hasButton('assetType_toEdit')" + :inactive-value="0" + active-color="#ee9d3f" + @change="(val)=>{statusChange(scope.row)}"> + </el-switch> + <el-switch + v-else-if="item.prop === 'ssh'" + v-model="scope.row.ssh" + :active-value="1" + :disabled="scope.row.buildIn === 1 || !hasButton('assetType_toEdit')" + :inactive-value="0" + active-color="#ee9d3f" + @change="(val)=>{statusChange(scope.row)}"> + </el-switch> + <el-switch + v-else-if="item.prop === 'telnet'" + v-model="scope.row.telnet" + :active-value="1" + :disabled="scope.row.buildIn === 1 || !hasButton('assetType_toEdit')" + :inactive-value="0" + active-color="#ee9d3f" + @change="(val)=>{statusChange(scope.row)}"> + </el-switch> + <span v-else>{{scope.row[item.prop]}}</span> + </template> + </el-table-column> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['edit', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `asset/typeConf?ids=${scope.row.id}`]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> </div> - <span v-else>{{scope.row[item.prop]}}</span> - </template> - </el-table-column> - <el-table-column fixed="right" width="28"> - <template slot="header" :resizable="false"> - <span @mousedown.stop="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)" class="nz-table-gear"> - <i class="nz-icon nz-icon-gear"></i> - </span> - </template> - </el-table-column> - </el-table> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" @click="toTop(scrollbarWrap)" class="to-top" id="assetType-list-totop" v-show="tools.showTopBtn && bottomBox.mainResizeShow"><i class="nz-icon nz-icon-top"></i></button> - <div class="pagination-bottom" v-show="!bottomBox.showSubList"> - <Pagination :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"></Pagination> - </div> - </div> - + </el-table-column> + </el-table> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> <transition name="right-box"> - <asset-type-box :asset-type="assetType" :asset-type-data="assetTypeData" @close="closeRightBox" v-if="rightBox.show"></asset-type-box> + <asset-type-box v-if="rightBox.show" :asset-type="object" :asset-type-data="assetTypeData" @close="closeRightBox"></asset-type-box> </transition> </div> </template> <script> -import deleteButton from '../../common/deleteButton' -import assetTypeBox from '../../common/rightBox/assetTypeBox' -import bus from '../../../libs/bus' +import assetTypeBox from '@/components/common/rightBox/assetTypeBox' +import deleteButton from '@/components/common/deleteButton' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' export default { name: 'asset-type-list', components: { - 'delete-button': deleteButton, - 'asset-type-box': assetTypeBox + deleteButton, + assetTypeBox, + nzDataList }, + mixins: [tableMixin], data () { return { - // 侧滑 - rightBox: { - show: false - }, - /* 二级页面相关 */ - bottomBox: { - assetTypeDetail: {}, - assetType: {}, - mainResizeShow: true, // dom高度改变时是否展示|隐藏 - subResizeShow: true, - isFullScreen: false, // 全屏状态 - showSubList: false, // 是否显示二级列表 - targetTab: '', // 显示二级列表中的哪个页签 - inTransform: false // 搜索框相关,搜索条件下拉框是否在transform里 - }, - - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - mainTableHeight: this.$tableHeight.normal, // 主列表table高度 - batchDeleteObjs: [], - assetType: {}, assetTypeData: [], tableId: 'assetTypeTable', // 需要分页的table的id,用于记录每页数量 - blankAssetType: { // 空白对象 + blankObject: { // 空白对象 id: '', pid: '', pname: '', name: '', vm: 0, vmh: 0, ssh: 0, telnet: 0, buildIn: 0, remark: '' }, - pageObj: { // 分页对象 - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, tableTitle: [ // 原table列 { label: 'ID', @@ -213,12 +179,6 @@ export default { label: this.$t('overall.remark'), prop: 'remark', show: true - }, { - label: this.$t('overall.option'), - prop: 'option', - show: true, - width: 120, - fixed: 'right' } ], tableData: [], @@ -231,63 +191,10 @@ export default { label: 'name', disabled: false }] - }, - searchLabel: {}, // 搜索参数 - scrollbarWrap: null, - delFlag: false + } } }, methods: { - // 全屏 - /* fullScreen() { - let vm = this; - this.$bottomBoxWindow.fullScreen(vm); - }, */ - // 退出全屏 - /* exitFullScreen() { - let vm = this; - this.$bottomBoxWindow.exitFullScreen(vm); - }, */ - // 鼠标拖动二级列表 - /* listResize(e) { - let vm = this; - this.$bottomBoxWindow.listResize(vm, e); - }, */ - closeRightBox (refresh) { - this.rightBox.show = false - if (refresh) { - this.delFlag = true - this.getAssetTypeTreeData() - this.getTableData() - } - }, - edit (u) { - this.assetType = JSON.parse(JSON.stringify(u)) - this.rightBox.show = true - }, - /* detail(u) { - this.bottomBox.assetType = JSON.parse(JSON.stringify(u)); - this.bottomBox.targetTab = "detail"; - this.bottomBox.showSubList = true; - }, */ - del (u) { - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('/asset/typeConf?ids=' + u.id).then(response => { - if (response.code === 200) { - this.delFlag = true - this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getTableData() - this.getAssetTypeTreeData() - } else { - this.$message.error(response.msg) - } - }) - }) - }, getAssetTypeTreeData () { this.$get('/asset/typeConf/tree').then(response => { if (response.code === 200) { @@ -322,10 +229,6 @@ export default { } }) }, - add () { - this.assetType = this.newAssetType() - this.rightBox.show = true - }, statusChange (obj) { this.$nextTick(() => { this.$put('/asset/typeConf', obj).then(response => { @@ -338,89 +241,10 @@ export default { this.getTableData() }) }) - }, - esc () { - this.rightBox.show = false - }, - newAssetType () { - return JSON.parse(JSON.stringify(this.blankAssetType)) - }, - pageNo (val) { - this.pageObj.pageNo = val - this.getTableData() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getTableData() - }, - search (searchObj) { - this.searchLabel = {} - this.pageObj.pageNo = 1 - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (this.$refs.assetTypeTable) { - this.$refs.assetTypeTable.bodyWrapper.scrollTop = 0 - } - this.getTableData() - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getTableData() - } - }, - beforeDestroy () { - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) - } - }, - watch: { - 'bottomBox.showSubList': function (n) { - const vm = this - this.$bottomBoxWindow.showSubListWatch(vm, n) - }, - tableData: { - deep: true, - handler (n) { - if (n.length === 0 && this.pageObj.pageNo > 1) { - this.pageNo(this.pageObj.pageNo - 1) - } - - if (!this.delFlag) { // 不是删除时回到顶部 - this.$refs.assetTypeTable.bodyWrapper.scrollTop = 0 - } else { - this.delFlag = false - } - } - } - }, - created () { - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize } }, mounted () { - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - this.getAssetTypeTreeData() - this.getTableData() } } </script> diff --git a/nezha-fronted/src/components/page/config/dc.vue b/nezha-fronted/src/components/page/config/dc.vue index 0f59757fd..f72c108eb 100644 --- a/nezha-fronted/src/components/page/config/dc.vue +++ b/nezha-fronted/src/components/page/config/dc.vue @@ -1,55 +1,32 @@ -<style lang="scss"> -@import '@/assets/css/common/tableCommon.scss'; -</style> <template> - <div class="dc list-page"> - <!--dc table start--> - <div class="main-list" :class="{'main-list-with-sub': bottomBox.showSubList}"> - <div class="main-modal"></div> - <div class="top-tools" v-show="bottomBox.mainResizeShow"> - <div class="top-tool-main-right" :class="{'top-tool-main-right-to-left-small': bottomBox.showSubList}"> - <div class="top-tool-search"> - <search-input ref="searchInput" :searchMsg="searchMsg" @search="search" :inTransform="bottomBox.inTransform"></search-input> - </div> - <button :title="$t('overall.createDatacenter')" @click="add" type="button" v-has="'dc_toAdd'" - id="dc-add" class="top-tool-btn margin-l-20"> - <i class="nz-icon-create-square nz-icon"></i> - </button> - <button :title="$t('overall.createDatacenter')" @click="toDownloadAgent" type="button" id="load-agent" class="top-tool-btn margin-l-20"> - <i class="nz-icon-download nz-icon"></i> - </button> - <delete-button :delete-objs="batchDeleteObjs" @before="delFlag=true" @after="getTableData" api="idc" v-has="'dc_delete'" id="dc-list-batch-delete"></delete-button> - <button id="account-column-setting" class="top-tool-btn margin-l-10" - type="button" @click="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)"> - <i class="nz-icon-gear nz-icon"></i> - </button> - </div> - <div class="pagination-top pagination-top-hide display-none"></div> - </div> - <!-- 自定义table列 --> - <transition name="el-zoom-in-top"> - <element-set - id="dc-list" - v-if="tools.showCustomTableTitle" - @close="tools.showCustomTableTitle = false" - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - ref="customTableTitle" - ></element-set> - </transition> - <div class="nz-table2"> + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.dc" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:top-tool-right> + <button id="dc-add" v-has="'dc_toAdd'" :title="$t('overall.createDatacenter')" class="top-tool-btn margin-l-20" + type="button" @click="add"> + <i class="nz-icon-create-square nz-icon"></i> + </button> + <delete-button id="account-list-batch-delete" v-has="'dc_delete'" :delete-objs="batchDeleteObjs" api="dc" @after="getTableData" @before="delFlag=true"></delete-button> + </template> + <template v-slot:default="slotProps"> <el-table - v-show="bottomBox.mainResizeShow" id="dc-list-table" - ref="dcTable" + ref="dataTable" v-loading="tools.loading" - :cell-class-name="assetStatClassName" :data="tableData" :height="mainTableHeight" + :cell-class-name="assetStatClassName" border - tooltip-effect="light" + @header-dragend="dragend" @sort-change="tableDataSort" - @selection-change="(selection)=>{this.batchDeleteObjs=selection}" + @selection-change="(selection)=>{batchDeleteObjs=selection}" > <el-table-column :resizable="false" @@ -61,14 +38,23 @@ v-for="(item, index) in tools.customTableTitle" v-if="item.show" :key="`col-${index}`" + :fixed="item.fixed" :label="item.label" - :prop="$tableSet.propTitle(item.prop,'dc')" + :prop="item.prop" :resizable="true" - :sortable="sortableShow(item.prop,'dc')" - show-overflow-tooltip + :sort-orders="['ascending', 'descending']" + :sortable="sortableShow(item.prop, fromRoute.dc)" + :width="`${item.width}`" + class="data-column" > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> <template slot-scope="scope" :column="item"> - <template v-if="item.prop == 'principal'"> + <template v-if="item.prop === 'principal'"> <template v-if="scope.row.principal"> <template v-for="item in userData"> <template v-if="scope.row.principal == item.userId">{{item.username}}</template> @@ -76,7 +62,7 @@ </template> <template v-else>-</template> </template> - <template v-else-if="item.prop == 'state'"> + <template v-else-if="item.prop === 'state'"> <el-switch v-model="scope.row.state" :disabled="!hasButton('dc_toEdit') || !hasButton('dc_toEdit')" @@ -86,15 +72,15 @@ @change="(val)=>{statusChange(scope.row)}" /> </template> - <template v-else-if="item.prop == 'longitude'"> + <template v-else-if="item.prop === 'longitude'"> <template v-if="regNumTest(scope.row.longitude)">{{scope.row.longitude}}</template> <template v-else>-</template> </template> - <template v-else-if="item.prop == 'latitude'"> + <template v-else-if="item.prop === 'latitude'"> <template v-if="regNumTest(scope.row.latitude)">{{scope.row.latitude}}</template> <template v-else>-</template> </template> - <template v-else-if="item.prop == 'assetStat' && scope.row.assetStat"> + <template v-else-if="item.prop === 'assetStat' && scope.row.assetStat"> <el-popover :content="$t('overall.result.total') + ':' + scope.row.assetStat.total + ',' + $t('asset.inStock') + ':' + scope.row.assetStat.inStock + ',' + $t('asset.notInStock') + ':' + scope.row.assetStat.outStock + ',' + $t('asset.suspended') + ':' + scope.row.assetStat.suspended" placement="top" @@ -108,30 +94,45 @@ </el-popover> </template > - <template v-else-if="item.prop == 'cabinetNum'"> - <span class="link" @click="showCabinet(scope.row)">{{scope.row[item.prop]}}</span> + <template v-else-if="item.prop === 'cabinetNum'"> + <span class="link" @click="$refs.dataList.showBottomBox('cabinet', scope.row)">{{scope.row[item.prop]}}</span> </template> <template v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</template> <template v-else>-</template> </template> </el-table-column> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['edit', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `dc?ids=${scope.row.id}`]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + </div> + </el-table-column> </el-table> - </div> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" @click="toTop(scrollbarWrap)" class="to-top" v-show="tools.showTopBtn && bottomBox.mainResizeShow" id="dc-list-totop"><i class="nz-icon nz-icon-top"></i></button> - <div class="pagination-bottom" v-show="!bottomBox.showSubList"> - <Pagination :tableId="tableId" :pageObj="pageObj" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"></Pagination> - </div> - </div> - <transition name="el-zoom-in-bottom"> - <bottom-box :detail="bottomBox.dcDetail" :from="$CONSTANTS.fromRoute.dc" :is-full-screen="bottomBox.isFullScreen" :obj="bottomBox.dc" :sub-resize-show="bottomBox.subResizeShow" :target-tab.sync="bottomBox.targetTab" v-if="bottomBox.showSubList" - @closeSubList="bottomBox.showSubList = false" @fullScreen="fullScreen" @exitFullScreen="exitFullScreen" @listResize="listResize" ></bottom-box> - </transition> - <!--dc table end--> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="dc-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> <transition name="right-box"> - <dc-box @close="closeDcBox" :dc="dc" :user-data="userData" @reload="getTableData" v-if="rightBox.dc.show"></dc-box> + <dc-box v-if="rightBox.dc.show" :dc="object" :user-data="userData" @close="closeDcBox" @reload="getTableData"></dc-box> </transition> <transition name="right-box"> - <traffic-setting-box @close="closeTrafficBox" :dc="dc" ref="trafficBox" v-if="rightBox.trafficSetting.show"></traffic-setting-box> + <traffic-setting-box v-if="rightBox.trafficSetting.show" ref="trafficBox" :dc="object" @close="closeTrafficBox"></traffic-setting-box> </transition> <span v-if="dcDataRefresh" style="display: none"></span> <el-dialog :visible.sync="showAgentDownload" width="620px" append-to-body class="nz-dialog agent-dialog" @close="closeDialog" :title="$t('config.dc.agent.title')"> @@ -181,54 +182,32 @@ </div> </template> <script> -import bus from '../../../libs/bus' -import dcBox from '../../common/rightBox/dcBox' // dc弹框 -import trafficSettingBox from '../../common/rightBox/trafficSetting/trafficSettingBox' -import deleteButton from '../../common/deleteButton' +import bus from '@/libs/bus' +import dcBox from '@/components/common/rightBox/dcBox' // dc弹框 +import trafficSettingBox from '@/components/common/rightBox/trafficSetting/trafficSettingBox' +import deleteButton from '@/components/common/deleteButton' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' const regNum = /^[0-9]+.?[0-9]*/ export default { name: 'dc', components: { - 'traffic-setting-box': trafficSettingBox, - 'dc-box': dcBox, - 'delete-button': deleteButton + trafficSettingBox, + dcBox, + deleteButton, + nzDataList }, + mixins: [tableMixin], data () { return { - /* 二级页面相关 */ - bottomBox: { - dcDetail: {}, - dc: {}, - mainResizeShow: true, // dom高度改变时是否展示|隐藏 - subResizeShow: true, - isFullScreen: false, // 全屏状态 - showSubList: false, // 是否显示二级列表 - targetTab: '', // 显示二级列表中的哪个页签 - inTransform: false // 搜索框相关,搜索条件下拉框是否在transform里 - }, - mainTableHeight: this.$tableHeight.normal, // 主列表table高度 - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - batchDeleteObjs: [], tableId: 'dcTable', // 需要分页的table的id,用于记录每页数量 - dc: {}, - blankDc: { + object: {}, + blankObject: { id: '', name: '', location: '', tel: '', principal: '', - // area: { - // id: 0, - // name: '' - // } state: 'ON', longitude: undefined, latitude: undefined @@ -237,11 +216,6 @@ export default { dc: { show: false }, trafficSetting: { show: false } }, - pageObj: { - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, tableTitle: [ { label: 'ID', @@ -286,8 +260,6 @@ export default { show: true } ], - tableData: [], - userData: [], searchMsg: { // 给搜索框子组件传递的信息 zheze_none: true, searchLabelList: [{ @@ -298,9 +270,7 @@ export default { disabled: false }] }, - searchLabel: {}, // 搜索参数 tabShow: 1, // 控制显示一级页面和二级页面 1 dc 2cabinet - scrollbarWrap: null, delFlag: false, showAgentDownload:false, token:'', @@ -319,7 +289,8 @@ export default { osType:"Centos", dc:"", type:1, - } + }, + userData: [] } }, computed: { @@ -369,15 +340,6 @@ export default { } return '' }, - jumpTo (data, id) { - bus.$emit('menu-change', data) - this.$router.push({ - path: '/' + data, - query: { - t: +new Date() - } - }) - }, edit (u) { this.dc = JSON.parse(JSON.stringify(u)) if (!regNum.test(this.dc.longitude)) { @@ -391,67 +353,23 @@ export default { } this.rightBox.dc.show = true }, - configTraffic (u) { - this.dc = JSON.parse(JSON.stringify(u)) - this.rightBox.trafficSetting.show = true - }, detail (u) { - this.bottomBox.dc = JSON.parse(JSON.stringify(u)) - if (!this.bottomBox.dc.area) { - this.$set(this.bottomBox.dc, 'area', { id: '', name: '' }) + this.bottomBox.object = JSON.parse(JSON.stringify(u)) + if (!this.bottomBox.object.area) { + this.$set(this.bottomBox.object, 'area', { id: '', name: '' }) } this.bottomBox.targetTab = 'detail' this.bottomBox.showSubList = true }, - // 全屏 - fullScreen () { - const vm = this - this.$bottomBoxWindow.fullScreen(vm) - }, - // 退出全屏 - exitFullScreen () { - const vm = this - this.$bottomBoxWindow.exitFullScreen(vm) - }, - // 鼠标拖动二级列表 - listResize (e) { - const vm = this - this.$bottomBoxWindow.listResize(vm, e) - }, - convertToDetail (obj) { - const detail = JSON.parse(JSON.stringify(obj)) - return detail - /* let detail = []; - detail.push({label: this.$t("overall.name"), value: obj.name}); - detail.push({label: this.$t("config.dc.area"), value: obj.area.name}); - detail.push({label: this.$t("asset.location"), value: obj.location}); - detail.push({label: this.$t("config.dc.cabinetNum"), value: obj.cabinetNum}); - let assets = this.$t('overall.result.total') + ' ' + obj.assetStat.total + ',' + this.$t('asset.inStock') + ' ' + obj.assetStat.inStock + ',' + this.$t('asset.notInStock') + ' ' + obj.assetStat.outStock; - detail.push({label: this.$t("config.dc.assets"), value: assets}); - detail.push({label: this.$t("asset.tel"), value: obj.tel}); - let principal = ''; - for (let i = 0; i < this.userData.length; i++) { - if (this.userData[i].userId == obj.principal) { - principal = this.userData[i].username; - break; - } - } - detail.push({label: this.$t("asset.principal"), value: principal}); - return detail; */ - }, add () { - this.dc = this.newDc() + this.object = this.newObject() this.rightBox.dc.show = true }, - newDc () { - return JSON.parse(JSON.stringify(this.blankDc)) - }, closeDcBox (refresh) { this.rightBox.dc.show = false if (refresh) { this.delFlag = true this.getTableData() - bus.$emit('dc-list-change') } }, closeTrafficBox (refresh) { @@ -461,24 +379,6 @@ export default { this.getTableData() } }, - del (u) { - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('dc?ids=' + u.id).then(response => { - if (response.code === 200) { - this.delFlag = true - this.$message({ duration: 1000, type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getTableData() - bus.$emit('dc-list-change') - } else { - this.$message.error(response.msg) - } - }) - }) - }, statusChange (idc) { this.$put('dc', idc).then(response => { if (response.code === 200) { @@ -498,14 +398,14 @@ export default { this.$set(this.searchLabel, 'pageNo', this.pageObj.pageNo) this.$set(this.searchLabel, 'pageSize', this.pageObj.pageSize) this.tools.loading = true - this.$get('idc', this.searchLabel).then(response => { + this.$get('dc', this.searchLabel).then(response => { this.tools.loading = false if (response.code === 200) { this.tableData = response.data.list this.pageObj.total = response.data.total if (!this.scrollbarWrap) { this.$nextTick(() => { - this.scrollbarWrap = this.$refs.dcTable.bodyWrapper + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper this.toTopBtnHandler(this.scrollbarWrap) }) } @@ -522,58 +422,6 @@ export default { }) }) }, - pageNo (val) { - this.pageObj.pageNo = val - this.getTableData() - }, - pageSize (val) { - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.pageObj.pageSize = val - this.getTableData() - }, - search (searchObj) { - let orderBy = '' - if (this.searchLabel.orderBy) { - orderBy = this.searchLabel.orderBy - } - this.searchLabel = {} - this.pageObj.pageNo = 1 - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (orderBy) { - this.$set(this.searchLabel, 'orderBy', orderBy) - } - if (this.$refs.dcTable && this.$refs.dcTable.bodyWrapper) { - this.$refs.dcTable.bodyWrapper.scrollTop = 0 - } - this.getTableData() - }, - showCabinet (dc) { - this.bottomBox.targetTab = 'cabinet' - this.bottomBox.dc = JSON.parse(JSON.stringify(dc)) - this.bottomBox.showSubList = true - }, - sortableShow (label, form) { - if (label === 'state') { - return false - } - return this.$tableSet.sortableShow(label, form) - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getTableData() - }, regNumTest (val) { // 校验是否是数字 return regNum.test(val) }, @@ -583,59 +431,11 @@ export default { }) } }, - watch: { - 'bottomBox.dc': { - deep: true, - handler (n) { - if (n.id) { - this.bottomBox.dcDetail = this.convertToDetail(n) - } - } - }, - 'bottomBox.showSubList': function (n) { - const vm = this - this.$bottomBoxWindow.showSubListWatch(vm, n) - }, - tableData: { - deep: true, - handler (n) { - if (n.length === 0 && this.pageObj.pageNo > 1) { - this.pageNo(this.pageObj.pageNo - 1) - } - - if (!this.delFlag) { // 不是删除时回到顶部 - this.$refs.dcTable.bodyWrapper.scrollTop = 0 - } else { - this.delFlag = false - } - } - } - }, beforeDestroy () { bus.$off('dc-list-change') - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) - }; - }, - created () { - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize - } - }, - destroyed () { - }, mounted () { this.getUserData() - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - // this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - this.getTableData() - this.getAllDc(); } } </script> diff --git a/nezha-fronted/src/components/page/config/exprTemp.vue b/nezha-fronted/src/components/page/config/exprTemp.vue index 1e9607bc9..986a133ae 100644 --- a/nezha-fronted/src/components/page/config/exprTemp.vue +++ b/nezha-fronted/src/components/page/config/exprTemp.vue @@ -1,126 +1,103 @@ <template> - <div class="main-list main-and-sub-transition" :class="{'main-list-with-sub': bottomBox.showSubList}"> - <!--工具组--> - <div class="top-tools" v-show="bottomBox.mainResizeShow"> - <div class="top-tool-main-right" :class="{'top-tool-main-right-to-left': bottomBox.showSubList}"> - <div class="top-tool-search margin-r-20"> - <search-input :searchMsg="searchMsg" @search="search" - :inTransform="bottomBox.inTransform" :single="true"></search-input> - </div> + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.expressionTemplate" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:top-tool-right> <export-excel - id="asset-list" - export-file-name="asset" + id="expression-template-list" + class="top-tool-export margin-l-20" export-url="expression/tmpl/export" import-url="expression/tmpl/import" + export-file-name="expression-template" :params="searchLabel" :permissions="{import: 'asset_import', export: 'asset_export'}" - @afterImport="afterTableListChange" + @afterImport="getTableData" v-has="'expr_temp_save'" > <template slot="optionZone"> - <button :title="$t('overall.exportExcelLower')" @click="addTemp" type="button" v-has="'expr_temp_save'" - class="nz-btn nz-btn-size-normal nz-btn-style-light" id="alert-list-export"> + <button id="expr-tmpl-list-export" v-has="'expr_temp_save'" :title="$t('overall.createTemplate')" class="top-tool-btn" + type="button" @click="add"> <i class="nz-icon nz-icon-create-square"></i> </button> </template> </export-excel> - <delete-button :delete-objs="batchDeleteObjs" @after="getexprTemp" + <delete-button :delete-objs="batchDeleteObjs" @after="getTableData" :api="'expression/tmpl'" v-has="'expr_temp_delete'" id="alert-msg-batch-delete"></delete-button> - </div> - <div class="pagination-top pagination-top-hide display-none"></div> - </div> - <!--表格开始--> - <transition name="el-zoom-in-top"> - <element-set - id="alert-rule-element-set" - v-if="tools.showCustomTableTitle" - @close="tools.showCustomTableTitle = false" - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - ref="customTableTitle" - ></element-set> - </transition> - <el-table - id="alert-rule-table" - class="nz-table" - :data="tableData" - border - v-show="bottomBox.mainResizeShow" - ref="exprTempTable" - tooltip-effect="light" - :height="mainTableHeight" - v-loading="tools.loading" - style="width: 100%;" - @sort-change="tableDataSort" - @selection-change="(selection)=>{this.batchDeleteObjs=selection}" - > - <el-table-column - :resizable="false" - type="selection" - width="40" - align="center"> - </el-table-column> - - <el-table-column - :resizable="true" - v-for="(item, index) in tools.customTableTitle" - v-if="item.show" - :key="`col-${index}`" - :label="item.label" - :show-overflow-tooltip="item.prop!=='matchers'" - :sort-orders="['ascending', 'descending']" - :sortable="$tableSet.sortableShow(item.prop,'exprTemp')" - :prop="$tableSet.propTitle(item.prop,'exprTemp')" - :width="item.width" - > - <template slot-scope="scope" :column="item"> - <div v-if="item.prop == 'option'" class="content-right-options"> - <span :id="'alert-edit-'+scope.row.id" :title="$t('overall.edit')" @click.stop="edit(scope.row)" - class="content-right-option" v-has="'expr_temp_update'" v-if="scope.row.buildIn !== 1"> - <i class="nz-icon nz-icon-edit"></i> - </span> - <span - :id="'alert-del-'+scope.row.id" - :title="$t('overall.delete')" - @click="del(scope.row)" - class="content-right-option" - v-has="'expr_temp_delete'" - v-if="scope.row.buildIn !== 1"> - <i class="nz-icon nz-icon-delete"></i> - </span> - <span - :id="'alert-copy-'+scope.row.id" - :title="$t('overall.copy')" - @click="copyRow(scope.row,'exprTemp')" - class="content-right-option" - v-has="'expr_temp_save'"> - <i class="nz-icon nz-icon-override"></i> - </span> - </div> - <span v-else-if="scope.row[item.prop]">{{scope.row[item.prop] || '-'}}</span> - <template v-else>-</template> - </template> - </el-table-column> - - <el-table-column width="28" :resizable="false"> - <template slot="header"> - <span @mousedown.stop="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)" - class="nz-table-gear"> - <i class="nz-icon nz-icon-gear"></i> - </span> - </template> - </el-table-column> - </el-table> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" - @click="toTop(scrollbarWrap)" class="to-top" v-show="tools.showTopBtn && bottomBox.mainResizeShow" - id="alert-rule-toTop"><i class="nz-icon nz-icon-top"></i></button> - <!--表格结束--> - <!--分页部分--> - <div class="pagination-bottom" v-show="!bottomBox.showSubList"> - <Pagination :tableId="tableId" :pageObj="pageObj" @pageNo='pageNo' @pageSize='pageSize' - ref="Pagination"></Pagination> - </div> + </template> + <template v-slot:default="slotProps"> + <el-table + id="role-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" + > + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </template> + <template slot-scope="scope" :column="item"> + <span v-if="scope.row[item.prop]">{{scope.row[item.prop] || '-'}}</span> + <template v-else>-</template> + </template> + </el-table-column> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['edit', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['copy', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-override"></i><span class="operation-dropdown-text">{{$t('config.exprTemp.copy')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `sys/role?ids=${scope.row.id}`]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + </div> + </el-table-column> + </el-table> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> <!--导出--> <div class="export-xlsx"> <el-dialog :visible.sync="importBox.show" :title="importBox.title" :modal-append-to-body='false' @@ -137,56 +114,33 @@ </div> <!--侧滑--> <transition name="right-box"> - <exprTempBox v-if="rightBox.show" :exprTemp="exprTemp" @close="closeRightBox" - ref="exprTempBox"></exprTempBox> + <exprTempBox v-if="rightBox.show" ref="exprTempBox" :exprTemp="object" + @close="closeRightBox"></exprTempBox> </transition> </div> </template> <script> -import bus from '../../../libs/bus' -import exportXLSX from '../../common/exportXLSX' -import deleteButton from '../../common/deleteButton' -import exprTempBox from '../../common/rightBox/exprTempBox' -import { calcDurationByStringTimeB } from '../../common/js/tools' +import bus from '@/libs/bus' +import exportXLSX from '@/components/common/exportXLSX' +import exprTempBox from '@/components/common/rightBox/exprTempBox' +import { calcDurationByStringTimeB } from '@/components/common/js/tools' +import deleteButton from '@/components/common/deleteButton' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' + export default { name: 'exprTemp', components: { deleteButton, exprTempBox, + nzDataList, 'export-excel': exportXLSX }, + mixins: [tableMixin], data () { return { tableId: 'exprTemp', - // 侧滑 - rightBox: { - show: false - }, - /* 二级列表相关 */ - mainTableHeight: this.$tableHeight.normal, // 主列表table高度 - /* 二级页面相关 */ - bottomBox: { - tabList: [], // 二级列表的标签 - tabDetailList: [], // 多个详情 - mainResizeShow: true, // dom高度改变时是否展示|隐藏 - subResizeShow: true, - isFullScreen: false, // 全屏状态 - showSubList: false, // 是否显示二级列表 - targetTab: '', // 显示二级列表中的哪个页签 - inTransform: false // 搜索框相关,搜索条件下拉框是否在transform里 - }, - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - /* 批量删除相关 */ - batchDeleteObjs: [], /* 搜素相关 */ searchMsg: { // 给搜索框子组件传递的信息 zheze_none: true, @@ -212,12 +166,6 @@ export default { } ] }, - searchLabel: {}, // 搜索参数 - pageObj: { - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, /* 表格相关 */ tableTitle: [ { @@ -241,26 +189,19 @@ export default { label: this.$t('config.exprTemp.remark'), prop: 'remark', show: true - }, { - label: this.$t('alert.config.option'), - prop: 'option', - show: true, - width: 120 } ], - tableData: [], // 导出相关 importBox: { show: false, title: this.$t('overall.exportExcel') }, deleteBox: { show: false, ids: '', remark: '', state: 2 }, // 创建修改相关 - blackExprTemp: { + blankObject: { id: '', name: '', gname: '', expression: '', remark: '' }, - exprTemp: {}, nowTime: '' } }, @@ -274,31 +215,22 @@ export default { } } }, - created () { - - }, mounted () { - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) this.initEvent() - this.getexprTemp() }, methods: { initEvent () { bus.$on('alert-rule-list-change', () => { - this.getexprTemp() + this.getTableData() }) bus.$on('dc-list-change', () => { - this.getexprTemp() + this.getTableData() }) bus.$on('alert-message-change', () => { - this.getexprTemp() + this.getTableData() }) }, - getexprTemp () { + getTableData () { if (!this.hasButton('rule_view')) { this.$message.error(this.$t('tip.noAccess')) return @@ -314,55 +246,13 @@ export default { this.nowTime = this.utcTimeToTimezoneStr(response.time) if (!this.scrollbarWrap) { this.$nextTick(() => { - this.scrollbarWrap = this.$refs.exprTempTable.bodyWrapper + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper this.toTopBtnHandler(this.scrollbarWrap) }) } } }) }, - pageNo (val) { - this.pageObj.pageNo = val - this.getexprTemp() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getexprTemp() - }, - search (searchObj) { - let orderBy = '' - if (this.searchLabel.orderBy) { - orderBy = this.searchLabel.orderBy - } - this.searchLabel = {} - this.pageObj.pageNo = 1 - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (orderBy) { - this.$set(this.searchLabel, 'orderBy', orderBy) - } - this.$refs.exprTempTable.bodyWrapper.scrollTop = 0 - this.getexprTemp() - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getexprTemp() - }, - openDelMessageBox () { - // if (this.batchDeleteObjs.length < 1) return - }, showExportDialog () { this.importBox.show = true }, @@ -383,48 +273,10 @@ export default { this.exportExcel(temp) this.closeDialog() }, - afterTableListChange () { - this.getexprTemp() - }, - addTemp () { - this.exprTemp = JSON.parse(JSON.stringify(this.blackExprTemp)) - this.rightBox.show = true - }, - edit (row) { - this.$get('expression/tmpl/' + row.id).then(res => { - this.exprTemp = { ...res.data } - this.rightBox.show = true - }) - }, - del (row) { - if (this.prevent_opt.save) { - return - } - ; - this.prevent_opt.save = true - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('expression/tmpl?ids=' + row.id).then(response => { - this.prevent_opt.save = false - if (response.code === 200) { - this.$message({ type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getexprTemp() - } else { - this.$message.error(response.msg) - } - }) - }).catch(() => { - this.prevent_opt.save = false - }) - }, overtime (row) { if (this.prevent_opt.save) { return } - ; this.prevent_opt.save = true this.$confirm(this.$t('tip.confirmOvertime'), { confirmButtonText: this.$t('tip.yes'), @@ -435,7 +287,7 @@ export default { this.prevent_opt.save = false if (response.code === 200) { this.$message({ type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getexprTemp() + this.getTableData() } else { this.$message.error(response.msg) } @@ -443,18 +295,7 @@ export default { }).catch(() => { this.prevent_opt.save = false }) - }, - closeRightBox (refresh) { - this.rightBox.show = false - if (refresh) { - this.delFlag = true - this.getexprTemp() - } } } } </script> - -<style scoped lang="scss"> - -</style> diff --git a/nezha-fronted/src/components/page/config/mib.vue b/nezha-fronted/src/components/page/config/mib.vue index 77b795773..8cadc9c9c 100644 --- a/nezha-fronted/src/components/page/config/mib.vue +++ b/nezha-fronted/src/components/page/config/mib.vue @@ -1,155 +1,165 @@ -<style scoped> - .mib { - height: 100%; - } -</style> <template> - <div class="mib"> - <template v-if="showTab == 'file'"> - <div class="top-tools"> - <div class="nz-tab top-tool-main-right top-tool-main-right-to-left-little" style="width: 300px"> - <div class="nz-tab-item-box" id="module-type-1"> - <div class="nz-tab-item nz-tab-item-active">{{$t("config.mib.mibFiles")}}</div> - </div> - <div @click="showTab = 'browser'" class="nz-tab-item-box" id="module-type-2" v-has="'snmp_browser_view'"> - <div class="nz-tab-item">{{$t("config.mib.mibBrowser")}}</div> - </div> + <div style="height: 100%"> + <nz-data-list + v-if="showTab === 'file'" + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.mib" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:top-tool-left> + <div id="module-type-1" class="nz-tab-item-box"> + <div class="nz-tab-item nz-tab-item-active">{{$t("config.mib.mibFiles")}}</div> </div> - <div class="top-tool-main-right"> - <div class="top-tool-search"> - <search-input :searchMsg="searchMsg" @search="search"></search-input> - </div> - <button :title="$t('overall.createMib')" @click="add" class="nz-btn nz-btn-size-normal nz-btn-style-light margin-l-20" id="mib-add" type="button" v-has="'snmp_file_toAdd'"> - <i class="nz-icon-create-square nz-icon"></i> - </button> - <delete-button :delete-objs="batchDeleteObjs" @after="getTableData" @before="delFlag=true" api="mib" v-has="'snmp_file_delete'" id="mib-list-batch-delete"></delete-button> + <div id="module-type-2" v-has="'snmp_browser_view'" class="nz-tab-item-box" @click="showTab = 'browser'"> + <div class="nz-tab-item">{{$t("config.mib.mibBrowser")}}</div> </div> - </div> - <!-- 自定义table列 --> - <transition name="el-zoom-in-top"> - <element-set - id="mib-list" - v-if="tools.showCustomTableTitle" - @close="tools.showCustomTableTitle = false" - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - ref="customTableTitle" - ></element-set> - </transition> - <el-table :data="tableData" :height="$tableHeight.normal" @sort-change="tableDataSort" border class="nz-table mib-table" ref="mibTable" style="width: 100%;" v-loading="tools.loading" id="mib-list-table" - @selection-change="(selection)=>{this.batchDeleteObjs=selection}" - > - <el-table-column - :resizable="false" - type="selection" - width="40" - align="center"> - </el-table-column> - <el-table-column :resizable="true" v-for="(item, index) in tools.customTableTitle" v-if="item.show" :class-name="item.prop == 'modelsDetail'?'detail-column':''" - :key="`col-${index}`" :label="item.label" :sortable="$tableSet.sortableShow(item.prop,'mib')" - :prop="$tableSet.propTitle(item.prop,'mib')" - :sort-orders="['ascending', 'descending']"> - <template slot-scope="scope" :column="item"> - <template v-if="item.prop == 'updateUser'" >{{scope.row[item.prop].name}}</template> - <template v-else-if="item.prop == 'fileName' && scope.row[item.prop]" > - <span @click="downloadMib(scope.row)" class="link">{{scope.row[item.prop]}}</span> + </template> + <template v-slot:top-tool-right> + <button id="mib-add" v-has="'snmp_file_toAdd'" :title="$t('overall.createMib')" class="top-tool-btn margin-l-20" type="button" @click="add"> + <i class="nz-icon-create-square nz-icon"></i> + </button> + <delete-button id="mib-list-batch-delete" v-has="'snmp_file_delete'" :delete-objs="batchDeleteObjs" api="mib" @after="getTableData" @before="delFlag=true"></delete-button> + </template> + <template v-slot:default="slotProps"> + <el-table + id="role-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" + > + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> </template> - <template v-else-if="item.prop == 'modelsDetail' && scope.row['modelsDetail'] && scope.row['modelsDetail'].length >0" > - <div style="height: 100%"> - <div style="height: 100%; overflow: auto;"> - <div v-for="(n,i) in scope.row['modelsDetail']" :key="n.name+'-'+n.id+'-'+i" class="detail-item-content"> - <el-popover trigger="hover" placement="top" > - <div> - <div> - <span>{{$t('overall.name')}}:</span> - <span>{{n.name}}</span> - </div> + <template slot-scope="scope" :column="item"> + <template v-if="item.prop == 'updateUser'" >{{scope.row[item.prop].name}}</template> + <template v-else-if="item.prop == 'fileName' && scope.row[item.prop]" > + <span class="link" @click="downloadMib(scope.row)">{{scope.row[item.prop]}}</span> + </template> + <template v-else-if="item.prop === 'modelsDetail' && scope.row['modelsDetail'] && scope.row['modelsDetail'].length >0" > + <div style="height: 100%"> + <div style="height: 100%; overflow: auto;"> + <div v-for="(n,i) in scope.row['modelsDetail']" :key="n.name+'-'+n.id+'-'+i" class="detail-item-content"> + <el-popover placement="top" trigger="hover" > <div> - <span>{{$t('config.mib.vendor')}}:</span> - <span>{{n.vendor}}</span> + <div> + <span>{{$t('overall.name')}}:</span> + <span>{{n.name}}</span> + </div> + <div> + <span>{{$t('config.mib.vendor')}}:</span> + <span>{{n.vendor}}</span> + </div> + <div> + <span>{{$t('config.mib.type')}}:</span> + <span>{{n.type}}</span> + </div> </div> - <div> - <span>{{$t('config.mib.type')}}:</span> - <span>{{n.type}}</span> - </div> - </div> - <template slot="reference"> - <div class="detail-item-content" v-if="i < scope.row['modelsDetail'].length-1">{{n.name}},</div> - <div class="detail-item-content" v-else>{{n.name}}</div> - </template> - </el-popover> + <template slot="reference"> + <div v-if="i < scope.row['modelsDetail'].length-1" class="detail-item-content">{{n.name}},</div> + <div v-else class="detail-item-content">{{n.name}}</div> + </template> + </el-popover> + </div> </div> </div> - </div> + </template> + <span v-else-if="item.prop === 'updateAt'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> + <template v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</template> + <template v-else>-</template> </template> - <span v-else-if="item.prop == 'updateAt'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> - <div v-else-if="item.prop == 'option'" class="content-right-options"> - <span :id="'mib-download-'+scope.row.id" :title="$t('overall.download')" @click="downloadMib(scope.row)" class="content-right-option" v-has="'snmp_file_download'"><i class="nz-icon nz-icon-download1"></i></span> - - <span :id="'mib-edit-'+scope.row.id" :title="$t('overall.edit')" @click="edit(scope.row)" class="content-right-option" v-has="'snmp_file_toEdit'"><i class="nz-icon nz-icon-edit"></i></span> - - <span :id="'mib-del-'+scope.row.id" :title="$t('overall.delete')" @click="del(scope.row)" class="content-right-option" v-has="'snmp_file_delete'"><i class="nz-icon nz-icon-delete"></i></span> + </el-table-column> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item v-has="'snmp_file_download'" :command="['edit', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['download', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-download1"></i><span class="operation-dropdown-text">{{$t('overall.download')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `mib?ids=${scope.row.id}`]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> </div> - <template v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</template> - <template v-else>-</template> - </template> - </el-table-column> - <el-table-column :resizable="false" width="28"> - <template slot="header"> - <span @mousedown.stop="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)" class="nz-table-gear"> - <i class="nz-icon nz-icon-gear"></i> - </span> - </template> - </el-table-column> - </el-table> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" @click="toTop(scrollbarWrap)" class="to-top" v-show="tools.showTopBtn" id="mib-list-totop"><i class="nz-icon nz-icon-top"></i></button> - <Pagination :tableId="tableId" :pageObj="pageObj" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"></Pagination> - </template> + </el-table-column> + </el-table> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> <mib-browser :show-tab="showTab" v-if="showTab == 'browser'" @toFileTab="showTab = 'file'"></mib-browser> <transition name="right-box"> - <mib-box v-if="rightBox.show" ref="mibBox" :mib="mib" @reload="getTableData" @close="closeRightBox"></mib-box> + <mib-box v-if="rightBox.show" ref="mibBox" :mib="object" @close="closeRightBox" @reload="getTableData"></mib-box> </transition> </div> - </template> <script> import axios from 'axios' -import bus from '../../../libs/bus' import mibBrowser from './mibBrowser' -import deleteButton from '../../common/deleteButton' +import mibBox from '@/components/common/rightBox/mibBox' +import deleteButton from '@/components/common/deleteButton' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' + export default { name: 'mib', components: { - 'mib-browser': mibBrowser, - 'delete-button': deleteButton + mibBox, + mibBrowser, + deleteButton, + nzDataList }, + mixins: [tableMixin], data () { return { showTab: 'file', // file/browser - rightBox: { show: false }, - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - batchDeleteObjs: [], tableId: 'mibTable', // 需要分页的table的id,用于记录每页数量 - mib: {}, - blankMib: { + object: {}, + blankObject: { id: null, name: '', remark: '', models: '', file: null }, - pageObj: { - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, tableTitle: [ { label: 'ID', @@ -180,14 +190,8 @@ export default { label: this.$t('config.mib.updateAt'), prop: 'updateAt', show: true - }, { - label: this.$t('config.account.option'), - prop: 'option', - show: true, - width: 120 } ], - tableData: [], searchMsg: { // 给搜索框子组件传递的信息 zheze_none: true, searchLabelList: [{ @@ -203,60 +207,10 @@ export default { label: 'name', disabled: false }] - }, - searchLabel: {}, // 搜索参数 - scrollbarWrap: null, - delFlag: false + } } }, methods: { - clickOutside () { - this.rightBox.show = false - }, - edit (u) { - this.mib = JSON.parse(JSON.stringify(u)) - this.rightBox.show = true - }, - closeRightBox (refresh) { - this.rightBox.show = false - if (refresh) { - this.delFlag = true - this.getTableData() - } - }, - del (u) { - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('mib?ids=' + u.id).then(response => { - if (response.code === 200) { - this.delFlag = true - this.$message({ duration: 1000, type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getTableData() - } else { - this.$message.error(response.msg) - } - }) - }) - }, - add () { - this.mib = this.newMib() - this.rightBox.show = true - }, - newMib () { - return JSON.parse(JSON.stringify(this.blankMib)) - }, - jumpTo (data, id) { - bus.$emit('menu-change', data) - this.$router.push({ - path: '/' + data, - query: { - t: +new Date() - } - }) - }, getTableData () { if (!this.hasButton('snmp_file_view')) { this.$message.error(this.$t('tip.noAccess')) @@ -273,42 +227,13 @@ export default { this.pageObj.total = response.data.total if (!this.scrollbarWrap) { this.$nextTick(() => { - this.scrollbarWrap = this.$refs.mibTable.bodyWrapper + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper this.toTopBtnHandler(this.scrollbarWrap) }) } } }) }, - pageNo (val) { - this.pageObj.pageNo = val - this.getTableData() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getTableData() - }, - search (searchObj) { - let orderBy = '' - if (this.searchLabel.orderBy) { - orderBy = this.searchLabel.orderBy - } - this.pageObj.pageNo = 1 - this.searchLabel = {} - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (orderBy) { - this.$set(this.searchLabel, 'orderBy', orderBy) - } - if (this.$refs.mibTable && this.$refs.mibTable.bodyWrapper) { - this.$refs.mibTable.bodyWrapper.scrollTop = 0 - } - this.getTableData() - }, downloadMib (mib) { if (!this.hasButton('snmp_file_download')) { return @@ -335,55 +260,7 @@ export default { window.URL.revokeObjectURL(link.href) } }) - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getTableData() - } - }, - watch: { - tableData: { - deep: true, - handler (n) { - if (n.length === 0 && this.pageObj.pageNo > 1) { - this.pageNo(this.pageObj.pageNo - 1) - } - if (!this.delFlag) { // 不是删除时回到顶部 - this.$refs.mibTable.bodyWrapper.scrollTop = 0 - } else { - this.delFlag = false - } - } - } - }, - created () { - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize } - }, - mounted () { - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - - this.getTableData() - }, - beforeDestroy () { - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) - }; } } </script> diff --git a/nezha-fronted/src/components/page/config/model.vue b/nezha-fronted/src/components/page/config/model.vue index 1fccaac01..4f2959bd3 100644 --- a/nezha-fronted/src/components/page/config/model.vue +++ b/nezha-fronted/src/components/page/config/model.vue @@ -1,49 +1,30 @@ -<style lang="scss"> -@import '@/assets/css/common/tableCommon.scss'; -</style> <template> - <div class="model list-page"> - <div class="main-list" :class="{'main-list-with-sub': bottomBox.showSubList}"> - <div class="main-modal"></div> - <div class="top-tools" v-show="bottomBox.mainResizeShow"> - <div class="top-tool-main-right" :class="{'top-tool-main-right-to-left-small': bottomBox.showSubList}"> - <div class="top-tool-search"> - <search-input :inTransform="bottomBox.inTransform" :searchMsg="searchMsg" @search="search"></search-input> - </div> - <button id="model-add" v-has="'model_toAdd'" :title="$t('overall.createModel')" class="top-tool-btn margin-l-20" @click="add"> - <i class="nz-icon-create-square nz-icon"></i> - </button> - <delete-button :delete-objs="batchDeleteObjs" @after="getTableData" @before="delFlag=true" api="model" v-has="'model_delete'" id="model-list-batch-delete"></delete-button> - <button id="account-column-setting" class="top-tool-btn margin-l-10" - type="button" @click="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)"> - <i class="nz-icon-gear nz-icon"></i> - </button> - </div> - <div class="pagination-top pagination-top-hide display-none"></div> - </div> - <!-- 自定义table列 --> - <transition name="el-zoom-in-top"> - <element-set - id="model-list" - v-if="tools.showCustomTableTitle" - @close="tools.showCustomTableTitle = false" - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - ref="customTableTitle" - ></element-set> - </transition> - <div class="nz-table2"> - <el-table v-show="bottomBox.mainResizeShow" - id="model-list-table" - ref="modelTable" - v-loading="tools.loading" - :cell-class-name="assetStatClassName" - :data="tableData" - :height="mainTableHeight" - border - @sort-change="tableDataSort" - @row-dblclick="panel" - @selection-change="(selection)=>{this.batchDeleteObjs=selection}" + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.model" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:top-tool-right> + <button id="model-add" v-has="'model_toAdd'" :title="$t('overall.createModel')" class="top-tool-btn margin-l-20" @click="add"> + <i class="nz-icon-create-square nz-icon"></i> + </button> + <delete-button id="model-list-batch-delete" v-has="'model_delete'" :delete-objs="batchDeleteObjs" api="model" @after="getTableData" @before="delFlag=true"></delete-button> + </template> + <template v-slot:default="slotProps"> + <el-table + id="model-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" > <el-table-column :resizable="false" @@ -51,89 +32,94 @@ type="selection" width="55"> </el-table-column> - <el-table-column v-for="(item, index) in tools.customTableTitle" - v-if="item.show" - :key="`col-${index}`" - :label="item.label" - :prop="$tableSet.propTitle(item.prop,'model')" - :resizable="true" - :sort-orders="['ascending', 'descending']" - :sortable="$tableSet.sortableShow(item.prop,'model')"> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> <template slot-scope="scope" :column="item"> - <template v-if="item.prop == 'vendor'" >{{scope.row[item.prop].value}}</template> - <template v-else-if="item.prop == 'type'" >{{scope.row[item.prop].value}}</template> - <template v-else-if="item.prop == 'assetStat' && scope.row.assetStat" > + <template v-if="item.prop === 'vendor'" >{{scope.row[item.prop].value}}</template> + <template v-else-if="item.prop === 'type'" >{{scope.row[item.prop].value}}</template> + <template v-else-if="item.prop === 'assetStat' && scope.row.assetStat" > <el-popover :content="$t('overall.result.total') + ':' + scope.row.assetStat.total + ',' + $t('asset.inStock') + ':' + scope.row.assetStat.inStock + ',' + $t('asset.notInStock') + ':' + scope.row.assetStat.outStock + ',' + $t('asset.suspended') + ':' + scope.row.assetStat.suspended" placement="top" trigger="hover"> - <div slot="reference" class="dc-asset-states"> - <span class="dc-asset-state dc-asset-state-total">{{scope.row.assetStat.total}}</span> - <span class="dc-asset-state dc-asset-state-in">{{scope.row.assetStat.inStock}}</span> - <span class="dc-asset-state dc-asset-state-out">{{scope.row.assetStat.outStock}}</span> - <span class="dc-asset-state dc-asset-state-suspended">{{scope.row.assetStat.suspended}}</span> - </div> - </el-popover> + <div slot="reference" class="dc-asset-states"> + <span class="dc-asset-state dc-asset-state-total">{{scope.row.assetStat.total}}</span> + <span class="dc-asset-state dc-asset-state-in">{{scope.row.assetStat.inStock}}</span> + <span class="dc-asset-state dc-asset-state-out">{{scope.row.assetStat.outStock}}</span> + <span class="dc-asset-state dc-asset-state-suspended">{{scope.row.assetStat.suspended}}</span> + </div> + </el-popover> </template> <template v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</template> <template v-else>-</template> </template> </el-table-column> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['edit', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `sys/role?ids=${scope.row.id}`]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + </div> + </el-table-column> </el-table> - </div> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" @click="toTop(scrollbarWrap)" class="to-top" v-show="tools.showTopBtn" id="model-list-totop"><i class="nz-icon nz-icon-top"></i></button> - <div class="pagination-bottom" v-show="!bottomBox.showSubList"> - <Pagination :tableId="tableId" :pageObj="pageObj" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"></Pagination> - </div> - </div> - <transition name="el-zoom-in-bottom"> - <bottom-box :from="$CONSTANTS.fromRoute.model" :is-fullscreen="bottomBox.isFullScreen" :obj="bottomBox.model" :sub-resize-show="bottomBox.subResizeShow" :target-tab.sync="bottomBox.targetTab" v-if="bottomBox.showSubList" - @closeSubList="bottomBox.showSubList = false" @fullScreen="fullScreen" @exitFullScreen="exitFullScreen" @listResize="listResize" ref="panelBox"></bottom-box> - </transition> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> <transition name="right-box"> - <model-box v-if="rightBox.show" ref="modelBox" :model="model" @close="closeRightBox" @reload="getTableData"></model-box> + <model-box v-if="rightBox.show" ref="modelBox" :model="object" @close="closeRightBox" @reload="getTableData"></model-box> </transition> </div> - </template> <script> -import bus from '../../../libs/bus' -import deleteButton from '../../common/deleteButton' +import modelBox from '@/components/common/rightBox/modelBox' +import deleteButton from '@/components/common/deleteButton' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' export default { name: 'model', components: { - 'delete-button': deleteButton + deleteButton, + modelBox, + nzDataList }, + mixins: [tableMixin], data () { return { - /* 二级页面相关 */ - bottomBox: { - modelDetail: {}, // asset详情 - model: {}, // 告警信息对应的asset对象 - mainResizeShow: true, // dom高度改变时是否展示|隐藏 - subResizeShow: true, - isFullScreen: false, // 全屏状态 - showSubList: false, // 是否显示二级列表 - targetTab: '', // 显示二级列表中的哪个页签 - inTransform: false // 搜索框相关,搜索条件下拉框是否在transform里 - }, - mainTableHeight: this.$tableHeight.normal, // 主列表table高度 - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - batchDeleteObjs: [], tableId: 'modelTable', // 需要分页的table的id,用于记录每页数量 - rightBox: { show: false }, - - model: {}, - blankModel: { + blankObject: { id: '', name: '', vendor: { id: '', value: '', code: '', type: '' }, @@ -144,11 +130,6 @@ export default { typeCode: '', uSize: 1 }, - pageObj: { - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, tableTitle: [ { label: 'ID', @@ -173,7 +154,6 @@ export default { show: true } ], - tableData: [], searchMsg: { // 给搜索框子组件传递的信息 zheze_none: true, searchLabelList: [{ @@ -189,10 +169,7 @@ export default { label: 'dc', disabled: false }] - }, - searchLabel: {}, // 搜索参数 - scrollbarWrap: null, - delFlag: false + } } }, methods: { @@ -210,65 +187,6 @@ export default { this.bottomBox.model = obj this.bottomBox.targetTab = 'panel' }, - // 全屏 - fullScreen () { - const vm = this - this.$bottomBoxWindow.fullScreen(vm) - }, - // 退出全屏 - exitFullScreen () { - const vm = this - this.$bottomBoxWindow.exitFullScreen(vm) - }, - // 鼠标拖动二级列表 - listResize (e) { - const vm = this - this.$bottomBoxWindow.listResize(vm, e) - }, - edit (u) { - this.model = Object.assign({}, u) - this.rightBox.show = true - }, - del (u) { - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('model?ids=' + u.id).then(response => { - if (response.code === 200) { - this.delFlag = true - this.$message({ duration: 1000, type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getTableData() - } else { - this.$message.error(response.msg) - } - }) - }) - }, - add () { - this.model = this.newModel() - this.rightBox.show = true - }, - newModel () { - return JSON.parse(JSON.stringify(this.blankModel)) - }, - closeRightBox (refresh) { - this.rightBox.show = false - if (refresh) { - this.delFlag = true - this.getTableData() - } - }, - jumpTo (data, id) { - bus.$emit('menu-change', data) - this.$router.push({ - path: '/' + data, - query: { - t: +new Date() - } - }) - }, getTableData () { if (!this.hasButton('model_view')) { this.$message.error(this.$t('tip.noAccess')) @@ -285,94 +203,12 @@ export default { this.pageObj.total = response.data.total if (!this.scrollbarWrap) { this.$nextTick(() => { - this.scrollbarWrap = this.$refs.modelTable.bodyWrapper + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper this.toTopBtnHandler(this.scrollbarWrap) }) } } }) - }, - pageNo (val) { - console.info(val) - this.pageObj.pageNo = val - this.getTableData() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getTableData() - }, - search (searchObj) { - let orderBy = '' - if (this.searchLabel.orderBy) { - orderBy = this.searchLabel.orderBy - } - this.pageObj.pageNo = 1 - this.searchLabel = {} - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (orderBy) { - this.$set(this.searchLabel, 'orderBy', orderBy) - } - if (this.$refs.modelTable && this.$refs.modelTable.bodyWrapper) { - this.$refs.modelTable.bodyWrapper.scrollTop = 0 - } - this.getTableData() - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getTableData() - } - }, - created () { - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize - } - }, - mounted () { - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - - this.getTableData() - }, - watch: { - 'bottomBox.showSubList': function (n) { - const vm = this - this.$bottomBoxWindow.showSubListWatch(vm, n) - }, - tableData: { - deep: true, - handler (n) { - if (n.length === 0 && this.pageObj.pageNo > 1) { - this.pageNo(this.pageObj.pageNo - 1) - } - if (!this.delFlag) { // 不是删除时回到顶部 - this.$refs.modelTable.bodyWrapper.scrollTop = 0 - } else { - this.delFlag = false - } - } - } - }, - beforeDestroy () { - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) } } } diff --git a/nezha-fronted/src/components/page/config/operationLog.vue b/nezha-fronted/src/components/page/config/operationLog.vue new file mode 100644 index 000000000..a351daa8d --- /dev/null +++ b/nezha-fronted/src/components/page/config/operationLog.vue @@ -0,0 +1,208 @@ +<template> + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle" + :from="fromRoute.operationLog"> + <template v-slot:default="slotProps"> + <el-table + id="role-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" + > + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> + <template slot-scope="scope" :column="item"> + <span v-if="item.prop === 'time'"> + {{scope.row[item.prop]}} ms + </span> + <span v-else-if="item.prop === 'username'">{{formatUsername(scope.row)}}</span> + <span v-else-if="item.prop === 'createDate'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> + <span v-else>{{scope.row[item.prop]}}</span> + </template> + </el-table-column> + </el-table> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> + </div> +</template> +<script> +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' + +export default { + name: 'oparetionlog', + components: { + nzDataList + }, + mixins: [tableMixin], + data () { + return { + tableId: 'operationLogTable', // 需要分页的table的id,用于记录每页数量 + tableTitle: [ + { + label: this.$t('config.operationlog.id'), + prop: 'id', + show: true, + width: 80 + }, { + label: this.$t('config.operationlog.username'), + prop: 'username', + show: true + }, + { + label: this.$t('config.operationlog.ip'), + prop: 'ip', + show: true + }, + { + label: this.$t('config.operationlog.operation'), + prop: 'operation', + show: true + }, + { + label: this.$t('config.operationlog.type'), + prop: 'type', + show: true + }, + { + label: this.$t('config.operationlog.state'), + prop: 'state', + show: true + }, + // { + // label: this.$t('config.operationlog.userId'), + // prop: 'userId', + // show: false, + // }, + { + label: this.$t('config.operationlog.operaId'), + prop: 'operaId', + show: false + }, + { + label: this.$t('config.operationlog.createDate'), + prop: 'createDate', + show: true + }, + { + label: this.$t('config.operationlog.time'), + prop: 'time', + show: false + }, + { + label: this.$t('config.operationlog.params'), + prop: 'params', + show: false + }, + { + label: this.$t('config.operationlog.response'), + prop: 'response', + show: false + } + ], + searchMsg: { // 给搜索框子组件传递的信息 + zheze_none: true, + searchLabelList: [ + { + id: 11, + name: this.$t('config.operationlog.type'), + type: 'input', + label: 'type', + disabled: false + }, { + id: 12, + name: this.$t('config.operationlog.username'), + type: 'input', + label: 'username', + disabled: false + }, { + id: 13, + name: this.$t('config.operationlog.operation'), + type: 'selectString', + label: 'operation', + disabled: false + } + ] + } + } + }, + methods: { + messageStyle (e) { + if (e.column.label === this.$t('config.operationlog.state')) { + if (e.row.state === 'success') { + return 'success' + } else { + return 'danger' + } + } + return '' + }, + getTableData () { + this.$set(this.searchLabel, 'pageNo', this.pageObj.pageNo) + this.$set(this.searchLabel, 'pageSize', this.pageObj.pageSize) + this.tools.loading = true + this.$get('sys/log/list', this.searchLabel).then(response => { + this.tools.loading = false + if (response.code === 200) { + this.tableData = response.data.list + this.pageObj.total = response.data.total + if (!this.scrollbarWrap) { + this.$nextTick(() => { + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper + this.toTopBtnHandler(this.scrollbarWrap) + }) + } + } + }) + }, + formatUsername (row) { + if (row.username) { + return row.username + } else if (row.operation === 'login' && !row.username) { // 如果是登录 且登录失败 + return JSON.parse(row.params).username + } else { + return '-' + } + } + } +} +</script> diff --git a/nezha-fronted/src/components/page/config/operationlog.vue b/nezha-fronted/src/components/page/config/operationlog.vue index ad28d7222..021b4ed3a 100644 --- a/nezha-fronted/src/components/page/config/operationlog.vue +++ b/nezha-fronted/src/components/page/config/operationlog.vue @@ -1,112 +1,82 @@ -<style scoped> - .operationlog { - height: 100%; - } -</style> <template> - <div class="operationlog"> - <div class="top-tools"> - <div></div> - <div> - <div class="top-tool-search margin-r-5"> - <search-input :searchMsg="searchMsg" @search="search"></search-input> - </div> - </div> - </div> - <!-- 自定义table列 --> - <transition name="el-zoom-in-top"> - <element-set - id="operation-log-list" - v-if="tools.showCustomTableTitle" - @close="tools.showCustomTableTitle = false" - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - ref="customTableTitle" - ></element-set> - </transition> - <el-table - id="operation-log-list-table" - class="nz-table" - :data="tableData" - border - ref="operationLogTable" - :height="$tableHeight.normal" - v-loading="tools.loading" - :cell-class-name="messageStyle" - style="width: 100%;" - @sort-change="tableDataSort" - > - <el-table-column - :resizable="true" - v-for="(item, index) in tools.customTableTitle" - v-if="item.show" - :key="`col-${index}`" - :label="item.label" - :sortable="$tableSet.sortableShow(item.prop,'operationlog')" - :prop="$tableSet.propTitle(item.prop,'operationlog')" - :sort-orders="['ascending', 'descending']" - > - <template slot-scope="scope" :column="item"> - <span v-if="item.prop == 'time'"> - {{scope.row[item.prop]}} ms - </span> - <span v-else-if="item.prop == 'username'">{{formatUsername(scope.row)}}</span> - <span v-else-if="item.prop == 'createDate'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> - <span v-else>{{scope.row[item.prop]}}</span> - </template> - </el-table-column> - <el-table-column width="28"> - <template slot="header"> - <span @mousedown.stop="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)" class="nz-table-gear"> - <i class="nz-icon nz-icon-gear"></i> - </span> - </template> - </el-table-column> - </el-table> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" @click="toTop(scrollbarWrap)" class="to-top" v-show="tools.showTopBtn" id="operation-log-totop"><i class="nz-icon nz-icon-top"></i></button> - <Pagination :tableId="tableId" :pageObj="pageObj" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"></Pagination> + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.operationLog" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:default="slotProps"> + <el-table + id="role-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" + > + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> + <template slot-scope="scope" :column="item"> + <span v-if="item.prop === 'time'"> + {{scope.row[item.prop]}} ms + </span> + <span v-else-if="item.prop === 'username'">{{formatUsername(scope.row)}}</span> + <span v-else-if="item.prop === 'createDate'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> + <span v-else>{{scope.row[item.prop]}}</span> + </template> + </el-table-column> + </el-table> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> </div> </template> <script> -import bus from '../../../libs/bus' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' + export default { name: 'oparetionlog', + components: { + nzDataList + }, + mixins: [tableMixin], data () { return { tableId: 'operationLogTable', // 需要分页的table的id,用于记录每页数量 - - rightBox: { // 弹出框相关 - show: false - }, - rightBoxResize: { // resize弹出框相关 - show: false, - isAdd: false, // false,true:resize - title: '' - }, - rightBoxDownload: { // 下载弹出框相关 - show: false, - isAdd: false, // false,true:resize - title: '' - }, - rightBoxUpload: { // 上传弹出框相关 - show: false, - isAdd: false, // false,true:resize - title: '' - }, - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - pageObj: { - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, tableTitle: [ { label: this.$t('config.operationlog.id'), @@ -169,7 +139,6 @@ export default { show: false } ], - tableData: [], searchMsg: { // 给搜索框子组件传递的信息 zheze_none: true, searchLabelList: [ @@ -193,15 +162,13 @@ export default { disabled: false } ] - }, - searchLabel: {}, // 搜索参数 - scrollbarWrap: null + } } }, methods: { messageStyle (e) { - if (e.column.label == this.$t('config.operationlog.state')) { - if (e.row.state == 'success') { + if (e.column.label === this.$t('config.operationlog.state')) { + if (e.row.state === 'success') { return 'success' } else { return 'danger' @@ -209,7 +176,7 @@ export default { } return '' }, - getTableData: function () { + getTableData () { this.$set(this.searchLabel, 'pageNo', this.pageObj.pageNo) this.$set(this.searchLabel, 'pageSize', this.pageObj.pageSize) this.tools.loading = true @@ -220,22 +187,13 @@ export default { this.pageObj.total = response.data.total if (!this.scrollbarWrap) { this.$nextTick(() => { - this.scrollbarWrap = this.$refs.operationLogTable.bodyWrapper + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper this.toTopBtnHandler(this.scrollbarWrap) }) } } }) }, - pageNo (val) { - this.pageObj.pageNo = val - this.getTableData() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getTableData() - }, formatUsername (row) { if (row.username) { return row.username @@ -244,70 +202,7 @@ export default { } else { return '-' } - }, - search: function (searchObj) { - let orderBy = '' - if (this.searchLabel.orderBy) { - orderBy = this.searchLabel.orderBy - } - this.searchLabel = {} - this.pageObj.pageNo = 1 - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (orderBy) { - this.$set(this.searchLabel, 'orderBy', orderBy) - } - this.getTableData() - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getTableData() - } - }, - watch: { - tableData () { - if (this.$refs.operationLogTable && this.$refs.operationLogTable.bodyWrapper) { - this.$refs.operationLogTable.bodyWrapper.scrollTop = 0 - } - } - }, - beforeDestroy () { - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) - }; - }, - computed: { - isCurrentUser () { - return function (username) { - return localStorage.getItem('nz-username') == username - } } - }, - created () { - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize - } - }, - mounted () { - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - this.getTableData() } } </script> diff --git a/nezha-fronted/src/components/page/config/promServer.vue b/nezha-fronted/src/components/page/config/promServer.vue index 71943db10..65a797ea8 100644 --- a/nezha-fronted/src/components/page/config/promServer.vue +++ b/nezha-fronted/src/components/page/config/promServer.vue @@ -1,42 +1,29 @@ -<style lang="scss"> -@import '@/assets/css/common/tableCommon.scss'; -</style> <template> - <div class="prom list-page"> - <div class="main-list" :class="{'main-list-with-sub': bottomBox.showSubList}"> - <div class="main-modal"></div> - <div class="top-tools" v-show="bottomBox.mainResizeShow"> - <div class="top-tool-main-right" :class="{'top-tool-main-right-to-left': bottomBox.showSubList}"> - <div class="top-tool-search"> - <search-input ref="searchInput" :searchMsg="searchMsg" @search="search" :inTransform="bottomBox.inTransform"></search-input> - </div> - <button :title="$t('overall.createPrometheusServer')" @click="add" type="button" v-has="'prom_toAdd'" - id="prom-add" class="top-tool-btn margin-l-20"> - <i class="nz-icon-create-square nz-icon"></i> - </button> - <delete-button :delete-objs="batchDeleteObjs" @after="getTableData" @before="delFlag=true" api="promServer" v-has="'prom_delete'" id="promserver-list-batch-delete"></delete-button> - <button id="prom-column-setting" class="top-tool-btn margin-l-10" - type="button" @click="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)"> - <i class="nz-icon-gear nz-icon"></i> - </button> - </div> - <div class="pagination-top pagination-top-hide display-none"></div> - </div> - <!-- 自定义table列 --> - <transition name="el-zoom-in-top"> - <element-set - id="promserver-list" - v-if="tools.showCustomTableTitle" - @close="tools.showCustomTableTitle = false" - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - ref="customTableTitle" - ></element-set> - </transition> - <div class="nz-table2"> - <el-table v-show="bottomBox.mainResizeShow" ref="promTable" v-loading="tools.loading" :data="tableData" - :height="mainTableHeight" border @sort-change="tableDataSort" - @selection-change="(selection)=>{this.batchDeleteObjs=selection}" + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.promServer" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:top-tool-right> + <button id="prom-add" v-has="'prom_toAdd'" :title="$t('overall.createPrometheusServer')" class="top-tool-btn margin-l-20" + type="button" @click="add"> + <i class="nz-icon-create-square nz-icon"></i> + </button> + <delete-button id="promserver-list-batch-delete" v-has="'prom_delete'" :delete-objs="batchDeleteObjs" api="agent" @after="getTableData" @before="delFlag=true"></delete-button> + </template> + <template v-slot:default="slotProps"> + <el-table ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" > <el-table-column :resizable="false" @@ -47,20 +34,24 @@ <el-table-column v-for="(item, index) in tools.customTableTitle" v-if="item.show" :key="`col-${index}`" :label="item.label" - :prop="$tableSet.propTitle(item.prop,'promServer')" + :prop="propTitle(item.prop, fromRoute.promServer)" :resizable="true" :sort-orders="['ascending', 'descending']" - :sortable="$tableSet.sortableShow(item.prop,'promServer')"> + :sortable="sortableShow(item.prop, fromRoute.promServer)"> + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> <template slot-scope="scope" :column="item"> - <span v-if="item.prop == 'idc'" >{{scope.row[item.prop]?scope.row[item.prop].name:'-'}}</span> + <span v-if="item.prop === 'idc'" >{{scope.row[item.prop]?scope.row[item.prop].name:'-'}}</span> - <span v-else-if="item.prop == 'type'"> - <!--{{scope.row[item.prop] == '1' ? 'Global' : ''}} - {{scope.row[item.prop] == '2' ? 'Per-Datacenter' : ''}}--> + <span v-else-if="item.prop === 'type'"> {{findServerType(scope.row[item.prop]).text}} </span> - <span v-else-if="item.prop == 'checkTime'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> - <span v-else-if="item.prop == 'status'"> + <span v-else-if="item.prop === 'checkTime'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> + <span v-else-if="item.prop === 'status'"> <el-popover :content="$t('asset.assetStatPre')+(scope.row.checkTime?utcTimeToTimezoneStr(scope.row.checkTime):$t('asset.assetStatDown'))" placement="right" trigger="hover" width="200"> <div slot="reference" style="width: 20px"> <div :class="{'active-icon green':scope.row[item.prop] == '1','active-icon red':scope.row[item.prop] == '0' || scope.row[item.prop] == '-1' || scope.row[item.prop] == '-2'}"></div> @@ -71,74 +62,62 @@ <template v-else>-</template> </template> </el-table-column> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['edit', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `agent?ids=${scope.row.id}`]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + </div> + </el-table-column> </el-table> - </div> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" @click="toTop(scrollbarWrap)" class="to-top" v-show="tools.showTopBtn && bottomBox.mainResizeShow" id="promserver-list-totop"><i class="nz-icon nz-icon-top"></i></button> - <div class="pagination-bottom" v-show="!bottomBox.showSubList"> - <Pagination :tableId="tableId" :pageObj="pageObj" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"></Pagination> - </div> - </div> - <transition name="el-zoom-in-bottom"> - <bottom-box v-if="bottomBox.showSubList" :sub-resize-show="bottomBox.subResizeShow" :obj="bottomBox.promServer" :is-full-screen="bottomBox.isFullScreen" :from="'promServer'" :target-tab.sync="bottomBox.targetTab" :detail="bottomBox.promDetail" - @closeSubList="bottomBox.showSubList = false" @fullScreen="fullScreen" @exitFullScreen="exitFullScreen" @listResize="listResize" ></bottom-box> - </transition> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="account-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> <transition name="right-box"> - <prom-server-box v-if="rightBox.show" :prom-server="promServer" @close="closeRightBox"></prom-server-box> + <prom-server-box v-if="rightBox.show" :prom-server="object" @close="closeRightBox"></prom-server-box> </transition> </div> </template> <script> -import bus from '../../../libs/bus' -import promServerBox from '../../common/rightBox/promServerBox' -import deleteButton from '../../common/deleteButton' +import deleteButton from '@/components/common/deleteButton' +import promServerBox from '@/components/common/rightBox/promServerBox' +import { promServer } from '@/components/common/js/constants' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' export default { name: 'promServer', components: { - 'prom-server-box': promServerBox, - 'delete-button': deleteButton + nzDataList, + promServerBox, + deleteButton }, + mixins: [tableMixin], data () { return { - // 侧滑 - rightBox: { - show: false - }, - /* 二级页面相关 */ - bottomBox: { - promDetail: {}, - promServer: {}, - mainResizeShow: true, // dom高度改变时是否展示|隐藏 - subResizeShow: true, - isFullScreen: false, // 全屏状态 - showSubList: false, // 是否显示二级列表 - targetTab: '', // 显示二级列表中的哪个页签 - inTransform: false // 搜索框相关,搜索条件下拉框是否在transform里 - }, - mainTableHeight: this.$tableHeight.normal, // 主列表table高度 - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - batchDeleteObjs: [], tableId: 'promTable', // 需要分页的table的id,用于记录每页数量 - promServer: {}, - blankPromServer: { + blankObject: { id: '', host: '', port: 9090, idc: { id: '', name: '', location: '' } }, - pageObj: { - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, tableTitle: [ { label: 'ID', @@ -207,97 +186,10 @@ export default { disabled: false }] }, - searchLabel: {}, // 搜索参数 - promServerType: null, - scrollbarWrap: null, - delFlag: false + promServerType: null } }, methods: { - // 全屏 - fullScreen () { - const vm = this - this.$bottomBoxWindow.fullScreen(vm) - }, - // 退出全屏 - exitFullScreen () { - const vm = this - this.$bottomBoxWindow.exitFullScreen(vm) - }, - // 鼠标拖动二级列表 - listResize (e) { - const vm = this - this.$bottomBoxWindow.listResize(vm, e) - }, - convertToDetail (obj) { - const detail = [] - detail.push({ label: this.$t('config.dc.dc'), value: obj.idc.name }) - detail.push({ label: 'Host', value: obj.host }) - detail.push({ label: 'Port', value: obj.port }) - let type = '' - for (let i = 0; i < this.$CONSTANTS.promServer.typeData.length; i++) { - if (obj.value == this.$CONSTANTS.promServer.typeData[i].type) { - type = this.$CONSTANTS.promServer.typeData[i].label - break - } - } - detail.push({ label: this.$t('config.promServer.type'), value: type }) - detail.push({ - label: this.$t('asset.state'), - value: obj.status, - type: 'status', - msg: this.$t('asset.assetStatPre') + (obj.checkTime ? obj.checkTime : this.$t('asset.assetStatDown')) - }) - return detail - }, - edit (u) { - this.promServer = JSON.parse(JSON.stringify(u)) - this.rightBox.show = true - }, - /* 删除 */ - del (u) { - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('promServer?ids=' + u.id).then(response => { - if (response.code === 200) { - this.delFlag = true - this.$message({ duration: 1000, type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getTableData() - } else { - this.$message.error(response.msg) - } - }) - }) - }, - detail (u) { - this.bottomBox.promServer = JSON.parse(JSON.stringify(u)) - this.bottomBox.targetTab = 'detail' - this.bottomBox.showSubList = true - }, - add () { - this.promServer = this.newPromServer() - this.rightBox.show = true - }, - closeRightBox (refresh) { - this.rightBox.show = false - if (refresh) { - this.delFlag = true - this.getTableData() - } - }, - - jumpTo (data, id) { - bus.$emit('menu-change', data) - this.$router.push({ - path: '/' + data, - query: { - t: +new Date() - } - }) - }, getTableData () { if (!this.hasButton('prom_view')) { this.$message.error(this.$t('tip.noAccess')) @@ -306,7 +198,7 @@ export default { this.$set(this.searchLabel, 'pageNo', this.pageObj.pageNo) this.$set(this.searchLabel, 'pageSize', this.pageObj.pageSize) this.loading = true - this.$get('promServer', this.searchLabel).then(response => { + this.$get('agent', this.searchLabel).then(response => { this.loading = false if (response.code === 200) { for (let i = 0; i < response.data.list.length; i++) { @@ -321,45 +213,13 @@ export default { this.pageObj.total = response.data.total if (!this.scrollbarWrap) { this.$nextTick(() => { - this.scrollbarWrap = this.$refs.promTable.bodyWrapper + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper this.toTopBtnHandler(this.scrollbarWrap) }) } } }) }, - newPromServer () { - return JSON.parse(JSON.stringify(this.blankPromServer)) - }, - pageNo (val) { - this.pageObj.pageNo = val - this.getTableData() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getTableData() - }, - search (searchObj) { - let orderBy = '' - if (this.searchLabel.orderBy) { - orderBy = this.searchLabel.orderBy - } - this.pageObj.pageNo = 1 - this.searchLabel = {} - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (orderBy) { - this.$set(this.searchLabel, 'orderBy', orderBy) - } - if (this.$refs.promTable && this.$refs.promTable.bodyWrapper) { - this.$refs.promTable.bodyWrapper.scrollTop = 0 - } - this.getTableData() - }, // 获取dc数据 getDcData () { return new Promise(resolve => { @@ -371,22 +231,10 @@ export default { }) }) }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getTableData() - }, findServerType (type) { if (!this.promServerType) { this.promServerType = [] - this.$CONSTANTS.promServer.theData.forEach(item => { + promServer.theData.forEach(item => { this.promServerType = this.promServerType.concat(item.children) }) } @@ -395,59 +243,11 @@ export default { }) } }, - created () { - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize - } - }, mounted () { // 初始化数据 Promise.all([this.getDcData()]).then(response => { this.getTableData() }) - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize - } - }, - beforeDestroy () { - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) - }; - }, - - watch: { - 'bottomBox.promServer': { - deep: true, - handler (n) { - this.bottomBox.promDetail = this.convertToDetail(n) - } - }, - 'bottomBox.showSubList': function (n) { - const vm = this - this.$bottomBoxWindow.showSubListWatch(vm, n) - }, - tableData: { - deep: true, - handler (n) { - if (n.length === 0 && this.pageObj.pageNo > 1) { - this.pageNo(this.pageObj.pageNo - 1) - } - if (!this.delFlag) { // 不是删除时回到顶部 - this.$refs.promTable.bodyWrapper.scrollTop = 0 - } else { - this.delFlag = false - } - } - } } } </script> diff --git a/nezha-fronted/src/components/page/config/roles.vue b/nezha-fronted/src/components/page/config/roles.vue index 31f892840..9db864629 100644 --- a/nezha-fronted/src/components/page/config/roles.vue +++ b/nezha-fronted/src/components/page/config/roles.vue @@ -1,49 +1,31 @@ -<style lang="scss"> -@import '@/assets/css/common/tableCommon.scss'; -</style> <template> - <div class="roles list-page"> - <!-- 主页面 --> - <div class="main-list" > - <!-- 顶部工具栏 --> - <div class="main-modal"></div> - <div class="top-tools" > - <div class="top-tool-main-right" > - <div class="top-tool-search"> - <search-input :searchMsg="searchMsg" @search="search" ref="searchInput" ></search-input> - </div> - <button v-has="'role_toAdd'" :title="$t('overall.createRole')" class="top-tool-btn margin-l-20" @click="add" - id="roles-add" type="button"> - <i class="nz-icon-create-square nz-icon"></i> - </button> - <delete-button :delete-objs="batchDeleteObjs" :filter-function="(arr)=>{return '?ids='+arr.map(t=>t.id).join(',')}" @after="getTableData" @before="delFlag=true" api="sys/role" v-has="'role_delete'" id="role-list-batch-delete"></delete-button> - <button id="account-column-setting" class="top-tool-btn margin-l-10" - type="button" @click="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)"> - <i class="nz-icon-gear nz-icon"></i> - </button> - </div> - <!-- 顶部分页组件,当打开底部上滑框时出现 --> - <div class="pagination-top pagination-top-hide display-none"></div> - </div> - <!-- 自定义table列 --> - <transition name="el-zoom-in-top"> - <element-set - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - @close="tools.showCustomTableTitle = false" - ref="customTableTitle" - v-if="tools.showCustomTableTitle" - ></element-set> - </transition> - <div class="nz-table2"> + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.role" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:top-tool-right> + <button id="roles-add" v-has="'role_toAdd'" :title="$t('overall.createRole')" class="top-tool-btn margin-l-20" + type="button" @click="add"> + <i class="nz-icon-create-square nz-icon"></i> + </button> + <delete-button id="role-list-batch-delete" v-has="'role_delete'" :delete-objs="batchDeleteObjs" api="sys/role" @after="getTableData" @before="delFlag=true"></delete-button> + </template> + <template v-slot:default="slotProps"> <el-table - ref="rolesTable" + id="role-list-table" + ref="dataTable" v-loading="tools.loading" :data="tableData" :height="mainTableHeight" border - @selection-change="(selection)=>{this.batchDeleteObjs=selection}" + @header-dragend="dragend" @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" > <el-table-column :resizable="false" @@ -60,22 +42,16 @@ :prop="item.prop" :resizable="true" :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" > - <template slot="header" > - <span v-if="item.type == 'tag'" :title="item.label" class="tag-header"><span class="tag-value">{{item.label}}</span><span style="color:orange;"> [Notification]</span></span> - <span v-else><span>{{item.label}}</span></span> + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> </template> <template slot-scope="scope" :column="item"> - <div v-if="item.prop == 'option'" class="content-right-options"> - <template v-if="scope.row.buildIn != 1"> - <span :id="'roles-edit-'+scope.row.id" v-has="'role_toEdit'" :title="$t('overall.edit')" class="content-right-option" @click="edit(scope.row)"><i :class="{'gray-filter':scope.row.buildIn == 1}" class="nz-icon nz-icon-edit"></i></span> - - <span :id="'roles-del-'+scope.row.id" v-has="'role_delete'" :title="$t('overall.delete')" class="content-right-option" @click="del(scope.row)"><i :class="{'gray-filter':scope.row.buildIn == 1}" class="nz-icon nz-icon-delete"></i></span> - </template> - <template v-else> - <span :id="'roles-detail-'+scope.row.id" :title="$t('overall.view')" class="content-right-option" @click="detail(scope.row)"><i class="nz-icon nz-icon-view"></i></span> - </template> - </div> <template v-if="item.prop == 'name'"> <template v-if="scope.row.i18n"> <span>{{$t(scope.row.i18n)}}</span> @@ -93,72 +69,54 @@ <el-table-column :resizable="false" fixed="right" - width="165"> + :width="operationWidth"> <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> <div slot-scope="scope" class="table-operation-items"> - <button class="table-operation-item" @click="showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('operationLog', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> <el-dropdown size="medium" trigger="hover" @command="tableOperation"> <div class="table-operation-item table-operation-item--more"> <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> </div> <el-dropdown-menu slot="dropdown"> - <el-dropdown-item :command="['edit', scope.row]" ><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> - <el-dropdown-item :command="['delete', scope.row]" ><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> + <el-dropdown-item :command="['edit', scope.row]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> + <el-dropdown-item :command="['delete', scope.row, `sys/role?ids=${scope.row.id}`]" :disabled="isBuildIn(scope.row)"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> </el-dropdown-menu> </el-dropdown> </div> </el-table-column> </el-table> - </div> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" @click="toTop(scrollbarWrap)" class="to-top" v-show="tools.showTopBtn && bottomBox.mainResizeShow"><i class="nz-icon nz-icon-top"></i></button> - <div class="pagination-bottom" > - <Pagination :tableId="tableId" :pageObj="pageObj" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"></Pagination> - </div> - </div> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> <transition name="right-box"> - <role-box :detail="rightBox.detail" :role="role" @close="closeRightBox" v-if="rightBox.show"></role-box> + <role-box v-if="rightBox.show" :role="object" @close="closeRightBox"></role-box> </transition> </div> </template> <script> -import deleteButton from '../../common/deleteButton' -import roleBox from '../../common/rightBox/roleBox' -import bus from '../../../libs/bus' +import roleBox from '@/components/common/rightBox/roleBox' +import deleteButton from '@/components/common/deleteButton' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' export default { name: 'roles', components: { - 'role-box': roleBox, - 'delete-button': deleteButton + roleBox, + deleteButton, + nzDataList }, + mixins: [tableMixin], data () { return { - // 侧滑 - rightBox: { - show: false, - detail: false - }, - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - mainTableHeight: this.$tableHeight.normal, // 主列表table高度 - batchDeleteObjs: [], - role: {}, - tableId: 'rolesTable', // 需要分页的table的id,用于记录每页数量 - blankRole: { // 空白对象 - - }, - pageObj: { // 分页对象 - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 + blankObject: { // 空白对象 + name: '' }, tableTitle: [ // 原table列 { @@ -176,7 +134,6 @@ export default { show: true } ], - tableData: [], searchMsg: { // 给搜索框子组件传递的信息 zheze_none: true, searchLabelList: [{ @@ -186,53 +143,10 @@ export default { label: 'name', disabled: false }] - }, - searchLabel: {}, // 搜索参数 - scrollbarWrap: null, - delFlag: false + } } }, methods: { - closeRightBox (refresh) { - this.rightBox.show = false - if (refresh) { - this.delFlag = true - this.getTableData() - } - }, - edit (u) { - if (u.buildIn == 1) { - return - } - this.role = JSON.parse(JSON.stringify(u)) - this.$get('sys/role/menu/' + this.role.id).then(response => { - if (response.code == 200) { - this.role.menuIds = response.data.selectedIds - this.rightBox.show = true - this.rightBox.detail = false - } - }) - }, - del (u) { - if (u.buildIn == 1) { - return - } - this.$confirm(this.$t('tip.confirmDelete'), { - confirmButtonText: this.$t('tip.yes'), - cancelButtonText: this.$t('tip.no'), - type: 'warning' - }).then(() => { - this.$delete('sys/role?ids=' + u.id).then(response => { - if (response.code === 200) { - this.delFlag = true - this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') }) - this.getTableData() - } else { - this.$message.error(response.msg) - } - }) - }) - }, getTableData () { if (!this.hasButton('role_view')) { this.$message.error(this.$t('tip.noAccess')) @@ -255,93 +169,7 @@ export default { } } }) - }, - add () { - this.role = this.newRole() - this.rightBox.show = true - this.rightBox.detail = false - }, - esc () { - this.rightBox.show = false - this.rightBox.detail = false - }, - detail: function (data) { - this.role = JSON.parse(JSON.stringify(data)) - this.rightBox.show = true - this.rightBox.detail = true - }, - newRole () { - return JSON.parse(JSON.stringify(this.blankRole)) - }, - pageNo (val) { - this.pageObj.pageNo = val - this.getTableData() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getTableData() - }, - search (searchObj) { - this.searchLabel = {} - this.pageObj.pageNo = 1 - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (this.$refs.rolesTable) { - this.$refs.rolesTable.bodyWrapper.scrollTop = 0 - } - this.getTableData() - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getTableData() - } - }, - watch: { - tableData: { - deep: true, - handler (n) { - if (n.length === 0 && this.pageObj.pageNo > 1) { - this.pageNo(this.pageObj.pageNo - 1) - } - if (!this.delFlag) { // 不是删除时回到顶部 - this.$refs.rolesTable.bodyWrapper.scrollTop = 0 - } else { - this.delFlag = false - } - } } - }, - created () { - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize - } - }, - beforeDestroy () { - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) - }; - }, - mounted () { - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - this.getTableData() } } </script> diff --git a/nezha-fronted/src/components/page/config/terminalLog.vue b/nezha-fronted/src/components/page/config/terminalLog.vue new file mode 100644 index 000000000..fd58c1c3d --- /dev/null +++ b/nezha-fronted/src/components/page/config/terminalLog.vue @@ -0,0 +1,292 @@ +<template> + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle" + :from="fromRoute.terminalLog"> + <template v-slot:default="slotProps"> + <el-table + id="terminal-log-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" + > + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> + </template> + <template slot-scope="scope" :column="item"> + <span v-if="item.prop === 'time'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> + <template v-else-if="item.prop === 'status'"> + <span>{{getStatusText(scope.row.status)}}</span> + </template> + <template v-else-if="item.prop === 'uuid'"> + <span>{{scope.row.uuid.substring(0, 8).toUpperCase()}}</span> + </template> + <template v-else-if="item.prop === 'remote'"> + <span>{{getRemoteText(scope.row)}}</span> + </template> + <template v-else-if="item.prop === 'duration'"> + <el-tooltip placement="right" effect="light" :disabled="!scope.row.status"> + <div slot="content"> + {{$t('config.terminallog.endTime')}}<br/> + {{scope.row.endTime}} + </div> + <span>{{getDuration(scope.row)}}</span> + </el-tooltip> + </template> + <template v-else-if="item.prop === 'authType'"> + <span v-if="scope.row.authType == 1">{{$t('config.terminallog.password')}}</span> + <span v-else-if="scope.row.authType == 2">{{$t('config.terminallog.key')}}</span> + </template> + <span v-else>{{scope.row[item.prop]}}</span> + </template> + </el-table-column> + <el-table-column + :resizable="false" + fixed="right" + :width="operationWidth"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> + <template v-if="scope.row.status == 0"> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('monitor', scope.row)" :title="$t('config.terminallog.monitor.monitor')"><i class="nz-icon nz-icon-JC"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['shutdown', scope.row]"><i class="nz-icon nz-icon-ZD"></i><span class="operation-dropdown-text">Kill</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + </template> + <template v-else> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('cmd', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['record', scope.row]"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('config.terminallog.record.record')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + </template> + </div> + </el-table-column> + </el-table> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> + </div> +</template> +<script> +import { terminalLog } from '@/components/common/js/constants' +import { calcDurationByStringTimeB } from '@/components/common/js/tools' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' + +export default { + name: 'terminalLog', + components: { + nzDataList + }, + mixins: [tableMixin], + data () { + return { + tableId: 'terminalLogTable', // 需要分页的table的id,用于记录每页数量 + + tableTitle: [ + { + label: this.$t('config.terminallog.id'), + prop: 'id', + show: true, + width: 80 + }, { + label: 'Session ID', + prop: 'uuid', + show: true + }, { + label: 'Username', + prop: 'username', + show: true + }, + { + label: this.$t('config.terminallog.source'), + prop: 'remoteAddr', + show: true + }, + { + label: this.$t('config.terminallog.remote'), + prop: 'remote', + show: true + }, + { + label: this.$t('config.terminallog.protocol'), + prop: 'protocol', + show: true + }, + { + label: this.$t('config.terminallog.startTime'), + prop: 'startTime', + show: true + }, + { + label: this.$t('config.terminallog.duration'), + prop: 'duration', + show: true + }, + { + label: 'AuthType', + prop: 'authType', + show: false + }, + { + label: this.$t('config.terminallog.status'), // killusername鼠标悬停形式 + prop: 'status', + show: true, + width: 100 + } + ], + searchMsg: { // 给搜索框子组件传递的信息 + zheze_none: true, + searchLabelList: [ + { + id: 11, + name: this.$t('config.terminallog.host'), + type: 'input', + label: 'host', + disabled: false + }, { + id: 12, + name: this.$t('config.terminallog.user'), + type: 'input', + label: 'username', + disabled: false + } + ] + }, + nowTime: '' + } + }, + computed: { + getStatusText () { + return function (status) { + return terminalLog.status[status] + } + }, + getRemoteText () { + return function (record) { + return `${record.loginUser}@${record.host}:${record.port}` + } + }, + getDuration () { + return function (record) { + if (record.endTime) { + return calcDurationByStringTimeB(record.startTime, record.endTime) + } + return calcDurationByStringTimeB(record.startTime, this.nowTime) + } + } + }, + methods: { + tableOperation ([command, row]) { + switch (command) { + case 'shutdown': { + this.shutdown(row) + break + } + default: + this.$refs.dataList.showBottomBox(command, row) + break + } + }, + getTableData () { + const params = { + ...this.searchLabel, + pageNo: this.pageObj.pageNo, + pageSize: this.pageObj.pageSize + } + this.$get('terminal/session', params).then(response => { + this.tools.loading = false + if (response.code === 200) { + this.tableData = response.data.list + this.nowTime = this.utcTimeToTimezoneStr(response.time) + this.pageObj.total = response.data.total + if (!this.scrollbarWrap) { + this.$nextTick(() => { + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper + this.toTopBtnHandler(this.scrollbarWrap) + }) + } + } + }) + }, + shutdown (record) { + this.$confirm(this.$t('tip.killTerm'), { + confirmButtonText: this.$t('tip.yes'), + cancelButtonText: this.$t('tip.no'), + type: 'warning' + }).then(() => { + this.$put('/terminal/kill', { uuid: record.uuid }).then(res => { + if (res.code === 200) { + this.$message.success(this.$t('config.terminallog.success')) + this.bottomBox.showSubList = false + this.getTableData() + } else { + this.$message.error(this.$t('config.terminallog.killErrorTip')) + } + }) + }) + }, + messageStyle (e) { + if (e.column.label == this.$t('config.terminallog.status')) { + if (e.row.status == '0') { + return 'success' + } else if (e.row.status == '1') { + return 'warning' + } else if (e.row.status == '2') { + return 'suspended' + } else if (e.row.status == '3') { + return 'danger' + } else if (e.row.status == '4') { + return 'danger' + } + } + return '' + } + } +} +</script> diff --git a/nezha-fronted/src/components/page/config/terminallog.vue b/nezha-fronted/src/components/page/config/terminallog.vue index 1d1cfc2d4..a04a8e238 100644 --- a/nezha-fronted/src/components/page/config/terminallog.vue +++ b/nezha-fronted/src/components/page/config/terminallog.vue @@ -1,169 +1,133 @@ -<style scoped> - .terminallog { - height: 100%; - } -</style> <template> - <div class="terminallog"> - <div :class="{'main-list-with-sub': bottomBox.showSubList}" class="main-list"> - <!-- 顶部工具栏 --> - <div class="main-modal"></div> - <div class="top-tools" v-show="bottomBox.mainResizeShow"> - <div :class="{'top-tool-main-right-to-left': bottomBox.showSubList}" class="top-tool-main-right"> - <div class="top-tool-search margin-r-5"> - <search-input :searchMsg="searchMsg" @search="search"></search-input> - </div> - </div> - <div class="pagination-top pagination-top-hide display-none"></div> - </div> - <!-- 自定义table列 --> - <transition name="el-zoom-in-top"> - <element-set - :custom-table-title.sync="tools.customTableTitle" - :original-table-title="tableTitle" - @close="tools.showCustomTableTitle = false" - ref="customTableTitle" - v-if="tools.showCustomTableTitle" - ></element-set> - </transition> - <el-table - :cell-class-name="messageStyle" - :data="tableData" - :height="$tableHeight.normal" - @sort-change="tableDataSort" - border - class="nz-table" - ref="terminalLogTable" - style="width: 100%;" - v-loading="tools.loading"> - <el-table-column - :key="`col-${index}`" - :label="item.label" - :prop="$tableSet.propTitle(item.prop,'temrminallog')" - :resizable="true" - :sort-orders="['ascending', 'descending']" - :sortable="$tableSet.sortableShow(item.prop,'temrminallog')" - v-for="(item, index) in tools.customTableTitle" - v-if="item.show" + <div style="height: 100%"> + <nz-data-list + ref="dataList" + :components="['searchInput', 'elementSet']" + :custom-table-title.sync="tools.customTableTitle" + :from="fromRoute.terminalLog" + :search-msg="searchMsg" + :table-id="tableId" + :table-title="tableTitle"> + <template v-slot:default="slotProps"> + <el-table + id="terminal-log-list-table" + ref="dataTable" + v-loading="tools.loading" + :data="tableData" + :height="mainTableHeight" + border + @header-dragend="dragend" + @sort-change="tableDataSort" + @selection-change="(selection)=>{batchDeleteObjs=selection}" > - <template :column="item" slot-scope="scope"> - <span v-if="item.prop == 'time'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> - <template v-else-if="item.prop == 'status'"> - <span>{{getStatusText(scope.row.status)}}</span> - </template> - <template v-else-if="item.prop == 'uuid'"> - <span>{{scope.row.uuid.substring(0, 8).toUpperCase()}}</span> + <el-table-column + :resizable="false" + align="center" + type="selection" + width="55"> + </el-table-column> + <el-table-column + v-for="(item, index) in tools.customTableTitle" + v-if="item.show" + :key="`col-${index}`" + :fixed="item.fixed" + :label="item.label" + :prop="item.prop" + :resizable="true" + :sort-orders="['ascending', 'descending']" + :width="`${item.width}`" + class="data-column" + > + <template slot="header"> + <span> + <span>{{item.label}}</span> + <div class="col-resize-area"></div> + </span> </template> - <template v-else-if="item.prop == 'remote'"> - <span>{{getRemoteText(scope.row)}}</span> - </template> - <template v-else-if="item.prop == 'duration'"> - <el-tooltip placement="right" effect="light" :disabled="!scope.row.status"> - <div slot="content"> - {{$t('config.terminallog.endTime')}}<br/> - {{scope.row.endTime}} - </div> - <span>{{getDuration(scope.row)}}</span> - </el-tooltip> + <template slot-scope="scope" :column="item"> + <span v-if="item.prop === 'time'">{{utcTimeToTimezoneStr(scope.row[item.prop])}}</span> + <template v-else-if="item.prop === 'status'"> + <span>{{getStatusText(scope.row.status)}}</span> + </template> + <template v-else-if="item.prop === 'uuid'"> + <span>{{scope.row.uuid.substring(0, 8).toUpperCase()}}</span> + </template> + <template v-else-if="item.prop === 'remote'"> + <span>{{getRemoteText(scope.row)}}</span> + </template> + <template v-else-if="item.prop === 'duration'"> + <el-tooltip :disabled="!scope.row.status" effect="light" placement="right"> + <div slot="content"> + {{$t('config.terminallog.endTime')}}<br/> + {{scope.row.endTime}} + </div> + <span>{{getDuration(scope.row)}}</span> + </el-tooltip> + </template> + <template v-else-if="item.prop === 'authType'"> + <span v-if="scope.row.authType == 1">{{$t('config.terminallog.password')}}</span> + <span v-else-if="scope.row.authType == 2">{{$t('config.terminallog.key')}}</span> + </template> + <span v-else>{{scope.row[item.prop]}}</span> </template> - <template v-else-if="item.prop == 'option'"> + </el-table-column> + <el-table-column + :resizable="false" + :width="operationWidth" + fixed="right"> + <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> + <div slot-scope="scope" class="table-operation-items"> <template v-if="scope.row.status == 0"> - <span :id="'terminalLog-shutdown-'+scope.row.id" @click="shutdown(scope.row)" class="content-right-option" title="Kill"><i class="nz-icon nz-icon-ZD"></i></span> - - <span :id="'terminalLog-monitor-'+scope.row.id" :title="$t('config.terminallog.monitor.monitor')" @click="monitor(scope.row)" class="content-right-option"><i class="nz-icon nz-icon-JC"></i></span> + <button :title="$t('config.terminallog.monitor.monitor')" class="table-operation-item" @click="$refs.dataList.showBottomBox('monitor', scope.row)"><i class="nz-icon nz-icon-JC"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['shutdown', scope.row]"><i class="nz-icon nz-icon-ZD"></i><span class="operation-dropdown-text">Kill</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> </template> <template v-else> - <span :id="'terminalLog-replay-'+scope.row.id" :title="$t('config.terminallog.record.record')" @click="showRecord(scope.row)" class="content-right-option"><i class="nz-icon nz-icon-replay2"></i></span> - - <span :id="'terminalLog-log-'+scope.row.id" :title="$t('config.terminallog.log')" @click="showHistoryCMD(scope.row)" class="content-right-option"><i class="nz-icon nz-icon-terminal-log"></i></span> + <button class="table-operation-item" @click="$refs.dataList.showBottomBox('cmd', scope.row)"><i class="nz-icon nz-icon-view1"></i></button> + <el-dropdown size="medium" trigger="hover" @command="tableOperation"> + <div class="table-operation-item table-operation-item--more"> + <span>…</span><i class="nz-icon nz-icon-arrow-down"></i> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item :command="['record', scope.row]"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('config.terminallog.record.record')}}</span></el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> </template> - - </template> - <template v-else-if="item.prop == 'authType'"> - <span v-if="scope.row.authType==1">{{$t('config.terminallog.password')}}</span> - <span v-else-if="scope.row.authType==2">{{$t('config.terminallog.key')}}</span> - </template> - <span v-else>{{scope.row[item.prop]}}</span> - </template> - </el-table-column> - <el-table-column width="28"> - <template slot="header"> - <span @mousedown.stop="!tools.showCustomTableTitle && (tools.showCustomTableTitle = true)" class="nz-table-gear"> - <i class="nz-icon nz-icon-gear"></i> - </span> - </template> - </el-table-column> - </el-table> - <button :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" @click="toTop(scrollbarWrap)" class="to-top" v-show="tools.showTopBtn"><i class="nz-icon nz-icon-top"></i></button> - <div class="pagination-bottom" v-show="!bottomBox.showSubList"> - <Pagination :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"></Pagination> - </div> - </div> - - <!-- 底部上滑框 --> - <transition name="el-zoom-in-bottom"> - <bottom-box :detail="bottomBox.terminalLog" :is-full-screen="bottomBox.isFullScreen" :obj="bottomBox.terminalLog" :sub-resize-show="bottomBox.subResizeShow" :target-tab.sync="bottomBox.targetTab" @closeSubList="closeSubList" @exitFullScreen="exitFullScreen" - @fullScreen="fullScreen" @listResize="listResize" from="terminal" v-if="bottomBox.showSubList" ></bottom-box> - </transition> + </div> + </el-table-column> + </el-table> + <!-- 回到table顶部的按钮 --> + <button v-show="tools.showTopBtn && slotProps.mainResizeShow" id="role-list-totop" :class="{'to-top-is-hover': tools.tableHover}" :style="{top: tools.toTopBtnTop}" class="to-top" @click="toTop(scrollbarWrap)"><i class="nz-icon nz-icon-top"></i></button> + </template> + <!-- 分页组件 --> + <template v-slot:pagination> + <Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination> + </template> + </nz-data-list> </div> </template> <script> -import bus from '../../../libs/bus' -import { terminalLog } from '../../common/js/constants' -import { calcDurationByStringTimeB } from '../../common/js/tools' +import { terminalLog } from '@/components/common/js/constants' +import { calcDurationByStringTimeB } from '@/components/common/js/tools' +import nzDataList from '@/components/common/table/nzDataList' +import tableMixin from '@/components/common/mixin/table' export default { - name: 'terminallog', + name: 'terminalLog', + components: { + nzDataList + }, + mixins: [tableMixin], data () { return { tableId: 'terminalLogTable', // 需要分页的table的id,用于记录每页数量 - /* 二级页面相关 */ - bottomBox: { - terminalLog: {}, - mainResizeShow: true, // dom高度改变时是否展示|隐藏 - subResizeShow: true, - isFullScreen: false, // 全屏状态 - showSubList: false, // 是否显示二级列表 - targetTab: '', // 显示二级列表中的哪个页签 - inTransform: false // 搜索框相关,搜索条件下拉框是否在transform里 - }, - - /* 工具参数 */ - tools: { - loading: false, // 是否显示table加载动画 - toTopBtnTop: this.$tableHeight.toTopBtnTop, // to-top按钮的top属性 - tableHover: false, // 控制滚动条和top按钮同时出现 - showTopBtn: false, // 显示To top按钮 - showCustomTableTitle: false, // 自定义列弹框是否显示 - customTableTitle: [] // 自定义列工具的数据 - }, - rightBox: { // 弹出框相关 - show: false, - isEdit: false, // false查看,true编辑 - title: '' - - }, - rightBoxResize: { // resize弹出框相关 - show: false, - isAdd: false, // false,true:resize - title: '' - }, - rightBoxDownload: { // 下载弹出框相关 - show: false, - isAdd: false, // false,true:resize - title: '' - }, - rightBoxUpload: { // 上传弹出框相关 - show: false, - isAdd: false, // false,true:resize - title: '' - }, - pageObj: { - pageNo: 1, - pageSize: this.$CONSTANTS.defaultPageSize, - total: 0 - }, tableTitle: [ { label: this.$t('config.terminallog.id'), @@ -214,16 +178,8 @@ export default { prop: 'status', show: true, width: 100 - }, - { - label: this.$t('config.account.option'), - prop: 'option', - show: true, - width: 120, - fixed: 'right' } ], - tableData: [], searchMsg: { // 给搜索框子组件传递的信息 zheze_none: true, searchLabelList: [ @@ -242,8 +198,6 @@ export default { } ] }, - searchLabel: {}, // 搜索参数 - scrollbarWrap: null, nowTime: '' } }, @@ -267,13 +221,18 @@ export default { } } }, - watch: { - 'bottomBox.showSubList': function (n) { - const vm = this - this.$bottomBoxWindow.showSubListWatch(vm, n) - } - }, methods: { + tableOperation ([command, row]) { + switch (command) { + case 'shutdown': { + this.shutdown(row) + break + } + default: + this.$refs.dataList.showBottomBox(command, row) + break + } + }, getTableData () { const params = { ...this.searchLabel, @@ -288,29 +247,13 @@ export default { this.pageObj.total = response.data.total if (!this.scrollbarWrap) { this.$nextTick(() => { - this.scrollbarWrap = this.$refs.terminalLogTable.bodyWrapper + this.scrollbarWrap = this.$refs.dataTable.bodyWrapper this.toTopBtnHandler(this.scrollbarWrap) }) } } }) }, - - showRecord (record) { - this.bottomBox.targetTab = 'record' - this.bottomBox.terminalLog = JSON.parse(JSON.stringify(record)) - this.bottomBox.showSubList = true - }, - showHistoryCMD (record) { - this.bottomBox.targetTab = 'cmd' - this.bottomBox.terminalLog = JSON.parse(JSON.stringify(record)) - this.bottomBox.showSubList = true - }, - monitor (record) { - this.bottomBox.targetTab = 'monitor' - this.bottomBox.terminalLog = JSON.parse(JSON.stringify(record)) - this.bottomBox.showSubList = true - }, shutdown (record) { this.$confirm(this.$t('tip.killTerm'), { confirmButtonText: this.$t('tip.yes'), @@ -328,21 +271,6 @@ export default { }) }) }, - // 全屏 - fullScreen () { - const vm = this - this.$bottomBoxWindow.fullScreen(vm) - }, - // 退出全屏 - exitFullScreen () { - const vm = this - this.$bottomBoxWindow.exitFullScreen(vm) - }, - // 鼠标拖动二级列表 - listResize (e) { - const vm = this - this.$bottomBoxWindow.listResize(vm, e) - }, messageStyle (e) { if (e.column.label == this.$t('config.terminallog.status')) { if (e.row.status == '0') { @@ -358,72 +286,7 @@ export default { } } return '' - }, - pageNo (val) { - this.pageObj.pageNo = val - this.getTableData() - }, - pageSize (val) { - this.pageObj.pageSize = val - localStorage.setItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId, val) - this.getTableData() - }, - search: function (searchObj) { - let orderBy = '' - if (this.searchLabel.orderBy) { - orderBy = this.searchLabel.orderBy - } - this.searchLabel = {} - this.pageObj.pageNo = 1 - for (const item in searchObj) { - if (searchObj[item]) { - this.$set(this.searchLabel, item, searchObj[item]) - } - } - if (orderBy) { - this.$set(this.searchLabel, 'orderBy', orderBy) - } - this.getTableData() - }, - closeSubList () { - this.bottomBox.showSubList = false - if (this.bottomBox.targetTab == 'monitor') { - this.getTableData() - } - }, - // 数据排序 - tableDataSort (item) { - let orderBy = '' - if (item.order === 'ascending') { - orderBy = item.prop - } - if (item.order === 'descending') { - orderBy = '-' + item.prop - } - this.$set(this.searchLabel, 'orderBy', orderBy) - this.getTableData() - } - }, - beforeDestroy () { - if (this.scrollbarWrap) { - this.scrollbarWrap.removeEventListener('scroll', bus.debounce) - }; - }, - created () { - // 是否存在分页缓存 - const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId) - if (pageSize != 'undefined' && pageSize != null) { - this.pageObj.pageSize = pageSize } - }, - mounted () { - // 初始化表头 - this.tools.customTableTitle = localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path) - ? JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.$route.path)) - : this.tableTitle - this.tableTitleReset(this.tableTitle, this.tools.customTableTitle) - - this.getTableData() } } </script> diff --git a/nezha-fronted/src/main.js b/nezha-fronted/src/main.js index 38f223a9f..f92a1c7b6 100644 --- a/nezha-fronted/src/main.js +++ b/nezha-fronted/src/main.js @@ -27,42 +27,14 @@ import Pagination from './components/common/pagination' // 引入全局分页组 import searchInput from './components/common/searchInput' // 搜索框组件 import elementSet from './components/common/elementSet' // 自定义表头组件 -import projectBox from './components/common/rightBox/projectBox' // project弹框组件 -import moduleBox from './components/common/rightBox/moduleBox' // module弹框组件 -import editEndpointBox from './components/common/rightBox/editEndpointBox' // endpoint弹框组件 -import addEndpointBox from './components/common/rightBox/addEndpointBox' // endpoint弹框组件 -import assetBox from './components/common/rightBox/assetBox' // 资产添加组件 -import batchEditAsset from './components/common/rightBox/batchEditAsset' // 资产批量修改组件 -import alertConfigBox from './components/common/rightBox/alertConfigBox' // 告警规则弹框组件 -import panelBox from './components/common/rightBox/panelBox' // 面板弹框组件 -import moduleListPop from './components/page/asset/moduleListPop' // 面板弹框组件 -import cabinetConfigBox from './components/common/popBox/cabinetConfig' // 面板弹框组件 -import modelBox from './components/common/rightBox/modelBox' // model弹框 -import bottomBox from './components/common/bottomBox/bottomBox' // 上滑框 -import loading from './components/common/loading' -import mibBox from './components/common/rightBox/mibBox' -import leftMenu from './components/common/leftMenu' -import pickTime from './components/common/pickTime' -import bus from './libs/bus' +import loading from '@/components/common/loading' +import pickTime from '@/components/common/pickTime' +import bus from '@/libs/bus' Vue.component('Pagination', Pagination) Vue.component('searchInput', searchInput) Vue.component('element-set', elementSet) -Vue.component('project-box', projectBox) -Vue.component('module-box', moduleBox) -Vue.component('edit-endpoint-box', editEndpointBox) -Vue.component('add-endpoint-box', addEndpointBox) -Vue.component('asset-box', assetBox) -Vue.component('batch-edit-asset', batchEditAsset) -Vue.component('alert-config-box', alertConfigBox) -Vue.component('panel-box', panelBox) -Vue.component('module-list-pop', moduleListPop) -Vue.component('cabinet-config-box', cabinetConfigBox) -Vue.component('model-box', modelBox) Vue.component('loading', loading) -Vue.component('bottom-box', bottomBox) -Vue.component('mib-box', mibBox) -Vue.component('left-menu', leftMenu) Vue.component('pick-time', pickTime) Vue.prototype.$axios = axios diff --git a/nezha-fronted/src/router/index.js b/nezha-fronted/src/router/index.js index cafbe7a00..1a41d3b35 100644 --- a/nezha-fronted/src/router/index.js +++ b/nezha-fronted/src/router/index.js @@ -79,11 +79,11 @@ export default new Router({ }, { path: '/terminalLog', - component: resolve => require(['../components/page/config/terminallog.vue'], resolve) + component: resolve => require(['../components/page/config/terminalLog.vue'], resolve) }, { path: '/operationLog', - component: resolve => require(['../components/page/config/operationlog.vue'], resolve) + component: resolve => require(['../components/page/config/operationLog.vue'], resolve) }, { path: '/about', |
