Merge remote-tracking branch 'origin/dev-3.1' into dev-3.1.1_theme

# Conflicts:
#	nezha-fronted/src/components/common/alert/alertLabel.vue
#	nezha-fronted/src/components/common/detailView/detailViewTopSearch.vue
#	nezha-fronted/src/components/common/i18n.js
#	nezha-fronted/src/components/common/labelFilter/clickSearch.vue
#	nezha-fronted/src/components/common/login.vue
#	nezha-fronted/src/components/common/popBox/topToolMoreOptions.vue
This commit is contained in:
chenjinsong
2021-11-04 14:49:40 +08:00
53 changed files with 1140 additions and 238 deletions

View File

@@ -99,6 +99,7 @@
:fromPath="'/alertList'"
style="height: calc(100% - 50px)"
:showOption="false"
:chart-alert-list="true"
></alertMessageTable>
<Pagination :pageObj="screenPageObj" @pageNo='screenPageNo' @pageSize='screenPageSize' ref="Pagination" ></Pagination>
<loading :ref="'localLoadingScreen'+chartIndex"></loading>
@@ -459,6 +460,9 @@ export default {
})
},
messageDetail (row) {
if (row.alertRule.type == 3) {
return
}
this.$get('/alert/rule/' + row.alertRule.id).then(res => {
this.currentMsg = { ...row, alertRule: { ...res.data } }
this.graphShow = true

View File

@@ -257,12 +257,14 @@ export default {
type: {},
// labelLoading:{},
that: {},
detailList: Boolean
detailList: Boolean,
alertTableDialog: Boolean
},
data () {
return {
alertLabelData: null,
loading: true
loading: true,
heightList: 0
}
},
components: {
@@ -292,30 +294,29 @@ export default {
},
computed: {
calcPosition () {
const self = this
return function (position) {
const clientHeight = (document.body.clientHeight < document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight
const dialog = document.querySelector('#dialog-alert-massage .el-dialog')
const dialogHeight = dialog.getBoundingClientRect()
const leftOffSetView = this.detailList ? -80 : 10
const topOffSetView = this.detailList ? 0 : 0
const leftOffSet = this.detailList ? -80 : 10
const topOffSet = this.detailList ? 70 : 0
const elHeight = self.type === 'asset' ? 318 : (self.type === 'project' ? 70 : 70)
if (position.top + elHeight > clientHeight) {
const topOffSet = this.detailList ? 60 : 22
if (position.top + this.heightList > clientHeight) {
return {
left: `${position.left + position.width + leftOffSet}px`,
top: `${position.top - elHeight + topOffSet}px`
top: `${position.top - this.heightList + topOffSet}px`
}
} else if (dialogHeight) {
return {
left: `${position.left + position.width + 10 - dialogHeight.x}px`,
top: `${position.top - dialogHeight.y}px`
} else if (this.alertTableDialog) {
const dialog = document.querySelector('#dialog-alert-massage .el-dialog')
const dialogHeight = dialog.getBoundingClientRect()
if (dialogHeight) {
return {
left: `${position.left + position.width + 10 - dialogHeight.x}px`,
top: `${position.top - dialogHeight.y}px`
}
}
} else {
return {
left: `${position.left + position.width + leftOffSetView}px`,
top: `${position.top + topOffSetView}px`
top: `${position.top}px`
}
}
}
@@ -397,6 +398,12 @@ export default {
return this.$t('asset.notInStock')
}
}
},
mounted () {
this.heightList = this.$refs.alertLabels.getBoundingClientRect().height
},
beforeDestroy () {
}
}

View File

@@ -11,7 +11,16 @@
</div>
<div class="alert-rule-box">
<div class="alert-rule-title">{{$t('alert.type')}}</div>
<div class="alert-rule-value">{{alertRuleData.type ? alertRuleData.type : '--'}}</div>
<div class="alert-rule-value">
<span v-if="alertRuleData.type === 1">
{{$t('project.metrics.metrics')}}
</span>
<span v-else-if="alertRuleData.type === 2">
{{$t('overall.logs')}}
</span>
<span v-else-if="alertRuleData.type === 3">SNMP trap</span>
<span v-else>--</span>
</div>
</div>
<div class="alert-rule-box">
<div class="alert-rule-title">{{$t('alert.severity')}}</div>

View File

@@ -50,11 +50,12 @@
<panel-tab-new v-if="from === fromRoute.endpoint && targetTab === 'panelTab'" v-show="subResizeShow" :from="from" :obj="obj" :paramsType="'endpoint'" :tabs="endpointTabs" :targetTab.sync="targetTab" @changeTab="changeTab" @getTableData="getTableData"></panel-tab-new>
<endpointQuery v-if="from === fromRoute.endpoint && targetTab === 'endpointQuery'" v-show="subResizeShow" :from="from" :obj="obj" :tabs="endpointTabs" :targetTab.sync="targetTab" @changeTab="changeTab"></endpointQuery>
<log-bottom-tab v-if="from === fromRoute.endpoint && targetTab === 'log' && hasLogConfig" v-show="subResizeShow" :from="from" :obj="obj" :tabs="endpointTabs" :targetTab.sync="targetTab" @changeTab="changeTab"></log-bottom-tab>
<alertMessageTabNew v-if="from === fromRoute.endpoint && targetTab === 'endpointAlertMessage'" v-show="subResizeShow" :from="from" :obj="obj" :tabs="endpointTabs" :targetTab="targetTab" @changeTab="changeTab"></alertMessageTabNew>
<alertMessageTabNew v-if="from === fromRoute.endpoint && targetTab === 'endpointAlertMessage'" v-show="subResizeShow" :from="from" :obj="obj" :tabs="endpointTabs" :targetTab.sync="targetTab" @changeTab="changeTab"></alertMessageTabNew>
<!--chartTemp的Tab-->
<panel-tab-new @getTableData="getTableData" :paramsType="'template'" v-if="from === fromRoute.chartTemp && targetTab === 'panel'" v-show="subResizeShow" :from="from" :obj="obj" :tabs="tabs.chartTemp.chartTempTabTitle" :targetTab.sync="targetTab" @changeTab="changeTab"></panel-tab-new>
<!--alertRule Tab-->
<alertMessageTabNew v-if="from === fromRoute.alertRule && targetTab === 'alertRuleAlertMessage'" v-show="subResizeShow" :from="from" :obj="obj" :tabs="tabs.alertRule.alertRule" @changeTab="changeTab" :targetTab="targetTab"></alertMessageTabNew>
<alertMessageTabNew v-if="from === fromRoute.alertRule && targetTab === 'alertRuleAlertMessage'" v-show="subResizeShow" :from="from" :obj="obj" :tabs="tabs.alertRule.alertRule" @changeTab="changeTab" :targetTab.sync="targetTab"></alertMessageTabNew>
<alertRuleEvalLog v-if="from === fromRoute.alertRule && targetTab === 'evalLog'" v-show="subResizeShow" :from="from" :obj="obj" :tabs="tabs.alertRule.alertRule" @changeTab="changeTab" :targetTab.sync="targetTab"></alertRuleEvalLog>
<!--model 下滑-->
<asset-tab v-if="(from === fromRoute.model) && targetTab === 'asset'" :tabs="tabs.model" ref="assetTab" :from="from" :obj="obj" @changeTab="changeTab" @exit="closeSubList"></asset-tab>
</div>
@@ -66,6 +67,7 @@
import cabinetTab from './tabs/cabinetTab'
import alertMessageTab from './tabs/alertMessageTab'
import alertMessageTabNew from './tabs/alertMessageTabNew'
import alertRuleEvalLog from './tabs/alertRuleEvalLog'
import assetSubTab from './tabs/assetSubTab'
import endpointQuery from './tabs/endpointQuery'
import endpointTab from './tabs/endpointTab'
@@ -97,7 +99,8 @@ export default {
endpointQuery,
panelTabNew,
assetTab,
assetSubTab
assetSubTab,
alertRuleEvalLog
},
props: {
isFullScreen: Boolean, // 是否全屏
@@ -203,7 +206,7 @@ export default {
{ prop: 'panelTab', name: this.$t('overall.detail') },
{ prop: 'endpointAlertMessage', name: this.$t('overall.alert') },
{ prop: 'endpointQuery', name: 'Metrics' },
{ prop: 'log', name: 'Log' },
{ prop: 'log', name: 'Log' }
]
},
chartTemp: {
@@ -213,7 +216,8 @@ export default {
},
alertRule: {
alertRule: [
{ prop: 'alertRuleAlertMessage', name: this.$t('overall.alert') }
{ prop: 'alertRuleAlertMessage', name: this.$t('overall.alert') },
{ prop: 'evalLog', name: this.$t('overall.alertRuleEvalLog') }
]
},
model: [

View File

@@ -4,7 +4,7 @@
<div class="top-tool-left">
<div class="sub-list-title" v-if="showTitle">{{bottomHeaderTitle}}<slot name="title"></slot></div>
<div class="sub-list-tabs">
<div v-for="tab in tabs" :key="tab.prop" :class="{'sub-list-tab--active': tab.active || tab.prop=== targetTab}" class="sub-list-tab" @click="changeTab(tab.prop)">{{tab.name}}</div>
<div v-for="tab in tabs" :key="tab.prop" :class="{'sub-list-tab--active': tab.active || tab.prop == targetTab }" :title='tab.prop + targetTab' class="sub-list-tab" @click="changeTab(tab.prop)">{{tab.name}}</div>
</div>
</div>
<div class="top-tool-right" v-if="!customTool">

View File

@@ -0,0 +1,117 @@
<template>
<nz-bottom-data-list
:showTitle='showTitle'
:api="url"
:custom-table-title.sync="tools.customTableTitle"
:layout="['elementSet']"
:search-msg="searchMsg"
:tabs="tabs"
:targetTab="targetTab"
:showPagination="false"
@search="search"
@changeTab="changeTab"
>
<template v-slot:title><span :title="obj.name">{{obj.name}}</span></template>
<template v-slot>
<alertRuleEvalLogTable
ref="dataTable"
v-loading="tools.loading"
:loading="tools.loading"
:api="url"
:custom-table-title="tools.customTableTitle"
:height="subTableHeight"
:now-time="nowTime"
:table-data="tableData"
:terminaLogTab="true"
@del="del"
@edit="edit"
@orderBy="tableDataSort"
@reload="getTableData"
@selectionChange="selectionChange"></alertRuleEvalLogTable>
</template>
<template v-slot:pagination>
<Pagination ref="Pagination" :pageObj="pageObj" :tableId="tableId" @pageNo='pageNo' @pageSize='pageSize'></Pagination>
</template>
</nz-bottom-data-list>
</template>
<script>
import dataListMixin from '@/components/common/mixin/dataList'
import subDataListMixin from '@/components/common/mixin/subDataList'
import nzBottomDataList from '@/components/common/bottomBox/nzBottomDataList'
import alertRuleEvalLogTable from '@/components/common/table/alert/alertRuleEvalLogTable'
import detailViewRightMixin from '@/components/common/mixin/detailViewRightMixin'
export default {
name: 'alertRuleEvalLog',
mixins: [dataListMixin, subDataListMixin, detailViewRightMixin],
components: {
nzBottomDataList,
alertRuleEvalLogTable
},
props: {
obj: Object,
showTitle: {
type: Boolean,
default: true
}
},
watch: {
obj (n) {
this.searchLabel = { id: n.id }
this.getTableData()
}
},
data () {
return {
url: 'alert/rule/1/evalLog',
tableId: 'alertRuleEvalLogTable', // 需要分页的table的id用于记录每页数量
searchMsg: { // 给搜索框子组件传递的信息
zheze_none: true,
searchLabelList: [
{
id: 11,
name: this.$t('config.terminallog.loginHost'),
type: 'input',
label: 'host',
disabled: false
}
]
},
nowTime: '',
searchLabel: { id: this.obj.id }
}
},
methods: {
getTableData (params) {
if (params && Object.keys(params).length > 0) {
for (const key in params) {
this.$set(this.searchLabel, key, params[key])
}
}
if (this.orderBy) {
this.$set(this.searchLabel, 'orderBy', this.orderBy)
}
this.$set(this.searchLabel, 'pageNo', this.pageObj.pageNo)
this.$set(this.searchLabel, 'pageSize', -1)
this.tools.loading = true
if (this.obj) {
this.$set(this.searchLabel, 'id', this.obj.id)
}
this.$get('alert/rule/' + this.obj.id + '/evalLog').then(response => {
this.tools.loading = false
this.nowTime = this.utcTimeToTimezoneStr(response.time)
if (response.code === 200) {
this.tableData = response.data
if (!this.scrollbarWrap) {
this.$nextTick(() => {
this.scrollbarWrap = this.$refs.dataTable.$refs.dataTable.bodyWrapper
this.toTopBtnHandler(this.scrollbarWrap)
})
}
}
})
}
}
}
</script>

View File

@@ -34,7 +34,8 @@
<button id="asset-create-asset" v-has="'dc_add'" class="top-tool-btn margin-r-10 margin-l-10" @click.stop="add">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="model"
:params="searchLabel"

View File

@@ -21,7 +21,8 @@
<button id="asset-create-asset" v-has="'panel_chart_add'" :title="$t('overall.createChart')" class="top-tool-btn margin-r-10" @click.stop="addChart">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
id="asset-list"
:params="filter"
:params-type="paramsType"
@@ -53,7 +54,8 @@
<button id="endpoint-create-chart" v-has="'panel_chart_add'" :title="$t('overall.createChart')" class="top-tool-btn margin-r-10" @click.stop="addChart">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
id="asset-list"
:link="obj"
:params="filter"
@@ -210,7 +212,8 @@ export default {
// deleteObj: {}, // 删除对象
// ---图表相关参数--end
scrollbarWrap: null,
panelDataList: []
panelDataList: [],
batchDeleteObjs: []
}
},
components: {

View File

@@ -25,8 +25,9 @@
<el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top detail-top-search-dropdown">
<div style="text-align: center;"><el-input style="width: calc(100% - 40px)" size="small" v-model="searchStr" @input="(val)=>{searchStrChange(val,key)}" suffix-icon="el-icon-search"/></div>
<el-checkbox-group v-model="selectValue[item.key]">
<el-dropdown-item v-for="(item3,index3) in item.children" :key="index3" :title="item3.name">
<el-dropdown-item v-for="(item3,index3) in item.children" :key="index3" :title="item3.name" class="nz-dropdown-menu__item-hover">
<el-checkbox :label="item3.id">{{item3.name}}</el-checkbox>
<span class="right-box-select-num">{{item3.num || 0}}</span>
</el-dropdown-item>
</el-checkbox-group>
</el-dropdown-menu>
@@ -56,9 +57,12 @@
<el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top detail-top-search-dropdown">
<div style="text-align: center;"><el-input style="width: calc(100% - 40px)" size="small" v-model="searchStr" @input="(val)=>{searchStrChange(val,key)}" suffix-icon="el-icon-search"/></div>
<el-checkbox-group v-model="selectValue[item.key]">
<el-dropdown-item v-for="(item3,index3) in item.children" :key="index3" >
<el-dropdown-item v-for="(item3,index3) in item.children" :key="index3" class="nz-dropdown-menu__item">
<!-- <span :title="item3.name" class="children-title-name"> {{item3.name}}</span>-->
<el-checkbox :label="item3.id+'-'+item4.id" :key="index4" v-for="(item4,index4) in item3.children" :title="item3.name+'/'+item4.name">{{item3.name+'/'+item4.name}}</el-checkbox>
<div v-for="(item4,index4) in item3.children" :key="index4" class="el-dropdown-menu__item nz-dropdown-menu__item-hover">
<el-checkbox :label="item3.id+'-'+item4.id" :title="item3.name+'/'+item4.name">{{item3.name+'/'+item4.name}}</el-checkbox>
<span class="right-box-select-num">{{item4.num || 0}}</span>
</div>
</el-dropdown-item>
</el-checkbox-group>
</el-dropdown-menu>
@@ -88,9 +92,12 @@
<el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top detail-top-search-dropdown">
<div style="text-align: center;"><el-input style="width: calc(100% - 40px)" size="small" v-model="searchStr" @input="(val)=>{searchStrChange(val,key)}" suffix-icon="el-icon-search"/></div>
<el-checkbox-group v-model="selectValue[item.key]">
<el-dropdown-item v-for="(item3,index3) in item.children" :key="index3" >
<el-dropdown-item v-for="(item3,index3) in item.children" :key="index3" class="nz-dropdown-menu__item">
<span :title="item3.name" class="children-title-name"> {{item3.name}}</span>
<el-checkbox :label="item3.id+'-'+item4.id" :key="index4" v-for="(item4,index4) in item3.children" :title="item4.name" :a="item3.id+'-'+item4.id">{{item4.name}}</el-checkbox>
<div :key="index4" v-for="(item4,index4) in item3.children" class="el-dropdown-menu__item nz-dropdown-menu__item-hover">
<el-checkbox :label="item3.id+'-'+item4.id" :title="item4.name" :a="item3.id+'-'+item4.id">{{item4.name}}</el-checkbox>
<span class="right-box-select-num">{{item4.num || 0}}</span>
</div>
</el-dropdown-item>
</el-checkbox-group>
</el-dropdown-menu>

View File

@@ -1,8 +1,6 @@
import Vue from 'vue'
import locale from 'element-ui/lib/locale'
import VueI18n from 'vue-i18n'
import { get } from '@/http'
// import messages from './language'
Vue.use(VueI18n)
// 从localStorage获取语言选择。
const i18n = new VueI18n({
@@ -16,15 +14,6 @@ export function loadI18n (i18nData) {
Object.keys(i18nData).forEach(lang => {
i18n.setLocaleMessage(lang, i18nData[lang])
})
} else {
get('/sys/i18n/lang').then(response => {
if (response.code === 200) {
i18nData = response.data
Object.keys(i18nData).forEach(lang => {
i18n.setLocaleMessage(lang, i18nData[lang])
})
}
})
}
}
export default i18n

View File

@@ -294,6 +294,15 @@ export function stringTimeParseToUnix (stringTime) {
time = time + localOffset - offset * 60 * 60 * 1000
return parseInt(time / 1000)
}
export function stringTimeParseToUnixMs (stringTime) {
let time = new Date(stringTime).getTime()
let offset = localStorage.getItem('nz-sys-timezone')
offset = moment.tz(offset).format('Z')
offset = Number.parseInt(offset)
const localOffset = new Date().getTimezoneOffset() * 60 * 1000 * -1 // 默认 一分钟显示时区偏移的结果
time = time + localOffset - offset * 60 * 60 * 1000
return parseInt(time)
}
export function getTime (size, unit) { // 计算时间
const now = new Date(bus.computeTimezone(new Date().getTime()))
if (unit) {
@@ -361,6 +370,28 @@ export function calcDurationByStringTimeB (startTime, endTime) {
return result
}
export function calcDurationByStringTimeMs (startTime, endTime) {
let durationSecond = stringTimeParseToUnixMs(endTime) - stringTimeParseToUnixMs(startTime)
let result = ''
if (durationSecond < 1000) {
result = `${durationSecond % 1000}ms`
return result
} else {
durationSecond = durationSecond / 1000
}
result = `${durationSecond % 60}s`
if (durationSecond >= 60 * 60 * 24) {
result = `${(Math.floor(durationSecond / 3600)) % 24}h`
result = `${Math.floor(durationSecond / (60 * 60 * 24))}d ${result}`
} else if (durationSecond >= 60 * 60) {
result = `${(Math.floor(durationSecond / 60)) % 60}m`
result = `${Math.floor(durationSecond / (60 * 60))}h ${result}`
} else if (durationSecond >= 60) {
result = `${(Math.floor(durationSecond / 60)) % 60}m ${result}`
}
return result
}
export function unixTimeParseToString (unixTime, fmt = 'yyyy-MM-dd hh:mm:ss') {
const date = new Date(unixTime * 1000)
const o = {

View File

@@ -76,7 +76,7 @@ export function nzNumber (rule, value, callback) {
}
export function noSpecialChar (rule, value, callback) {
const charReg = /^[\u4e00-\u9fa5a-z0-9A-Z-_.]+$/
const charReg = /[\u0000-\uFFFF]/
setTimeout(() => {
if (charReg.test(value)) {
callback()
@@ -170,7 +170,7 @@ export function checkExprTempAge (rule, value, callback) {
}, 100)
}
export function arrLength (rule, value, callback) { // 校验经纬度
export function arrLength (rule, value, callback) { // 校验数组
if (value.length > 0) {
callback()
} else {

View File

@@ -6,7 +6,7 @@
<template>
<el-checkbox-group v-if="data.type === 'checkBox'" ref="searchContent" v-model="selectValue[data.key]" @change="selectValue.change === 0 && selectValue.change++">
<template v-for="(item, j) in data.children">
<el-checkbox v-show="j < data.index || data.showMore" :key="j" :label="item.value" :title="item.key || item.name || item.label">{{item.key || item.name || item.label}}</el-checkbox>
<el-checkbox v-show="j < data.index || data.showMore" :key="j" :label="item.value" :title="item.key || item.name || item.label">{{item.key || item.name || item.label}} <span class="search-content-num">({{item.num || 0}})</span></el-checkbox>
</template>
</el-checkbox-group>
</template>
@@ -306,7 +306,7 @@ export default {
this.$set(c, 'labelWidth', labelWidth) // label区域宽
this.$set(c, 'inputWidth', this.widthConstant.dropdownCheckBox.inputOriginalWidth) // 内容区域宽
} else if (this.titleSearchListCopy[type].type === 'checkBox') {
const width = this.computeDistance(c.name) + this.widthConstant.checkBox.tagBlankTotal + this.widthConstant.checkBox.boxMargin
const width = this.computeDistance(c.name + ' (' + c.num + ')') + this.widthConstant.checkBox.tagBlankTotal + this.widthConstant.checkBox.boxMargin
this.$set(c, 'width', width) // 总宽
}
})

View File

@@ -17,7 +17,12 @@
@blur="$emit('blur', item, false, $event)"
@change="change"
@focus="$emit('focus', item, true, $event)"
></el-cascader>
>
<template slot-scope="{ node, data }">
<span>{{ data.name }}</span>
<span class="search-content-num">({{data.num || 0 }})</span>
</template>
</el-cascader>
</div>
</template>

View File

@@ -36,6 +36,7 @@ const cn = {
project: '系统',
monitor: '监控',
alert: '告警',
alertRuleEvalLog: 'Eval log',
asset: '资产',
config: '设置',
administration: '系统管理',
@@ -172,7 +173,12 @@ const cn = {
clearAllSelect: '清除选择的内容',
disabled: '已禁用',
enabled: '启用',
close: '关闭'
close: '关闭',
records: '导出形式',
fileFormat: '文件格式',
allData: '全部数据',
selectRecords: '选中的数据',
current: '当前页'
},
setup: {
step0: '欢迎',
@@ -1260,6 +1266,7 @@ const cn = {
alertMessage: '告警信息',
rule: '告警规则',
alertRule: '告警规则',
alertRuleMessage: 'Message',
alertList: '告警信息',
alertConfig: '告警规则',
alertName: '告警名称',
@@ -1355,7 +1362,7 @@ const cn = {
},
P1Rule: 'P1: 万分紧急,可导致业务瘫痪的告警',
P2Rule: 'P2: 重要,需要紧急关注的警报,但还没有影响业务',
P3Rule: 'P3: 轻微警报,需要处理,但不紧急'
P3Rule: 'P3: 轻微警报,需要处理,但不紧急',
},
project: {
chart: {

View File

@@ -35,6 +35,7 @@ const en = {
project: 'Project', // '系统'
monitor: 'Monitor', // 监控
alert: 'Alert', // "告警"
alertRuleEvalLog: 'Eval log',
asset: 'Asset', // '资产'
config: 'Setting', // '设置'
administration: 'Administration',
@@ -177,7 +178,12 @@ const en = {
clearAllSelect: 'Clear the selection',
disabled: 'Disabled',
enabled: 'Enabled',
close: 'Close'
close: 'Close',
records: 'Records',
fileFormat: 'File format',
allData: 'All data',
selectRecords: 'Select records',
current: 'Current page'
},
pageSize: '/page',
setup: {
@@ -1264,6 +1270,7 @@ const en = {
rule: 'Rule', // '规则'
alertMessage: 'Alert message', // "告警信息"
alertRule: 'Alert rule', // "告警规则"
alertRuleMessage: 'Message',
alertName: 'Name', // "告警名称"
method: 'Method', // "告警名称"
severity: 'Priority', // "等级"

View File

@@ -7,12 +7,12 @@
<div class="login-label"></div>
<div class="login-input" v-if="!verifyShow">
<i class="nz-icon nz-icon-user"></i>
<input id="usernameInput" v-model="loginData.username" name="userName" autocomplete="on" :placeholder="$t('login.username')" @keydown.enter="login"></input>
<input id="usernameInput" v-model="loginData.username" autocomplete="on" name="userName" placeholder="Username" @keydown.enter="login"></input>
</div>
<div class="login-label"></div>
<div class="login-input" v-if="!verifyShow">
<i class="nz-icon nz-icon-password"></i>
<input v-model="loginData.pin" type="password" name="password" autocomplete="on" :placeholder="$t('login.pin')" @keydown.enter="login"></input>
<input v-model="loginData.pin" autocomplete="on" name="password" placeholder="Password" type="password" @keydown.enter="login"></input>
</div>
<div class="login-label" v-if="verifyShow">{{$t('login.verifyTitle')}}</div>
<div class="login-input" v-if="verifyShow">
@@ -23,7 +23,7 @@
{{$t('login.verifyContent')}}
</div>
<div class="login-foot">
<button v-if="!verifyShow" id="login" v-loading="loading" :class="{'nz-btn-disabled': !license.valid}" class="login-btn" @click="login">{{$t("login.login")}}</button>
<button v-if="!verifyShow" id="login" v-loading="loading" :class="{'nz-btn-disabled': !license.valid}" class="login-btn" @click="login">Login</button>
<button v-if="verifyShow" id="verify" v-loading="loading" :class="{'nz-btn-disabled': !license.valid}" class="login-btn" @click="verify">{{$t("login.verify")}}</button>
</div>
<div class="login-license">
@@ -151,7 +151,6 @@ export default {
if (this.loading || !this.license.valid) {
return
}
// if (this.license.valid && this.validateLogin() && (this.$route.path == '/' || this.$route.path == '/login')) {
if (this.validateLogin() && (this.$route.path == '/' || this.$route.path == '/login')) {
this.loading = true
this.$post('/sys/login', this.loginData).then(res => {
@@ -160,27 +159,13 @@ export default {
this.authToken = res.data.authToken
this.lang = res.data.user.lang
this.$i18n.locale = this.lang
// 获取国际化内容
const getI18nData = new Promise(resolve => get('/sys/i18n/lang').then(response => {
if (response.code === 200) {
const i18nData = response.data
resolve(i18nData)
} else {
resolve()
}
}))
// 获取可选语言
const getLangList = new Promise(resolve => get('/sys/dict/all?type=lang').then(response => {
get('/sys/dict/all?type=lang').then(response => {
if (response.code === 200) {
const langList = response.data.map(lang => ({ name: lang.name, value: lang.value }))
this.$store.commit('setLangList', langList)
localStorage.setItem('nz-language-list', JSON.stringify(langList))
}
resolve()
}))
Promise.all([getI18nData, getLangList]).then(response => {
response[0] && loadI18n(response[0])
this.$store.commit('i18nReady', true)
})
sessionStorage.setItem('nz-token', res.data.authToken)
if (res.data.authFlag === 1) {

View File

@@ -43,15 +43,29 @@
</div>
</div>
<div v-if="importBox.type == 2">
<div class="upload-body">
<button :id="id+'-xlsx-export-current'" class="el-button el-button--default el-button--small" @click="exportCur">
<span>{{$t('overall.exportCur')}}</span>
</button>
<button :id="id+'-xlsx-export-all'" class="el-button el-button--default el-button--small" @click="exportAll">
<span>{{$t('overall.exportAll')}}</span>
</button>
<div class="upload-body" style="height: 200px">
<div class="export-box">
<span class="export-title">Records</span>
<el-radio-group v-model="importBox.record" size="small">
<el-radio-button :label="item.value" v-for="(item,index) in recordArr" :key="index" :disabled="item.value==='records'&&!deleteObjs.length">{{item.name}}</el-radio-button>
</el-radio-group>
</div>
<div class="export-box">
<span class="export-title">File format</span>
<el-radio-group v-model="importBox.format" size="small">
<el-radio-button :label="item.value" v-for="(item,index) in formatArr" :key="index" :disabled="item.value!==1">{{item.name}}</el-radio-button>
</el-radio-group>
</div>
</div>
<div slot="footer" class="footer">
<div class="el-message-box__btns">
<button :id="id+'-xlsx-import-export'" class="nz-btn nz-btn-size-normal-new nz-btn-style-normal-new" @click="exportData">
<span style="text-transform:Capitalize">{{$t('config.operationlog.operations.export')}}</span>
</button>
<button :id="id+'-xlsx-import-close'" class="nz-btn el-button el-button--default el-button--small" @click="closeDialog">
<span>{{$t('overall.close')}}</span>
</button>
</div>
</div>
</div>
<div v-if="importBox.type==3">
@@ -138,17 +152,29 @@ export default {
paramsType: {
type: String,
default: ''
}
},
deleteObjs: Array
},
data () {
return {
importBox: { show: false, title: this.$t('overall.importExcel'), type: 1 },
importBox: { show: false, title: this.$t('overall.importExcel'), type: 1, record: 'all', format: 1 },
importFile: null,
importFileList: [],
importResult: null,
exportShow: false,
panelLock: true,
language: localStorage.getItem('nz-language')
language: localStorage.getItem('nz-language'),
recordArr: [
{ name: this.$t('overall.allData'), value: 'all' },
{ name: this.$t('overall.selectRecords'), value: 'records' },
{ name: this.$t('overall.current'), value: 'current' }
],
formatArr: [
{ name: 'XLSX', value: 1 },
{ name: 'CSV', value: 2 },
{ name: 'JSON', value: 3 }
]
}
},
mounted () {
@@ -244,6 +270,8 @@ export default {
this.importResult = null
this.importFileList = []
this.importFile = null
this.importBox.value = 1
this.importBox.record = 'all'
})
},
downloadTemplate () {
@@ -309,6 +337,7 @@ export default {
delete params.searchName
}
params.language = localStorage.getItem('nz-language') || 'en'
params.format = this.importBox.format
this.exportExcel(this.exportUrl, params, this.exportFileName + '-' + this.getTimeString() + '.xlsx')
this.closeDialog()
},
@@ -341,10 +370,53 @@ export default {
// delete params.moduleId
// }
params.language = localStorage.getItem('nz-language') || 'en'
params.format = this.importBox.format
this.exportExcel(this.exportUrl, params, this.exportFileName + '-' + this.getTimeString() + '.xlsx')
this.closeDialog()
},
exportRecords() {
const params = JSON.parse(JSON.stringify(this.params))
if (this.params2) {
Object.keys(this.params2).forEach(key => {
if (params[key]) {
if (params[key].prototype.toString.call(val) === '[object Object]') {
Object.assign(params[key], this.params2[key])
} else if (params[key].prototype.toString.call(val) === '[object Array]') {
params[key].concat(this.params2[key])
}
} else {
params[key] = this.params2[key]
}
})
}
params.pageSize = -1
if (this.exportUrl.indexOf('panel') > -1) {
delete params.start_time
delete params.end_time
delete params.id
delete params.searchName
}
if (this.importUrl.indexOf('panel') > -1) {
delete params.panelId
}
// if (this.importUrl.indexOf('endpoint') > -1){
// delete params.moduleId
// }
params.language = localStorage.getItem('nz-language') || 'en'
params.format = this.importBox.format
params.ids = this.deleteObjs.map(item => item.id).join(',')
this.exportExcel(this.exportUrl, params, this.exportFileName + '-' + this.getTimeString() + '.xlsx')
this.closeDialog()
},
exportData () {
if (this.importBox.record === 'all') {
this.exportAll()
} else if (this.importBox.record === 'current') {
this.exportCur()
} else if (this.importBox.record === 'records') {
this.exportRecords()
}
},
exportExcel (url, params, fileName) {
if (this.paramsType) {
params.type = this.paramsType
@@ -395,7 +467,7 @@ export default {
this.importBox.width = '600px'
} else if (type == 2) { // export
this.importBox.title = this.$t('overall.exportExcel')
this.importBox.width = '300px'
this.importBox.width = '580px'
}
},
getTimeString () {

View File

@@ -6,9 +6,9 @@
<span v-cancel="{obj: editRole, func: esc}"><i class="nz-icon nz-icon-close"></i></span>
</div>
</div>
<div class="right-box__container">
<div class="right-box__container right-box-container__left">
<div class="container__form">
<el-form :disabled="detail" :model="editRole" :rules="rules" class="right-box-form right-box-form-left" label-position = "top" label-width="120px" ref="roleForm">
<el-form :disabled="detail" :model="editRole" :rules="rules" label-position="top" label-width="120px" ref="roleForm">
<!--name-->
<el-form-item :label="$t('config.roles.name')" prop="name">
<el-input maxlength="64" placeholder="" id="role-box-input-name"

View File

@@ -60,7 +60,7 @@
clearable
collapse-tags
placeholder=""
popper-class="right-box-select-top prevent-clickoutside"
popper-class="right-box-select-top right-public-box-dropdown-top prevent-clickoutside"
size="small">
<template v-for="item in languageList">
<el-option :key="item.value" :label="item.label" :value="item.value"></el-option>

View File

@@ -344,7 +344,7 @@
<script>
import chartDataFormat from '../../charts/chartDataFormat'
import promqlInput from '../../page/dashboard/explore/promqlInput'
import { nzNumber } from '../js/validate'
import { noSpecialChar, nzNumber } from '../js/validate'
import editRigthBox from '../mixin/editRigthBox'
import richTextEditor from '@/components/charts/richTextEditor'
import promqlInputMixin from '@/components/common/mixin/promqlInput'
@@ -406,7 +406,8 @@ export default {
editAlertRule: {},
rules: {
name: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
{ validator: noSpecialChar, trigger: 'change' }
],
expr: [
{ required: true, message: this.$t('validate.required'), trigger: 'change' },

View File

@@ -296,7 +296,7 @@
</template>
<script>
import { host, port, checkAssetAge } from '@/components/common/js/validate'
import { host, port, noSpecialChar } from '@/components/common/js/validate'
import { asset as assetConstants } from '@/components/common/js/constants'
import selectAssetType from '@/components/common/popBox/selectAssetType'
import locationCascader from '@/components/common/rightBox/locationCascader'
@@ -345,7 +345,7 @@ export default {
rules: {
name: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
{ validator: checkAssetAge, trigger: 'blur' }
{ validator: noSpecialChar, trigger: 'blur' }
],
pid: [
{ required: true, message: this.$t('validate.required'), trigger: 'change' }

View File

@@ -160,7 +160,7 @@ export default {
groupData: [],
rules: {
name: [{ required: true, message: this.$t('validate.required'), trigger: 'change' }],
metaKey: [{ required: true, message: this.$t('validate.required'), trigger: 'change' }, { pattern: /\w/, message: this.$t('validate.onlyWord'), trigger: 'change' }],
metaKey: [{ required: true, message: this.$t('validate.required'), trigger: 'change' }, { pattern: /[a-zA-Z_][a-zA-Z0-9_]*/, message: this.$t('validate.onlyWord'), trigger: 'change' }],
groupId: [{ required: true, message: this.$t('validate.required'), trigger: 'change' }],
type: [{ required: true, message: this.$t('validate.required'), trigger: 'change' }]
},

View File

@@ -66,6 +66,7 @@
<script>
import latlngPicker from '../latlngPicker'
import editRigthBox from '../mixin/editRigthBox'
import { noSpecialChar } from '@/components/common/js/validate'
const regNum = /^[0-9]+.?[0-9]*/
@@ -84,7 +85,8 @@ export default {
editDc: {},
rules: {
name: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
{ validator: noSpecialChar, trigger: 'change' }
]
// state: [
// { required: true, message: this.$t('validate.required'), trigger: 'blur' }

View File

@@ -196,7 +196,7 @@
<el-tab-pane :label="$t('project.endpoint.parameter')" name="Parameter">
<div id="module-box-params" ref="labelBoxScrollbar" style="height: 100%; overflow: auto;">
<div v-for="(item, index) in editEndpoint.paramObj" :key="index" class="param-box-row">
<el-form-item :prop="'paramObj.' + index + '.key'" class="param-box-row-key">
<el-form-item :prop="'paramObj.' + index + '.key'" class="param-box-row-key" :rules="[{ pattern: /[a-zA-Z_][a-zA-Z0-9_]*/, message: $t('validate.key') ,trigger: 'blur'}]">
<el-input v-model="item.key" placeholder="key" size="mini" ></el-input>
</el-form-item>
<span class="param-box-row-eq">=</span>
@@ -221,7 +221,7 @@
<el-tab-pane :label="$t('project.endpoint.labels2')" name="Labels">
<div id="module-box-labels" ref="labelBoxScrollbar" style="height: 100%; overflow: auto;">
<div v-for="(item, index) in editEndpoint.labelModule" :key="index" class="param-box-row">
<el-form-item :prop="'labelModule.' + index + '.key'" :rules="[{ pattern: /[a-zA-Z_:][a-zA-Z0-9_:]*/, message: $t('validate.key') ,trigger: 'blur'}]" class="param-box-row-key">
<el-form-item :prop="'labelModule.' + index + '.key'" :rules="[{ pattern: /[a-zA-Z_][a-zA-Z0-9_]*/, message: $t('validate.key') ,trigger: 'blur'}]" class="param-box-row-key">
<el-input v-model="item.key" placeholder="key" size="mini"></el-input>
</el-form-item>
<span class="param-box-row-eq">=</span>
@@ -257,7 +257,7 @@
class="half-form-item" :label="'Source labels'"
:rules="[
{ required: item.action === 'replace' || item.action === 'keep' || item.action === 'drop', message: $t('validate.required'), trigger: 'change' },
{ validator: item.action === 'replace' || item.action === 'keep' || item.action === 'drop'? arrLength : '', trigger: 'change' }
{ validator: item.action === 'replace' || item.action === 'keep' || item.action === 'drop'? arrLength : requirdRelabel, trigger: 'change' }
]">
<vue-tags-input
v-model="item.tags"
@@ -276,7 +276,7 @@
class="half-form-item" :label="'Target label'"
:rules="[
{ required: item.action === 'replace', message: $t('validate.required'), trigger: 'blur' },
{ pattern: /[a-zA-Z_:][a-zA-Z0-9_:]*/, message: $t('validate.key') ,trigger: 'blur'}]"
{ pattern: /[a-zA-Z_][a-zA-Z0-9_]*/, message: $t('validate.key') ,trigger: 'blur'}]"
>
<el-input id="module-box-input-target_label" v-model="item.target_label" placeholder='' size="small"></el-input>
</el-form-item>
@@ -396,12 +396,12 @@
<el-tab-pane :label="$t('project.endpoint.labels2')" name="Labels">
<div id="module-box-logs-labels" ref="labelBoxScrollbar" style="height: 100%; overflow: auto;">
<div v-for="(item1, i) in item.labelModule" :key="i" class="param-box-row">
<el-form-item :prop="'configs.1.config.'+ index +'.labelModule.' + i + '.key'" :rules="[{ pattern: /[a-zA-Z_:][a-zA-Z0-9_:]*/, message: $t('validate.key') ,trigger: 'blur'}]" class="param-box-row-key">
<el-input v-model="item1.key" placeholder="key" size="mini"></el-input>
<el-form-item :prop="'configs.1.config.'+ index +'.labelModule.' + i + '.key'" :rules="[{ pattern: /[a-zA-Z_][a-zA-Z0-9_]*/, message: $t('validate.key') ,trigger: 'blur'}]" class="param-box-row-key">
<el-input v-model="item1.key" placeholder="key" size="mini" @input="$forceUpdate()"></el-input>
</el-form-item>
<span class="param-box-row-eq">=</span>
<el-form-item class="param-box-row-value">
<el-input v-model="item1.value" placeholder="value" size="mini"></el-input>
<el-input v-model="item1.value" placeholder="value" size="mini" @input="$forceUpdate()"></el-input>
</el-form-item>
<span :id="'moduel-remove-label-'+i" class="param-box-row-symbol" @click="removeLogsLabel(index, i)"><i class="nz-icon nz-icon-shanchu1" style="color:#666;"></i></span>
</div>
@@ -442,7 +442,7 @@
<div v-for="(expressions, eindex) in item2.expressions" :key="eindex" style="display: flex;justify-content: space-around;align-items: center;margin-bottom: 16px">
<el-form-item
:prop="'configs.1.config.'+ index +'.pipeline.' + index2 + '.expressions.'+eindex+'.key'"
:rules="[{ required: true, message: $t('validate.required'), trigger: 'blur' }]"
:rules="[{ required: true, message: $t('validate.required'), trigger: 'blur' },{ pattern: /[a-zA-Z_][a-zA-Z0-9_]*/, message: $t('validate.key') ,trigger: 'blur'}]"
style="width: 45%;margin: 0"
>
<el-input v-model="item2.expressions[eindex].key" placeholder="key" size="mini" ></el-input>
@@ -506,7 +506,7 @@
<div v-for="(expressions, eindex) in item2.labels" :key="eindex" style="display: flex;justify-content: space-around;align-items: center;margin-bottom: 16px">
<el-form-item
:prop="'configs.1.config.'+ index +'.pipeline.' + index2 + '.labels.'+eindex+'.key'"
:rules="[{ required: true, message: $t('validate.required'), trigger: 'blur' }]"
:rules="[{ required: true, message: $t('validate.required'), trigger: 'blur' },{ pattern: /[a-zA-Z_][a-zA-Z0-9_]*/, message: $t('validate.key') ,trigger: 'blur'}]"
style="width: 45%;margin: 0"
>
<el-input v-model="item2.labels[eindex].key" placeholder="key" size="mini" ></el-input>
@@ -587,6 +587,7 @@ import pipelineSelect from './pipelineSelect'
import selectWalk from '../popBox/selectWalk'
import editRigthBox from '../mixin/editRigthBox'
import VueTagsInput from '@johmun/vue-tags-input'
import vm from "@/main";
export default {
name: 'editEndpointBoxNew',
@@ -816,6 +817,9 @@ export default {
methods: {
arrLength: arrLength,
port: port,
requirdRelabel (rule, value, callback) {
callback()
},
selectWalk (walk) {
if (this.editEndpoint.configs[0].config.walk.indexOf(walk) != -1) {
this.editEndpoint.configs[0].config.walk.splice(this.editEndpoint.configs[0].config.walk.indexOf(walk), 1)
@@ -1160,7 +1164,7 @@ export default {
this.editEndpoint.paramObj[index].value = newTags.map(item => item.text)
},
beforeAddingTag (tag) {
const regx = /[a-zA-Z_:][a-zA-Z0-9_:]*/
const regx = /[a-zA-Z_][a-zA-Z0-9_]*/
if (regx.test(tag.tag.text)) {
tag.addTag()
} else {
@@ -1296,6 +1300,7 @@ export default {
},
addLogsLabel (index) {
this.editEndpoint.configs[1].config[index].labelModule.push({ key: '', value: '' })
this.$forceUpdate()
},
removeLogsLabel (logsIndex, i) {
if (this.editEndpoint.configs[1].config[logsIndex].labelModule.length === 1) {

View File

@@ -37,8 +37,8 @@
placeholder=""
popper-class="right-box-select-top prevent-clickoutside"
size="small">
<template v-for="item in languageList">
<el-option :key="item.value" :label="item.label" :value="item.value"></el-option>
<template v-for="item in langList">
<el-option :key="item.value" :label="item.name" :value="item.value"></el-option>
</template>
</el-select>
</el-form-item>
@@ -75,7 +75,11 @@ export default {
type: Object
}
},
computed: {},
computed: {
langList () {
return this.$store.getters.getLangList
}
},
mixins: [editRigthBox],
data () {
return {
@@ -83,10 +87,6 @@ export default {
url: 'sys/user/profile',
rightBox: { profile: { show: false } },
editProfile: {},
languageList: [
{ value: 'en', label: 'English' },
{ value: 'cn', label: '简体中文' }
],
rules: {
name: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
@@ -135,7 +135,13 @@ export default {
}
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
this.esc(true)
this.$emit('clickProfile')
if (this.editProfile.lang !== localStorage.getItem('nz-language')) {
localStorage.setItem('nz-language', this.editProfile.lang)
this.$i18n.locale = this.editProfile.lang
this.$emit('clickProfile', true)
} else {
this.$emit('clickProfile', false)
}
} else {
this.$message.error(res.msg)
}

View File

@@ -16,7 +16,7 @@
<el-input id="project-box-input-name" v-model="editProject.name" maxlength="64" show-word-limit size="small"></el-input>
</el-form-item>
<el-form-item :label='$t("overall.remark")'>
<el-input id="project-box-input-name" v-model="editProject.remark" maxlength="256" show-word-limit type="textarea"></el-input>
<el-input id="project-box-input-remark" v-model="editProject.remark" maxlength="256" show-word-limit type="textarea"></el-input>
</el-form-item>
</el-form>
</div>

View File

@@ -0,0 +1,167 @@
<template>
<div class="right-box right-box-dc" v-clickoutside="{obj:editGlobalization,func:clickOutside}">
<!-- begin--标题-->
<div class="right-box__header">
<div class="header__title">{{editGlobalization.id ? ($t("config.menus.editI18n")) : $t("config.menus.createI18n")}}</div>
<div class="header__operation">
<span v-cancel="{obj: editGlobalization, func: esc}"><i class="nz-icon nz-icon-close"></i></span>
</div>
</div>
<!-- begin--表单-->
<div class="right-box__container">
<div class="container__form">
<el-form label-width="120px" size="small" :model="editGlobalization" label-position = "top" ref="globalizationForm">
<el-form-item :label='$t("config.menus.name")' prop="name">
<el-input placeholder="" maxlength="64" show-word-limit v-model="editGlobalization.name" size="small" id="dc-box-input-name"></el-input>
</el-form-item>
<el-form-item :label='$t("config.menus.code")' prop="code">
<el-input placeholder="" maxlength="64" show-word-limit v-model="editGlobalization.code" size="small" id="dc-box-input-code"></el-input>
</el-form-item>
<el-form-item :label="$t('config.menus.lang')" prop="lang">
<el-select id="account-input-language"
class="right-box__select"
v-model="editGlobalization.lang"
clearable
collapse-tags
placeholder=""
popper-class="right-box-select-top right-public-box-dropdown-top prevent-clickoutside"
size="small">
<template v-for="item in languageList">
<el-option :key="item.id" :label="item.name" :value="item.value"></el-option>
</template>
</el-select>
</el-form-item>
<el-form-item :label='$t("config.menus.value")' prop="value">
<el-input placeholder="" maxlength="64" show-word-limit v-model="editGlobalization.value" size="small" id="dc-box-input-value"></el-input>
</el-form-item>
<!-- <el-form-item :label='$t("i18n.remark")' prop="remark">-->
<!-- <el-input placeholder="" maxlength="64" show-word-limit v-model="editGlobalization.value" size="small" id="dc-box-input-value"></el-input>-->
<!-- </el-form-item>-->
</el-form>
</div>
</div>
<!--底部按钮-->
<div class="right-box__footer">
<button v-cancel="{obj:editGlobalization,func:esc}" id="dc-box-esc" class="footer__btn footer__btn--light">
<span>{{$t('overall.cancel')}}</span>
</button>
<button :class="{'nz-btn-disabled':prevent_opt.save}" :disabled="prevent_opt.save" @click="save" class="footer__btn" id="dc-box-save">
<span>{{$t('overall.save')}}</span>
</button>
</div>
</div>
</template>
<script>
import editRigthBox from '@/components/common/mixin/editRigthBox'
export default {
name: 'globalizationBox',
props: {
obj: {
type: Object
},
globalizationData: Array
},
mixins: [editRigthBox],
data () {
return {
editGlobalization: {},
areaData: [],
coordinateFlag: false,
languageList: []
}
},
methods: {
/* 关闭弹框 */
esc (refresh) {
this.prevent_opt.save = false
this.$emit('close', refresh)
},
clickOutside () {
this.esc(false)
},
/* 保存 */
save () {
if (this.prevent_opt.save) {
return
};
this.prevent_opt.save = true
this.$refs.globalizationForm.validate((valid) => {
if (valid) {
if (this.editGlobalization.id) {
const param = { ...this.editGlobalization }
this.$put('/sys/i18n', param).then(response => {
this.prevent_opt.save = false
if (response.code === 200) {
this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') })
this.esc(true)
} else {
this.$message.error(response.msg)
}
})
} else {
const param = { ...this.editGlobalization }
this.$post('/sys/i18n', param).then(response => {
this.prevent_opt.save = false
if (response.code === 200) {
this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') })
this.esc(true)
} else {
this.$message.error(response.msg)
}
})
}
} else {
this.prevent_opt.save = false
return false
}
})
},
/* 删除 */
del () {
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('/sys/i18n' + this.editGlobalization.id).then(response => {
this.prevent_opt.save = false
if (response.code === 200) {
this.$message({ duration: 1000, type: 'success', message: this.$t('tip.deleteSuccess') })
this.esc(true)
} else {
this.$message.error(response.msg)
}
})
}).catch(() => {
this.prevent_opt.save = false
})
},
langDataList () {
this.$get('/sys/dict/all', { type: 'lang' }).then(response => {
if (response.code === 200) {
this.languageList = response.data
} else {
this.$message.error(response.msg)
}
})
}
},
mounted () {
this.langDataList()
},
watch: {
obj: {
immediate: true,
deep: true,
handler (n, o) {
this.isEdit = true
this.editGlobalization = JSON.parse(JSON.stringify(n))
}
}
}
}
</script>

View File

@@ -0,0 +1,10 @@
diff a/nezha-fronted/src/components/common/rightBox/setting/globalizationBox.vue b/nezha-fronted/src/components/common/rightBox/setting/globalizationBox.vue (rejected hunks)
@@ -145,7 +145,7 @@
if (response.code === 200) {
this.languageList = response.data
if (!this.editGlobalization.id) {
- this.languageList[0].value = 'en'
+ this.languageList[1].value = 'en'
}
} else {
this.$message.error(response.msg)

View File

@@ -91,7 +91,7 @@
:id="scope.row[item.label].id"
:that="scope.row[item.label]"
:type="item.label"
:alert-table-dialog="true"
:alert-table-dialog="chartAlertList"
></alertLabel>
</span>
</template>
@@ -160,7 +160,8 @@ export default {
default: true
},
alertMessageTabNew: Boolean,
loading: Boolean
loading: Boolean,
chartAlertList: Boolean
},
mixins: [table, bus],
data () {

View File

@@ -0,0 +1,187 @@
<template>
<el-table
id="alertRuleTable"
ref="dataTable"
:data="tableData"
:height="height"
tooltip-effect="light"
border
@header-dragend="dragend"
@sort-change="tableDataSort"
@selection-change="selectionChange"
@row-dblclick="(row)=>{queryMessage(row)}"
>
<el-table-column
:resizable="false"
align="center"
type="selection"
width="55">
</el-table-column>
<el-table-column
v-for="(item, index) in customTableTitle"
v-if="item.show"
:key="`col-${index}`"
:fixed="item.fixed"
:label="item.label"
:min-width="`${item.minWidth}`"
:prop="item.prop"
:resizable="true"
:sort-orders="['ascending', 'descending']"
:sortable="item.sortable"
:width="`${item.width}`"
:show-overflow-tooltip="item.prop === 'description'"
class="data-column"
>
<template slot="header">
<span class="data-column__span">{{item.label}}</span>
<div class="col-resize-area"></div>
</template>
<template slot-scope="scope" :column="item">
<template v-if="item.prop === 'state'">
<div>
<div :class="{'active-icon green-bg':scope.row.state == 200,'active-icon red-bg':scope.row.state != 200}" style="position: relative">
</div>
<span>{{scope.row.state == 200?'Ok':'Error'}}</span>
</div>
</template>
<template v-else-if="item.prop === 'duration'">
<el-tooltip :disabled="!scope.row.etts" effect="light" placement="right">
<div slot="content">
{{$t('config.terminallog.endTime')}}<br/>
{{timestampStr(scope.row.etts)}}
</div>
<span>{{getDuration(scope.row)}}</span>
</el-tooltip>
</template>
<template v-else-if="item.prop === 'stts'">
{{timestampStr(scope.row[item.prop])}}
</template>
<span v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</span>
<template v-else>-</template>
</template>
</el-table-column>
<template slot="empty">
<div v-if="!loading" class="table-no-data">
<svg class="icon" aria-hidden="true">
<use xlink:href="#nz-icon-no-data-list"></use>
</svg>
<div class="table-no-data__title">No results found</div>
</div>
<div v-else>&nbsp;</div>
</template>
</el-table>
</template>
<script>
import table from '@/components/common/mixin/table'
import { calcDurationByStringTimeMs } from '@/components/common/js/tools'
export default {
name: 'alertRuleTable',
mixins: [table],
props: {
loading: Boolean,
nowTime: {}
},
data () {
return {
tableTitle: [
{
label: this.$t('config.dc.state'),
prop: 'state',
show: true,
minWidth: 100,
}, {
label: this.$t('alert.alertRuleMessage'),
prop: 'msg',
show: true,
minWidth: 100,
}, {
label: this.$t('alert.silence.startTime'),
prop: 'stts',
show: true,
minWidth: 300,
}, {
label: this.$t('config.terminallog.duration'),
prop: 'duration',
show: true,
minWidth: 120
}
]
}
},
computed: {
},
methods: {
getDuration (record) {
if (record.etts) {
return calcDurationByStringTimeMs(record.stts, record.etts)
}
return calcDurationByStringTimeMs(record.stts, this.utcTimeToTimezoneStr(this.nowTime))
}
}
}
</script>
<style scoped>
.colorEF7458{
color: #EF7458;
}
.color23BF9A{
color: #23BF9A;
}
/deep/ .active-icon {
margin-left: 5px;
}
</style>
<style>
.severity .P1{
background: #F5846A;
border-radius: 2px;
font-size: 12px;
color: #FFFFFF;
padding: 2px 6px;
}
.severity .P2{
background: #F7A54A;
border-radius: 2px;
font-size: 12px;
color: #FFFFFF;
padding: 2px 6px;
}
.severity .P3{
background: #F1C13D;
border-radius: 2px;
font-size: 12px;
color: #FFFFFF;
padding: 2px 6px;
}
.schedEnableTitle{
padding: 20px 15px;
margin-right: 0;
left: 1995px !important;
background: #FFFFFF;
border: 1px solid rgba(119,131,145,0.60);
box-shadow: 0 6px 16px 0 rgba(0,0,0,0.08);
border-radius: 3px;
}
.schedEnableTitle .nz-icon-a-rilizhou, .schedEnableTitle .nz-icon-dingshishijian{
font-size: 14px;
color: #666666;
margin-right: 12px;
}
.schedEnableTitle .week-item{
width: 32px;
height: 22px;
line-height: 22px;
opacity: 0.9;
background: #F6F6FA;
border-radius: 2px;
display: inline-block;
font-size: 12px;
color: #666666;
letter-spacing: 0;
font-weight: 400;
padding-left: 3px;
margin-right: 12px;
margin-bottom: 6px;
}
</style>

View File

@@ -116,7 +116,8 @@ export default {
},
mixins: [table],
props: {
loading: Boolean
loading: Boolean,
nowTime: {}
},
data () {
return {

View File

@@ -0,0 +1,128 @@
<template>
<el-table
id="dcTable"
ref="dataTable"
:data="tableData"
:height="height"
border
@header-dragend="dragend"
@sort-change="tableDataSort"
@selection-change="selectionChange"
>
<el-table-column
:resizable="false"
align="center"
type="selection"
width="55">
</el-table-column>
<el-table-column
v-for="(item, index) in customTableTitle"
v-if="item.show"
:key="`col-${index}`"
:fixed="item.fixed"
:label="item.label"
:min-width="`${item.minWidth}`"
:prop="item.prop"
:resizable="true"
:sort-orders="['ascending', 'descending']"
:sortable="item.sortable"
:width="`${item.width}`"
class="data-column"
>
<template slot="header">
<span class="data-column__span">{{item.label}}</span>
<div class="col-resize-area"></div>
</template>
<template slot-scope="scope" :column="item">
<template v-if="item.prop === 'lang'">
<span v-if="scope.row[item.prop] === 'en'">English</span>
<span v-else-if="scope.row[item.prop] === 'zh'">简体中文</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" v-has="'i18n_edit'" @click="tableOperation(['edit', scope.row])"><i class="nz-icon nz-icon-edit"></i></button>
<el-dropdown size="medium" v-has="['i18n_delete', 'i18n_edit']" trigger="click" @command="tableOperation">
<div class="table-operation-item table-operation-item--more">
<i class="nz-icon nz-icon-more3"></i>
</div>
<el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top">
<el-dropdown-item v-has="'i18n_delete'" :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-menu>
</el-dropdown>
</div>
</el-table-column>
<template slot="empty">
<div v-if="!loading" class="table-no-data">
<svg class="icon" aria-hidden="true">
<use xlink:href="#nz-icon-no-data-list"></use>
</svg>
<div class="table-no-data__title">No results found</div>
</div>
<div v-else>&nbsp;</div>
</template>
</el-table>
</template>
<script>
import table from '@/components/common/mixin/table'
export default {
name: 'globalizationTable',
mixins: [table],
props: {
loading: Boolean
},
data () {
return {
tableTitle: [
{
label: 'ID',
prop: 'id',
show: true,
width: 80,
sortable: 'custom'
}, {
label: this.$t('config.menus.name'),
prop: 'name',
show: true,
minWidth: 150,
sortable: 'custom'
}, {
label: this.$t('config.menus.code'),
prop: 'code',
show: true,
minWidth: 150,
sortable: 'custom'
}, {
label: this.$t('config.menus.lang'),
prop: 'lang',
show: true,
minWidth: 150,
sortable: 'custom'
}, {
label: this.$t('config.menus.value'),
prop: 'value',
minWidth: 150,
show: true
}
// , {
// label: this.$t('i18n.remark'),
// prop: 'remark',
// show: true,
// sortable: 'custom'
// }
]
}
}
}
</script>
<style scoped>
</style>

View File

@@ -38,11 +38,8 @@
<i class="nz-icon nz-icon-language-change"></i>
</div>
<el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top">
<el-dropdown-item>
<div id="header-to-english" :style="language === 'en'?'color:#f90':''" @click="changeLocal('en')"><i class="nz-icon nz-icon-lang-en"></i>English</div>
</el-dropdown-item>
<el-dropdown-item>
<div id="header-to-chinese" :style="language === 'cn'?'color:#f90':''" @click="changeLocal('cn')"><i class="nz-icon nz-icon-lang-zh"></i>简体中文</div>
<el-dropdown-item v-for="lang in langList" :key="lang.value">
<div :style="language === lang.value ? 'color:#f90' : ''" @click="changeLocal(lang.value)"><i :class="`nz-icon-lang-${lang.value}`" class="nz-icon"></i>{{lang.name}}</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
@@ -62,7 +59,6 @@
</el-dropdown-menu>
</el-dropdown>
</div>
<!-- <change-password :cur-user="username" :show-dialog="showChangePin" @click="showPinDialog" @dialogClosed="dialogClosed"></change-password>-->
<guide :show-dialog="showGuide" @dialogClosed="dialogClosed" @close="showGuide = false"></guide>
</div>
</template>
@@ -138,7 +134,6 @@ export default {
getLinkData () {
this.$get('link').then(response => {
this.$store.commit('setLinkData', response.data.list)
// this.linkData = response.data.list
})
},
changeLocal (lang) {
@@ -154,13 +149,6 @@ export default {
document.location.href = '/'
})
},
// refreshLang () {
// this.language = localStorage.getItem('nz-language')
// this.$i18n.locale = this.language
// this.$nextTick(() => {
// // window.location.reload()
// })
// },
showPinDialog () {
this.$router.push({
path: '/profile',
@@ -207,6 +195,9 @@ export default {
route () {
return this.$route.path
},
langList () {
return this.$store.getters.getLangList
},
breadcrumb () {
if (this.$route.path === '/profile') {
return [

View File

@@ -21,7 +21,8 @@
<button id="asset-create-asset" v-has="'asset_add'" :title="$t('overall.createAsset')" class="top-tool-btn" @click.stop="add">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="model"
:params="searchLabel"
@@ -87,7 +88,8 @@
@click="add">
<i class="nz-icon-create-square nz-icon"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="alert-rule"
:params="searchLabel"

View File

@@ -25,6 +25,7 @@
:custom-table-title="tools.customTableTitle"
:height="mainTableHeight"
:table-data="tableData"
:nowTime="nowTime"
@del="del"
@edit="edit"
@copy="copy"
@@ -163,6 +164,7 @@ export default {
this.tools.loading = true
this.$get(this.url, { ...this.searchLabel, ...this.searchCheckBox }).then(response => {
this.tools.loading = false
this.nowTime = this.utcTimeToTimezoneStr(response.time)
if (response.code === 200) {
for (let i = 0; i < response.data.list.length; i++) {
response.data.list[i].status = response.data.list[i].status + ''

View File

@@ -21,7 +21,8 @@
<button id="asset-create-asset" v-has="'asset_add'" :title="$t('overall.createAsset')" class="top-tool-btn" @click.stop="add">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="model"
:params="searchLabel"
@@ -92,7 +93,8 @@
<button id="asset-create-asset" v-has="'asset_add'" :title="$t('overall.createAsset')" class="top-tool-btn" @click.stop="add">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="model"
:params="searchLabel"
@@ -110,7 +112,7 @@
<template v-slot:before>
<div>
<el-dropdown-item>
<div id="asset-batch-asset" v-has="'asset_edit'" @click.stop="batchEdit"><i class="nz-icon nz-icon-batch-edit"></i>{{$t('overall.batchEdit')}}</div>
<div id="asset-batch-asset" v-has="'asset_edit'" @click="batchEdit"><i class="nz-icon nz-icon-batch-edit"></i>{{$t('overall.batchEdit')}}</div>
</el-dropdown-item>
<el-dropdown-item>
<delete-button :type="'link'" :title="$t('overall.batchDel')" id="asset-list-batch-delete" v-has="'asset_delete'" :api="url" :delete-objs="batchDeleteObjs" @after="getTableData" @before="delFlag=true"></delete-button>
@@ -556,7 +558,7 @@ export default {
})
})
},
getSearchableMetaData () {
getSearchableMetaData (metaData) {
return new Promise(resolve => {
this.$get('asset/field/meta', { pageSize: -1 }).then(response => {
if (response.code === 200) {
@@ -569,7 +571,20 @@ export default {
if (m.param) {
const param = JSON.parse(m.param)
if (param.items) {
data.push({ ...m, children: param.items.map(p => { return { ...p, id: p.name, metaId: m.id } }) })
// param.items.map(p => { return { ...p, id: p.name, metaId: m.id, num: metaData.find(meta => meta.id === m.id && meta.option === p.name).num } })
data.push({
...m,
children: param.items.map(p => {
const metaFind = metaData.find(meta => meta.id === m.id && meta.option === p.name)
return {
...p,
id: p.name,
name: p.name,
metaId: m.id,
num: metaFind ? metaFind.num : 0
}
})
})
}
}
})
@@ -602,7 +617,7 @@ export default {
// const titleSearchData = {}
this.modelData.forEach(m => {
m.value = []
arr.push({ ...m, name: m.brand.name + '/' + m.name, value: m.id })
arr.push({ ...m, name: m.brand.name + '/' + m.name, value: m.id, num: m.num })
// if (titleSearchData[m.brand.name]) {
// titleSearchData[m.brand.name].children.push(m)
// } else {

View File

@@ -21,7 +21,8 @@
<button id="asset-create-asset" v-has="'asset_add'" :title="$t('overall.createAsset')" class="top-tool-btn" @click.stop="add">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="model"
:params="searchLabel"
@@ -87,7 +88,8 @@
type="button" @click="add">
<i class="nz-icon-create-square nz-icon"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="model"
:params="searchLabel"
@@ -125,7 +127,6 @@
@orderBy="tableDataSort"
@reload="getTableData"
@selectionChange="selectionChange"
@statusChange='statusChange'
@showBottomBox="(targetTab, object) => { $refs.dataList.showBottomBox(targetTab, object) }"></dc-table>
</template>
<!-- 分页组件 -->
@@ -228,17 +229,6 @@ export default {
}
},
methods: {
statusChange (dc) {
this.$put(this.url, dc).then(response => {
if (response.code === 200) {
this.rightBox.show = false
this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') })
} else {
this.$message.error(response.msg)
}
this.getTableData()
})
},
getUserData () {
return new Promise(resolve => {
this.$get('sys/user', { pageSize: -1, pageNo: 1 }).then(response => {

View File

@@ -0,0 +1,155 @@
<template>
<div>
<nz-data-list
ref="dataList"
:api="url"
:layout="['searchInput', 'elementSet', 'pagination']"
:custom-table-title.sync="tools.customTableTitle"
:from="fromRoute.dc"
:search-msg="searchMsg"
@search="search"
@getTableData="getTableData"
>
<template v-slot:top-tool-right>
<button id="dc-add" v-has="'dc_add'" :title="$t('overall.createDatacenter')" class="top-tool-btn margin-r-10"
type="button" @click="add">
<i class="nz-icon-create-square nz-icon"></i>
</button>
</template>
<template v-slot:default="slotProps">
<globalization-table
ref="dataTable"
v-loading="tools.loading"
:loading="tools.loading"
:api="url"
:custom-table-title="tools.customTableTitle"
:height="mainTableHeight"
:table-data="tableData"
@del="del"
@edit="edit"
@copy="copy"
@orderBy="tableDataSort"
@reload="getTableData"
@selectionChange="selectionChange"
@showBottomBox="(targetTab, object) => { $refs.dataList.showBottomBox(targetTab, object) }"></globalization-table>
</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">
<i18n-box v-if="rightBox.show" :obj="object" :globalization-data="globalizationData" @close="closeRightBox" @reload="getTableData"></i18n-box>
</transition>
</div>
</template>
<script>
import nzDataList from '@/components/common/table/nzDataList'
import dataListMixin from '@/components/common/mixin/dataList'
import i18nBox from '@/components/common/rightBox/setting/globalizationBox'
import globalizationTable from '@/components/common/table/settings/globalizationTable'
export default {
name: 'i18n',
components: {
nzDataList,
i18nBox,
globalizationTable
},
mixins: [dataListMixin],
data () {
return {
url: 'sys/i18n',
tableId: 'i18nTable', // 需要分页的table的id用于记录每页数量
blankObject: {
ids: '',
name: '',
code: '',
lang: 'en',
value: ''
},
searchMsg: { // 给搜索框子组件传递的信息
zheze_none: true,
searchLabelList: [
{
name: 'ID',
type: 'input',
label: 'ids',
disabled: false
},
{
name: this.$t('i18n.code'),
type: 'input',
label: 'code',
disabled: false
},
{
name: this.$t('i18n.lang'),
type: 'input',
label: 'lang',
disabled: false
},
{
name: this.$t('i18n.value'),
type: 'input',
label: 'value',
disabled: false
}
]
},
globalizationData: [],
cabinetBoxShow: false
}
},
methods: {
getUserData () {
return new Promise(resolve => {
this.$get('/sys/i18n', { pageSize: -1, pageNo: 1 }).then(response => {
if (response.code === 200) {
this.globalizationData = response.data.list
} else {
this.$message.error(response.msg)
}
resolve()
})
})
},
addCabinet () {
this.cabinetBoxShow = true
},
closeRightBox (refresh) {
this.rightBox.show = false
this.cabinetBoxShow = false
if (refresh) {
this.delFlag = true
this.getTableData()
}
}
},
mounted () {
this.getUserData()
}
// watch: {
// $route: {
// immediate: true,
// handler () {
// // 是否弹出侧滑
// const add = this.$route.query.add
// if (add) {
// if (add === 'dc') {
// this.add()
// }
// if (add === 'cabinet') {
// this.addCabinet()
// }
// }
// }
// }
// }
}
</script>
<style scoped>
/deep/ td .nz-icon-gear:before{
color: #606266;
}
</style>

View File

@@ -14,7 +14,8 @@
type="button" @click="add">
<i class="nz-icon-create-square nz-icon"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="model"
:params="searchLabel"

View File

@@ -321,8 +321,13 @@ export default {
closeRightBox () {
this.rightBox.show = false
},
clickProfile () {
clickProfile (refresh) {
this.personalCenter()
if (refresh) {
setTimeout(() => {
window.location.reload()
}, 500)
}
},
closeDialog () {
this.authBindShow = false

View File

@@ -37,7 +37,8 @@
type="button" @click="add">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="expression-template-list"
export-url="visual/panel/export"

View File

@@ -22,7 +22,8 @@
type="button" @click="add">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="expression-template-list"
export-url="expression/tmpl/export"

View File

@@ -154,20 +154,6 @@ export default {
}
},
methods: {
statusChange (user) {
if (user.roles) {
user.roleIds = user.roles.map(t => t.id)
}
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') })
} else {
this.$message.error(response.msg)
}
this.getTableData()
})
},
edit (u, copyFlag) {
this.$get(`${this.url}/${u.id}`).then(response => {
const user = response.user

View File

@@ -1,60 +0,0 @@
<script>
import en from '../../common/language/en'
import cn from '../../common/language/cn'
export default {
name: 'language',
data () {
return {
result: null,
languageList: []
}
},
methods: {
compareFile: function (obj, compareObj) {
if (!obj) {
obj = en
}
if (!compareObj) {
compareObj = cn
}
const keys = Object.keys(obj)
for (const key of keys) {
if (typeof obj[key] === 'object') {
if (!compareObj[key]) {
this.$set(compareObj, key, {})
}
this.compareFile(obj[key], compareObj[key])
} else {
if (!compareObj[key]) {
this.$set(compareObj, key, obj[key])
}
}
}
this.result = cn
},
listLanguage: function (obj, compareObj) {
if (!obj) {
obj = en
}
if (!compareObj) {
compareObj = cn
}
const keys = Object.keys(obj)
for (const key of keys) {
if (typeof obj[key] === 'object') {
if (!compareObj[key]) {
this.$set(compareObj, key, {})
}
this.listLanguage(obj[key], compareObj[key])
} else {
if (!compareObj[key]) {
this.$set(compareObj, key, obj[key])
}
this.languageList.push({ en: obj[key], cn: compareObj[key] })
}
}
}
}
}
</script>

View File

@@ -47,7 +47,8 @@
<i class="nz-icon-create-square nz-icon"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
id="panel"
:params="filter"
:permissions="{
@@ -213,7 +214,8 @@ export default {
panelId: 0,
filterPanel: '',
// ---图表相关参数--end
scrollbarWrap: null
scrollbarWrap: null,
batchDeleteObjs: []
}
},
components: {

View File

@@ -21,7 +21,8 @@
<button id="asset-create-asset" v-has="'asset_add'" :title="$t('overall.createAsset')" class="top-tool-btn" @click.stop="add">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="model"
:params="searchLabel"
@@ -92,7 +93,8 @@
type="button" @click="add">
<i class="nz-icon-create-square nz-icon"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="endpoint-template-list"
:params="searchLabel"

View File

@@ -21,7 +21,8 @@
<button id="asset-create-asset" v-has="'asset_add'" :title="$t('overall.createAsset')" class="top-tool-btn" @click.stop="add">
<i class="nz-icon nz-icon-create-square"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="model"
:params="searchLabel"
@@ -88,7 +89,8 @@
type="button" @click="add">
<i class="nz-icon-create-square nz-icon"></i>
</button>
<top-tool-more-options
<top-tool-more-options
:delete-objs="batchDeleteObjs"
ref="export"
id="endpoint-template-list"
:params="searchLabel"

View File

@@ -117,6 +117,17 @@ Vue.mixin({
return bus.timeFormate(this.timezoneToUtcTime(time), format)
}
},
timestampStr: function (time, format = 'yyyy-MM-dd hh:mm:ss') {
const date = new Date(time)
const localOffset = date.getTimezoneOffset() * 60 * 1000 // 默认 一分钟显示时区偏移的结果
let dateStr = new Date(time).getTime() + localOffset
dateStr = bus.timeFormate(dateStr, format)
if (time) {
return bus.timeFormate(bus.UTCTimeToConfigTimezone(dateStr), format)
} else {
return '-'
}
},
hasButton (code) {
return hasButton(this.$store.getters.buttonList, code)
},

View File

@@ -3,7 +3,7 @@ import store from './store'
import { get, post } from './http'
import ElementUI from 'element-ui'
import Vue from 'vue'
import i18n from './components/common/i18n'
import i18n, { loadI18n } from './components/common/i18n'
import VueResource from 'vue-resource'
Vue.use(VueResource)
@@ -12,8 +12,8 @@ const loginWhiteList = ['/setup', '/sys/license/upload', '/sys/license/state'] /
const permissionWhiteList = ['/profile', '/menu', ...loginWhiteList] // 权限白名单
router.beforeEach((to, from, next) => {
const configUrl = 'static/config.json?Timestamp=' + new Date().getTime()
if (to.path === '/login') { // 拦截登录页面,系统初始化检查
const configUrl = 'static/config.json?Timestamp=' + new Date().getTime()
Vue.http.get(configUrl).then(config => {
get(config.body.baseUrl + 'setup/inited').then(res => {
if (res.code === 200) {
@@ -24,11 +24,33 @@ router.beforeEach((to, from, next) => {
}
}
})
if (!store.getters.i18nIsReady) {
get(config.body.baseUrl + 'sys/i18n/lang').then(res => {
if (res.code === 200) {
loadI18n(res.data)
store.commit('i18nReady', true)
}
})
}
})
} else if (sessionStorage.getItem('nz-token')) {
// 从localStorage加载i18n
if (!store.getters.i18nIsReady) {
Vue.http.get(configUrl).then(config => {
get(config.body.baseUrl + 'sys/i18n/lang').then(response => {
if (response.code === 200) {
loadI18n(response.data)
store.commit('i18nReady', true)
}
})
})
const langList = localStorage.getItem('nz-language-list')
if (langList) {
store.commit('setLangList', JSON.parse(langList))
}
}
new Promise(resolve => {
if (store.getters.menuList.length === 0) {
const configUrl = 'static/config.json?Timestamp=' + new Date().getTime()
Vue.http.get(configUrl).then(config => {
post(config.body.baseUrl + 'sys/user/permissions', { token: sessionStorage.getItem('nz-token') }).then(res => {
store.commit('setMenuList', sortByOrderNum(res.data.menus))

View File

@@ -114,6 +114,10 @@ export default new Router({
path: '/system',
component: resolve => require(['../components/page/config/system.vue'], resolve)
},
{
path: '/i18n',
component: resolve => require(['@/components/page/config/globalization.vue'], resolve)
},
{
path: '/alertMessage',
component: resolve => require(['../components/page/alert/alertMessage.vue'], resolve)

View File

@@ -35,7 +35,9 @@ const store = new Vuex.Store({
showTopoScreen: false,
logo: '',
isShrink: localStorage.getItem('nz-left-menu-shrink') == 'true',
metricsList: []
metricsList: [],
langList: [],
i18nReady: false
},
getters: {
getLinkData (state) {
@@ -71,6 +73,12 @@ const store = new Vuex.Store({
getMetricsList (state) {
return state.metricsList
},
getLangList (state) {
return state.langList
},
i18nIsReady (state) {
return state.i18nReady
}
},
mutations: {
/* 监听对象变化,用于顶部菜单与底部内容的同步 */
@@ -153,6 +161,12 @@ const store = new Vuex.Store({
},
setMetricsList (state, metricsList) {
state.metricsList = [...metricsList]
},
setLangList (state, langList) {
state.langList = langList
},
i18nReady (state, ready) {
state.i18nReady = ready
}
},
actions: {

View File

@@ -1,7 +1,7 @@
import { post, get } from '../http'
import { post, get } from '@/http'
import router from '../router'
import bus from '../libs/bus'
import { sortByOrderNum } from '../permission'
import { sortByOrderNum } from '@/permission'
import moment from 'moment-timezone'
import { theme } from '@/components/common/js/constants'