forked from github/dataease
feat: 删除前端工程中meterSphere组件
This commit is contained in:
parent
5781da135a
commit
46d24a17bc
@ -9,15 +9,15 @@
|
||||
<!--<i v-if="asideHidden" class="el-icon-arrow-right"/>-->
|
||||
<!--</div>-->
|
||||
<slot />
|
||||
<ms-horizontal-drag-bar />
|
||||
<de-horizontal-drag-bar />
|
||||
</el-aside>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsHorizontalDragBar from './dragbar/MsLeft2RightDragBar'
|
||||
import DeHorizontalDragBar from './dragbar/DeLeft2RightDragBar'
|
||||
export default {
|
||||
name: 'MsAsideContainer',
|
||||
components: { MsHorizontalDragBar },
|
||||
name: 'DeAsideContainer',
|
||||
components: { DeHorizontalDragBar },
|
||||
props: {
|
||||
width: {
|
||||
type: String,
|
@ -8,7 +8,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsContainer'
|
||||
name: 'DeContainer'
|
||||
}
|
||||
</script>
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsMainContainer'
|
||||
name: 'DeMainContainer'
|
||||
}
|
||||
</script>
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="drag-bar" v-bottom-to-top-drag/>
|
||||
<div v-bottom-to-top-drag class="drag-bar" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsBottom2TopDragBar"
|
||||
}
|
||||
export default {
|
||||
name: 'DeBottom2TopDragBar'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsLeft2RightDragBar'
|
||||
name: 'DeLeft2RightDragBar'
|
||||
}
|
||||
</script>
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="drag-bar" v-right-to-left-drag/>
|
||||
<div v-right-to-left-drag class="drag-bar" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsRight2LeftDragBar"
|
||||
}
|
||||
export default {
|
||||
name: 'DeRight2LeftDragBar'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
@ -1,8 +1,71 @@
|
||||
import permission from '@/directive/Permission'
|
||||
|
||||
export const left2RightDrag = {
|
||||
inserted(el, binding) {
|
||||
el.onmousedown = function(e) {
|
||||
const init = e.clientX
|
||||
const parent = el.parentNode
|
||||
const initWidth = parent.offsetWidth
|
||||
document.onmousemove = function(e) {
|
||||
const end = e.clientX
|
||||
const newWidth = end - init + initWidth
|
||||
if (newWidth < document.body.clientWidth - 10 && newWidth > 10) {
|
||||
parent.style.width = newWidth + 'px'
|
||||
}
|
||||
}
|
||||
document.onmouseup = function() {
|
||||
document.onmousemove = document.onmouseup = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const right2LeftDrag = {
|
||||
inserted(el, binding) {
|
||||
el.onmousedown = function(e) {
|
||||
const init = e.clientX
|
||||
const parent = el.parentNode
|
||||
const initWidth = parent.offsetWidth
|
||||
document.onmousemove = function(e) {
|
||||
const end = e.clientX
|
||||
const newWidth = initWidth - (end - init)
|
||||
if (newWidth < document.body.clientWidth - 10 && newWidth > 10) {
|
||||
parent.style.width = newWidth + 'px'
|
||||
}
|
||||
}
|
||||
document.onmouseup = function() {
|
||||
document.onmousemove = document.onmouseup = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const bottom2TopDrag = {
|
||||
inserted(el, binding) {
|
||||
el.onmousedown = function(e) {
|
||||
const init = e.clientY
|
||||
const parent = el.parentNode
|
||||
const initHeight = parent.offsetHeight
|
||||
document.onmousemove = function(e) {
|
||||
const end = e.clientY
|
||||
const newHeight = initHeight - (end - init)
|
||||
if (newHeight < document.body.clientHeight - 10 && newHeight > 10) {
|
||||
parent.style.height = newHeight + 'px'
|
||||
}
|
||||
}
|
||||
document.onmouseup = function() {
|
||||
document.onmousemove = document.onmouseup = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
install(Vue) {
|
||||
Vue.directive('permission', permission)
|
||||
Vue.directive('left-to-right-drag', left2RightDrag)
|
||||
Vue.directive('right-to-left-drag', right2LeftDrag)
|
||||
Vue.directive('bottom-to-top-drag', bottom2TopDrag)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,8 @@ import Cookies from 'js-cookie'
|
||||
import '@/styles/index.scss' // global css
|
||||
import ElementUI from 'element-ui'
|
||||
import Fit2CloudUI from 'fit2cloud-ui'
|
||||
// import 'element-ui/lib/theme-chalk/index.css'
|
||||
// import './styles/variables.scss'
|
||||
import i18n from './lang' // internationalization
|
||||
|
||||
import i18n from './lang' // internationalization
|
||||
import App from './App'
|
||||
import store from './store'
|
||||
import router from './router'
|
||||
@ -15,8 +13,6 @@ import '@/icons' // icon
|
||||
import '@/permission' // permission control
|
||||
import api from '@/api/index.js'
|
||||
import filter from '@/filter/filter'
|
||||
import message from '@/metersphere/common/js/message'
|
||||
import { left2RightDrag, bottom2TopDrag, right2LeftDrag } from '@/metersphere/common/js/directive'
|
||||
import directives from './directive'
|
||||
|
||||
import './styles/vdrr/common-temp.scss'
|
||||
@ -58,13 +54,8 @@ Vue.use(Fit2CloudUI, {
|
||||
i18n: (key, value) => i18n.t(key, value)
|
||||
})
|
||||
Vue.use(filter)
|
||||
Vue.use(message)
|
||||
Vue.use(directives)
|
||||
Vue.config.productionTip = false
|
||||
// 支持左右拖拽
|
||||
Vue.directive('left-to-right-drag', left2RightDrag)
|
||||
Vue.directive('right-to-left-drag', right2LeftDrag)
|
||||
Vue.directive('bottom-to-top-drag', bottom2TopDrag)
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
|
@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<chart
|
||||
:init-options="defaultInitOptions"
|
||||
:options="options"
|
||||
:theme="theme"
|
||||
:group="group"
|
||||
@click="onClick"
|
||||
:watch-shallow="watchShallow"
|
||||
:manual-update="manualUpdate"
|
||||
:autoresize="autoresize"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsChart",
|
||||
props: {
|
||||
options: Object,
|
||||
theme: [String, Object],
|
||||
initOptions: Object,
|
||||
group: String,
|
||||
autoresize: Boolean,
|
||||
watchShallow: Boolean,
|
||||
manualUpdate: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultInitOptions: this.initOptions
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
this.defaultInitOptions = this.defaultInitOptions || {};
|
||||
// 默认渲染svg
|
||||
// BUG: 渲染svg之后 图上的legend 太多会不显示
|
||||
// if (!this.defaultInitOptions.renderer) {
|
||||
// this.defaultInitOptions.renderer = 'svg';
|
||||
// }
|
||||
},
|
||||
methods: {
|
||||
onClick(params){
|
||||
this.$emit('onClick', params.data)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<span class="box">
|
||||
<el-tooltip class="item" effect="dark" :content="tips" placement="right">
|
||||
<el-button type="primary" size="mini" circle @click="exec()">
|
||||
<font-awesome-icon :icon="['fas', 'plus']" />
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsCreateBox',
|
||||
props: {
|
||||
tips: String,
|
||||
exec: Function
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.box {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
@ -1,136 +0,0 @@
|
||||
<template>
|
||||
<ms-aside-container :enable-aside-hidden="false" :width="width + 'px'">
|
||||
<div class="title-bar" :style="{'height': titleBarHeight + 'px'}">
|
||||
<slot name="title">
|
||||
<span :style="{'line-height': titleBarHeight - 10 + 'px'}" class="title-left">
|
||||
{{title}}
|
||||
</span>
|
||||
<span :style="{'line-height': titleBarHeight - 10 + 'px'}" class="title-right">
|
||||
<i class="el-icon-plus" @click="addFuc"/>
|
||||
</span>
|
||||
</slot>
|
||||
</div>
|
||||
<div :style="{'height': itemBarHeight + 'px'}" v-for="(item, index) in data" :key="index" class="item-bar" @click="itemSelected(index, item)" :class="{'item-selected' : index == selectIndex}">
|
||||
<input class="item-input" :style="{'height': itemBarHeight - 12 + 'px', 'line-height': itemBarHeight - 12 + 'px', 'width': width - 90 + 'px'}" v-model="item.name" :placeholder="$t('commons.input_content')"/>
|
||||
<span :style="{'line-height': itemBarHeight - 10 + 'px'}" class="item-right">
|
||||
<i v-for="(operator, operatorIndex) in itemOperators" :key="operatorIndex" :class="operator.icon" @click.stop="operator.func(item, index)"/>
|
||||
</span>
|
||||
</div>
|
||||
</ms-aside-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsAsideContainer from "./MsAsideContainer";
|
||||
|
||||
export default {
|
||||
name: "MsAsideItem",
|
||||
components: {MsAsideContainer},
|
||||
data() {
|
||||
return {
|
||||
selectIndex: -1
|
||||
}
|
||||
},
|
||||
props: {
|
||||
width: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
titleBarHeight: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
itemBarHeight: {
|
||||
type: Number,
|
||||
default: 35
|
||||
},
|
||||
title: String,
|
||||
data: Array,
|
||||
deleteFuc: Function,
|
||||
addFuc: Function,
|
||||
itemOperators: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [
|
||||
{
|
||||
icon: 'el-icon-delete',
|
||||
func: this.deleteFuc
|
||||
}
|
||||
];
|
||||
}
|
||||
},
|
||||
enableAsideHidden: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
itemSelected(index, item) {
|
||||
this.selectIndex = index;
|
||||
this.$emit('itemSelected', item);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.ms-aside-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.title-bar {
|
||||
width: 100%;
|
||||
background: #e9ebef;
|
||||
padding: 5px 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.item-bar {
|
||||
width: 100%;
|
||||
background: #F9F9F9;
|
||||
padding: 5px 10px;
|
||||
box-sizing: border-box;
|
||||
border: solid 1px #e6e6e6;
|
||||
}
|
||||
|
||||
.item-bar:hover .item-right {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.title-right,.item-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.item-right i {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
color: #409EFF;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.item-selected {
|
||||
background: #ECF5FF;
|
||||
border-left: solid #409EFF 5px;
|
||||
}
|
||||
|
||||
.item-selected .item-right {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.item-input {
|
||||
border: hidden;
|
||||
display: inline;
|
||||
background-color:rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
.item-input:focus{
|
||||
outline:none;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,112 +0,0 @@
|
||||
<template>
|
||||
<editor v-model="formatData" :lang="mode" @init="editorInit" :theme="theme" :height="height"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {formatHtml, formatJson, formatXml} from "../../../../common/js/format-utils";
|
||||
import toDiffableHtml from 'diffable-html';
|
||||
|
||||
export default {
|
||||
name: "MsCodeEdit",
|
||||
components: { editor: require('vue2-ace-editor')},
|
||||
data() {
|
||||
return {
|
||||
formatData: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
height: [String, Number],
|
||||
data: {
|
||||
type: String
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
default() {
|
||||
return 'chrome'
|
||||
}
|
||||
},
|
||||
init: {
|
||||
type: Function
|
||||
},
|
||||
enableFormat: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default() {
|
||||
return 'text';
|
||||
}
|
||||
},
|
||||
modes: {
|
||||
type: Array,
|
||||
default() {
|
||||
return ['text', 'json', 'xml', 'html'];
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.data) {
|
||||
this.formatData = "";
|
||||
}
|
||||
this.format();
|
||||
},
|
||||
watch: {
|
||||
formatData() {
|
||||
this.$emit('update:data', this.formatData);
|
||||
},
|
||||
mode() {
|
||||
this.format();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editorInit: function (editor) {
|
||||
require('brace/ext/language_tools') //language extension prerequsite...
|
||||
this.modes.forEach(mode => {
|
||||
require('brace/mode/' + mode); //language
|
||||
});
|
||||
require('brace/theme/' + this.theme)
|
||||
require('brace/snippets/javascript') //snippet
|
||||
if (this.readOnly) {
|
||||
editor.setReadOnly(true);
|
||||
}
|
||||
if (this.init) {
|
||||
this.init(editor);
|
||||
}
|
||||
},
|
||||
format() {
|
||||
if (this.enableFormat) {
|
||||
if (this.data) {
|
||||
switch (this.mode) {
|
||||
case 'json':
|
||||
this.formatData = formatJson(this.data);
|
||||
break;
|
||||
case 'html':
|
||||
this.formatData = toDiffableHtml(this.data);
|
||||
break;
|
||||
case 'xml':
|
||||
this.formatData = formatXml(this.data);
|
||||
break;
|
||||
default:
|
||||
this.formatData = this.data;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.formatData = this.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,101 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="title"
|
||||
:visible.sync="dialogVisible"
|
||||
class="delete-confirm"
|
||||
>
|
||||
|
||||
<el-row>
|
||||
<el-col>
|
||||
<span>{{ $t('commons.delete_confirm') }}</span>
|
||||
<span class="delete-tip"> DELETE-{{ record.name || record.title }}</span>
|
||||
<br>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="withTip" class="tip">
|
||||
<span>
|
||||
<slot class="tip" />
|
||||
</span>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="15">
|
||||
<el-input v-model="value" :placeholder="$t('commons.input_content')" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{ $t('commons.confirm') }}</el-button>
|
||||
</span>
|
||||
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsDeleteConfirm',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$t('commons.title')
|
||||
}
|
||||
},
|
||||
withTip: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
value: '',
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(record) {
|
||||
this.dialogVisible = true
|
||||
this.value = ''
|
||||
this.record = record
|
||||
},
|
||||
confirm() {
|
||||
if (this.value.trim() !== 'DELETE-' + (this.record.name || this.record.title)) {
|
||||
this.$warning(this.$t('commons.incorrect_input'))
|
||||
return
|
||||
}
|
||||
this.$emit('delete', this.record)
|
||||
this.dialogVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.delete-confirm >>> .el-dialog {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.delete-confirm .el-dialog:first-child {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.delete-confirm .el-row:first-child {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.delete-tip {
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tip {
|
||||
margin-bottom: 20px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,52 +0,0 @@
|
||||
<template>
|
||||
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button v-if="isShowValidate" type="warning" @click="validate" @keydown.enter.native.prevent>{{ $t('commons.validate') }}</el-button>
|
||||
<el-button type="primary" :disabled="disabled" @click="confirm" @keydown.enter.native.prevent>{{ $t('commons.confirm') }}</el-button>
|
||||
<el-button v-if="isShow" type="primary" @click="saveAsEdit" @keydown.enter.native.prevent>{{ title }}</el-button>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsDialogFooter',
|
||||
props: {
|
||||
isShow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isShowValidate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
this.$emit('cancel')
|
||||
},
|
||||
validate() {
|
||||
this.$emit('validate')
|
||||
},
|
||||
confirm() {
|
||||
this.$emit('confirm')
|
||||
},
|
||||
saveAsEdit() {
|
||||
this.$emit('saveAsEdit')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,223 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" id="ms-drawer" class="ms-drawer" :class="directionStyle" :style="{width: w + 'px', height: h + 'px'}" ref="msDrawer">
|
||||
|
||||
<ms-bottom2-top-drag-bar v-if="direction == 'bottom'"/>
|
||||
|
||||
<ms-right2-left-drag-bar v-if="direction == 'right'"/>
|
||||
|
||||
<div class="ms-drawer-header">
|
||||
<slot name="header"></slot>
|
||||
<i v-if="isShowClose" class="el-icon-close" @click="close"/>
|
||||
<font-awesome-icon v-if="!isFullScreen && showFullScreen" class="alt-ico" :icon="['fa', 'expand-alt']" size="lg" @click="fullScreen"/>
|
||||
<font-awesome-icon v-if="isFullScreen && showFullScreen" class="alt-ico" :icon="['fa', 'compress-alt']" size="lg" @click="unFullScreen"/>
|
||||
</div>
|
||||
<div class="ms-drawer-body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
<ms-left2-right-drag-bar v-if="direction == 'left'"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsRight2LeftDragBar from "./dragbar/MsRight2LeftDragBar";
|
||||
import MsLeft2RightDragBar from "./dragbar/MsLeft2RightDragBar";
|
||||
import MsBottom2TopDragBar from "./dragbar/MsBottom2TopDragBar";
|
||||
export default {
|
||||
name: "MsDrawer",
|
||||
components: {MsBottom2TopDragBar, MsLeft2RightDragBar, MsRight2LeftDragBar},
|
||||
data() {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 100,
|
||||
h: 100,
|
||||
directionStyle: 'left-style',
|
||||
dragBarDirection: 'vertical',
|
||||
isFullScreen: false,
|
||||
originalW: 100,
|
||||
originalH: 100,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
direction: {
|
||||
type: String,
|
||||
default() {
|
||||
return "left";
|
||||
}
|
||||
},
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default() {
|
||||
return 40;
|
||||
}
|
||||
},
|
||||
showFullScreen: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
isShowClose: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
// todo 其他方向待优化
|
||||
switch (this.direction) {
|
||||
case 'left':
|
||||
this.w = this.getWidthPercentage(this.size);
|
||||
this.h = this.getHeightPercentage(100);
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.directionStyle = 'left-style';
|
||||
this.dragBarDirection = 'horizontal';
|
||||
break;
|
||||
case 'right':
|
||||
this.w = this.getWidthPercentage(this.size);
|
||||
this.h = this.getHeightPercentage(100);
|
||||
this.x = document.body.clientWidth - this.w;
|
||||
this.y = 0;
|
||||
this.directionStyle = 'right-style';
|
||||
this.dragBarDirection = 'horizontal';
|
||||
break;
|
||||
case 'top':
|
||||
this.w = this.getWidthPercentage(100);
|
||||
this.h = this.getHeightPercentage(this.size);
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.directionStyle = 'top-style';
|
||||
this.dragBarDirection = 'vertical';
|
||||
break;
|
||||
case 'bottom':
|
||||
this.w = this.getWidthPercentage(100);
|
||||
this.h = this.getHeightPercentage(this.size);
|
||||
this.x = 0;
|
||||
this.y = document.body.clientHeight - this.h;
|
||||
this.directionStyle = 'bottom-style';
|
||||
this.dragBarDirection = 'vertical';
|
||||
break;
|
||||
}
|
||||
},
|
||||
getWidthPercentage(per) {
|
||||
return document.body.clientWidth * per / 100.0;
|
||||
},
|
||||
getHeightPercentage(per) {
|
||||
return document.body.clientHeight * per / 100.0;
|
||||
},
|
||||
fullScreen() {
|
||||
this.originalW = this.w;
|
||||
this.originalH = this.h;
|
||||
this.w = document.body.clientWidth;
|
||||
this.h = document.body.clientHeight;
|
||||
this.isFullScreen = true;
|
||||
},
|
||||
unFullScreen() {
|
||||
this.w = this.originalW;
|
||||
this.h = this.originalH;
|
||||
this.isFullScreen = false;
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.ms-drawer {
|
||||
background-color: white;
|
||||
border: 1px #DCDFE6 solid;
|
||||
-webkit-box-shadow: 0 8px 10px -5px rgba(0,0,0,.2), 0 16px 24px 2px rgba(0,0,0,.14), 0 6px 30px 5px rgba(0,0,0,.12);
|
||||
box-shadow: 0 8px 10px -5px rgba(0,0,0,.2), 0 16px 24px 2px rgba(0,0,0,.14), 0 6px 30px 5px rgba(0,0,0,.12);
|
||||
z-index: 999 !important;
|
||||
position: fixed;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.left-style {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.right-style {
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.top-style {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.bottom-style {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-top: 5px;
|
||||
}
|
||||
|
||||
.ms-drawer-body {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.ms-drawer-header {
|
||||
z-index: 999;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bottom-style .ms-drawer-header {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.el-icon-close {
|
||||
position: absolute;
|
||||
font-size: 20px;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.bottom-style .el-icon-close {
|
||||
right: 10px;
|
||||
top: 13px;
|
||||
}
|
||||
|
||||
.right-style .el-icon-close {
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.el-icon-close:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.alt-ico {
|
||||
position: absolute;
|
||||
font-size: 15px;
|
||||
right: 40px;
|
||||
top: 15px;
|
||||
color: #8c939d;
|
||||
}
|
||||
|
||||
.alt-ico:hover {
|
||||
color: black;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<el-dropdown @command="handleCommand" class="ms-dropdown">
|
||||
<slot>
|
||||
<span class="el-dropdown-link">
|
||||
{{currentCommand}}
|
||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
</slot>
|
||||
<el-dropdown-menu slot="dropdown" chang>
|
||||
<el-dropdown-item v-for="(command, index) in commands" :key="index" :command="command">
|
||||
{{command}}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsDropdown",
|
||||
data() {
|
||||
return {
|
||||
currentCommand: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
commands: {
|
||||
type: Array
|
||||
},
|
||||
defaultCommand: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.defaultCommand) {
|
||||
this.currentCommand = this.defaultCommand;
|
||||
} else if (this.commands && this.commands.length > 0) {
|
||||
this.currentCommand = this.commands [0];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleCommand(command) {
|
||||
this.currentCommand = command;
|
||||
this.$emit('command', command);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-dropdown-link {
|
||||
cursor: pointer;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
.el-icon-arrow-down {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<el-tooltip class="instructions-icon" :effect="effect" :placement="placement">
|
||||
<template v-slot:content>
|
||||
{{content}}
|
||||
</template>
|
||||
<i :style="{'font-size': size + 'px'}" class="el-icon-info"></i>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsInstructionsIcon",
|
||||
props: {
|
||||
content: String,
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'el-icon-question'
|
||||
},
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'top-start'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
effect: {
|
||||
type: String,
|
||||
default: 'dark'
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: '16'
|
||||
},
|
||||
isTesterPermission: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-icon-info {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.el-icon-info:hover {
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,165 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="jsoneditor-vue" style="height: 400px"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import 'jsoneditor/dist/jsoneditor.css';
|
||||
import JsonEditor from 'jsoneditor'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: [String, Number, Object, Array],
|
||||
expandedOnStart: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: "code"
|
||||
},
|
||||
modes: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return ["code"];
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
immediate: true,
|
||||
async handler(val) {
|
||||
if (!this.internalChange) {
|
||||
await this.setEditor(val);
|
||||
this.expandAll();
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
error: false,
|
||||
json: JSON.parse(this.value ? this.value : "{}"),
|
||||
internalChange: false,
|
||||
expandedModes: ["tree", "view", "form"],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
let self = this;
|
||||
let options = {
|
||||
mode: this.mode,
|
||||
modes: this.modes, // allowed modes
|
||||
onChange() {
|
||||
try {
|
||||
let json = self.editor.get();
|
||||
self.json = json;
|
||||
self.$emit("json-change", json);
|
||||
self.internalChange = true;
|
||||
self.$emit("input", json);
|
||||
self.$nextTick(function () {
|
||||
self.internalChange = false;
|
||||
});
|
||||
} catch (e) {
|
||||
self.$emit("has-error", e);
|
||||
}
|
||||
},
|
||||
onModeChange() {
|
||||
self.expandAll();
|
||||
},
|
||||
onError(error) {
|
||||
self.$emit("onError", error);
|
||||
}
|
||||
};
|
||||
this.editor = new JsonEditor(
|
||||
this.$el.querySelector(".jsoneditor-vue"),
|
||||
options,
|
||||
this.json
|
||||
);
|
||||
},
|
||||
methods: {
|
||||
expandAll() {
|
||||
if (
|
||||
this.expandedOnStart &&
|
||||
this.expandedModes.includes(this.editor.getMode())
|
||||
) {
|
||||
this.editor.expandAll();
|
||||
}
|
||||
},
|
||||
async setEditor(value) {
|
||||
if (this.editor) this.editor.set(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ace_line_group {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.json-editor-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.json-editor-container .tree-mode {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.json-editor-container .code-mode {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.jsoneditor-btns {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.jsoneditor-vue .jsoneditor-outer {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.jsoneditor-vue div.jsoneditor-tree {
|
||||
min-height: 350px;
|
||||
}
|
||||
|
||||
.json-save-btn {
|
||||
background-color: #20A0FF;
|
||||
border: none;
|
||||
color: #fff;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.json-save-btn:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.json-save-btn[disabled] {
|
||||
background-color: #1D8CE0;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/deep/ .jsoneditor-poweredBy {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/deep/ .jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected {
|
||||
background-color: #1E9FFB;
|
||||
}
|
||||
|
||||
/deep/ jsoneditor-tree {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/deep/ .jsoneditor {
|
||||
border-color: #1E9FFB;
|
||||
border-radius: 3px;
|
||||
}
|
||||
</style>
|
@ -1,124 +0,0 @@
|
||||
<template>
|
||||
|
||||
<div>
|
||||
<ms-chart :options="options" @onClick="onClick">
|
||||
</ms-chart>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import MsChart from "@/business/components/common/chart/MsChart";
|
||||
|
||||
export default {
|
||||
name: "MsPieChart",
|
||||
components: {MsChart},
|
||||
mounted() {
|
||||
this.getDataNamesByData();
|
||||
},
|
||||
watch: {
|
||||
data() {
|
||||
this.getDataNamesByData();
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
title: {
|
||||
text: this.text,
|
||||
subtext: this.subtext,
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 20,
|
||||
data: this.dataNames
|
||||
},
|
||||
series : [
|
||||
{
|
||||
name: this.name,
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
// roseType: 'angle',
|
||||
data: this.data,
|
||||
animation: false,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
formatter: '{b}:{c}'
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
dataNames: ['示例1','示例2','示例3']
|
||||
}
|
||||
},
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
default: '图表名称'
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: '数据名称'
|
||||
},
|
||||
subtext: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [
|
||||
{
|
||||
value:235, name:'示例1',
|
||||
itemStyle: {
|
||||
color: '#67C23A'
|
||||
}
|
||||
},
|
||||
{
|
||||
value:274, name:'示例2',
|
||||
itemStyle: {
|
||||
color: '#E6A23C'
|
||||
}
|
||||
},
|
||||
{
|
||||
value:274, name:'示例3',
|
||||
itemStyle: {
|
||||
color: '#F56C6C'
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDataNamesByData() {
|
||||
let itemNames = [];
|
||||
this.data.forEach(item => {
|
||||
itemNames.push(item.name);
|
||||
});
|
||||
this.dataNames = itemNames;
|
||||
},
|
||||
onClick(params){
|
||||
this.$emit('onClick', params);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.echarts {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<span class="previous-next-button">
|
||||
<span class="head-right-tip" v-if="index + 1 === list.length">
|
||||
{{ $t('test_track.plan_view.pre_case') }} : {{list[index - 1] ? list[index - 1].name : ''}}
|
||||
</span>
|
||||
<span class="head-right-tip" v-if="index + 1 !== list.length">
|
||||
{{ $t('test_track.plan_view.next_case') }} : {{list[index + 1] ? list[index + 1].name : ''}}
|
||||
</span>
|
||||
|
||||
<el-button plain size="mini" icon="el-icon-arrow-up" :disabled="index + 1 <= 1" @click="handlePre()"/>
|
||||
<span>
|
||||
{{ index + 1 }}/{{ list.length }}
|
||||
</span>
|
||||
<el-button plain size="mini" icon="el-icon-arrow-down" :disabled="index + 1 >= list.length" @click="handleNext()"/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsPreviousNextButton",
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default() {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlePre() {
|
||||
this.$emit('pre');
|
||||
},
|
||||
handleNext() {
|
||||
this.$emit('next');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.head-right-tip {
|
||||
color: darkgrey;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<ms-tag v-for="(role, index) in roles"
|
||||
:key="index"
|
||||
:effect="effect"
|
||||
:type="type"
|
||||
:content="$t('role.' + role.id)"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTag from "./MsTag";
|
||||
|
||||
export default {
|
||||
name: "MsRolesTag",
|
||||
components: {MsTag},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'primary',
|
||||
},
|
||||
roles: {
|
||||
type: Array
|
||||
},
|
||||
effect: {
|
||||
type: String,
|
||||
default: 'dark',
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,132 +0,0 @@
|
||||
<template>
|
||||
<div class="schedule-config">
|
||||
<div>
|
||||
<span class="cron-ico" @click="scheduleEdit">
|
||||
<i class="el-icon-date" size="small"></i>
|
||||
<span class="character">SCHEDULER</span>
|
||||
</span>
|
||||
<el-switch :disabled="!schedule.value || isReadOnly" v-model="schedule.enable" @change="scheduleChange"/>
|
||||
<ms-schedule-edit :is-read-only="isReadOnly" :schedule="schedule" :test-id="testId" :save="save"
|
||||
:custom-validate="customValidate"
|
||||
ref="scheduleEdit"/>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<span>
|
||||
{{ $t('schedule.next_execution_time') }}:
|
||||
<span :class="{'disable-character': !schedule.enable}"
|
||||
v-if="!schedule.enable">{{ $t('schedule.not_set') }}</span>
|
||||
<crontab-result v-if="schedule.enable" :enable-simple-mode="true" :ex="schedule.value" ref="crontabResult"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsScheduleEdit from "./MsScheduleEdit";
|
||||
import CrontabResult from "../cron/CrontabResult";
|
||||
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "MsScheduleConfig",
|
||||
components: {CrontabResult, MsScheduleEdit},
|
||||
data() {
|
||||
return {
|
||||
recentList: [],
|
||||
refreshScheduler: null,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
testId: String,
|
||||
save: Function,
|
||||
schedule: {},
|
||||
checkOpen: {
|
||||
type: Function,
|
||||
default() {
|
||||
return {
|
||||
checkOpen() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
customValidate: {
|
||||
type: Function,
|
||||
default: defaultCustomValidate
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scheduleEdit() {
|
||||
if (!this.checkOpen()) {
|
||||
return;
|
||||
}
|
||||
this.$refs.scheduleEdit.open();
|
||||
},
|
||||
scheduleChange() {
|
||||
this.$emit('scheduleChange');
|
||||
},
|
||||
flashResultList() {
|
||||
if (this.$refs.crontabResult) {
|
||||
this.$refs.crontabResult.expressionChange();
|
||||
}
|
||||
},
|
||||
cancelRefresh() {
|
||||
if (this.refreshScheduler) {
|
||||
clearInterval(this.refreshScheduler);
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.cancelRefresh();
|
||||
},
|
||||
watch: {
|
||||
schedule() {
|
||||
if (this.schedule.enable) {
|
||||
this.refreshScheduler = setInterval(this.flashResultList, 2000);
|
||||
} else {
|
||||
this.cancelRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.schedule-config {
|
||||
float: right;
|
||||
width: 250px;
|
||||
height: 15px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.el-icon-date {
|
||||
font-size: 20px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.character {
|
||||
font-weight: bold;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.disable-character {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.el-switch {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.cron-ico {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,216 +0,0 @@
|
||||
<template>
|
||||
<el-dialog :close-on-click-modal="false" width="60%" class="schedule-edit" :visible.sync="dialogVisible"
|
||||
@close="close">
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs v-model="activeName">
|
||||
|
||||
<el-tab-pane :label="$t('schedule.edit_timer_task')" name="first">
|
||||
<el-form :model="form" :rules="rules" ref="from">
|
||||
<el-form-item
|
||||
prop="cronValue">
|
||||
<el-input :disabled="isReadOnly" v-model="form.cronValue" class="inp"
|
||||
:placeholder="$t('schedule.please_input_cron_expression')"/>
|
||||
<!-- <el-button type="primary" @click="showCronDialog">{{$t('schedule.generate_expression')}}</el-button>-->
|
||||
<el-button :disabled="isReadOnly" type="primary" @click="saveCron">{{
|
||||
$t('commons.save')
|
||||
}}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-link :disabled="isReadOnly" type="primary" @click="showCronDialog">
|
||||
{{ $t('schedule.generate_expression') }}
|
||||
</el-link>
|
||||
</el-form-item>
|
||||
<crontab-result :ex="form.cronValue" ref="crontabResult"/>
|
||||
</el-form>
|
||||
<el-dialog width="60%" :title="$t('schedule.generate_expression')" :visible.sync="showCron"
|
||||
:modal="false">
|
||||
<crontab @hide="showCron=false" @fill="crontabFill" :expression="schedule.value"
|
||||
ref="crontab"/>
|
||||
</el-dialog>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('schedule.task_notification')" name="second">
|
||||
<schedule-task-notification :is-tester-permission="isTesterPermission" :test-id="testId"
|
||||
:schedule-receiver-options="scheduleReceiverOptions"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {checkoutTestManagerOrTestUser, getCurrentUser, listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||
import Crontab from "../cron/Crontab";
|
||||
import CrontabResult from "../cron/CrontabResult";
|
||||
import {cronValidate} from "@/common/js/cron";
|
||||
import ScheduleTaskNotification from "../../settings/organization/components/ScheduleTaskNotification";
|
||||
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "MsScheduleEdit",
|
||||
components: {CrontabResult, Crontab, ScheduleTaskNotification},
|
||||
props: {
|
||||
testId: String,
|
||||
save: Function,
|
||||
schedule: {},
|
||||
customValidate: {
|
||||
type: Function,
|
||||
default: defaultCustomValidate
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
watch: {
|
||||
'schedule.value'() {
|
||||
this.form.cronValue = this.schedule.value;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const validateCron = (rule, cronValue, callback) => {
|
||||
let customValidate = this.customValidate(this.getIntervalTime());
|
||||
if (!cronValue) {
|
||||
callback(new Error(this.$t('commons.input_content')));
|
||||
} else if (!cronValidate(cronValue)) {
|
||||
callback(new Error(this.$t('schedule.cron_expression_format_error')));
|
||||
}
|
||||
// else if(!this.intervalShortValidate()) {
|
||||
// callback(new Error(this.$t('schedule.cron_expression_interval_short_error')));
|
||||
// }
|
||||
else if (!customValidate.pass) {
|
||||
callback(new Error(customValidate.info));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
scheduleReceiverOptions: [],
|
||||
operation: true,
|
||||
dialogVisible: false,
|
||||
showCron: false,
|
||||
form: {
|
||||
cronValue: ""
|
||||
},
|
||||
activeName: 'first',
|
||||
rules: {
|
||||
cronValue: [{required: true, validator: validateCron, trigger: 'blur'}],
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
currentUser: () => {
|
||||
return getCurrentUser();
|
||||
},
|
||||
initUserList() {
|
||||
let param = {
|
||||
name: '',
|
||||
organizationId: this.currentUser().lastOrganizationId
|
||||
};
|
||||
|
||||
if (this.isTesterPermission) {
|
||||
this.result = this.$post('user/org/member/list/all', param, response => {
|
||||
this.scheduleReceiverOptions = response.data
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
/* handleClick() {
|
||||
if (this.activeName === "second") {
|
||||
this.result = this.$get('/notice/search/message/'+this.testId, response => {
|
||||
this.scheduleTask = response.data;
|
||||
})
|
||||
}
|
||||
},*/
|
||||
buildParam() {
|
||||
let param = {};
|
||||
param.notices = this.tableData
|
||||
param.testId = this.testId
|
||||
return param;
|
||||
},
|
||||
open() {
|
||||
this.initUserList();
|
||||
this.dialogVisible = true;
|
||||
this.form.cronValue = this.schedule.value;
|
||||
listenGoBack(this.close);
|
||||
this.activeName = 'first'
|
||||
},
|
||||
crontabFill(value, resultList) {
|
||||
//确定后回传的值
|
||||
this.form.cronValue = value;
|
||||
this.$refs.crontabResult.resultList = resultList;
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
showCronDialog() {
|
||||
this.showCron = true;
|
||||
},
|
||||
saveCron() {
|
||||
this.$refs['from'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.intervalShortValidate();
|
||||
this.save(this.form.cronValue);
|
||||
this.dialogVisible = false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
saveNotice() {
|
||||
let param = this.buildParam();
|
||||
this.result = this.$post("notice/save", param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
})
|
||||
},
|
||||
close() {
|
||||
this.dialogVisible = false;
|
||||
this.form.cronValue = '';
|
||||
this.$refs['from'].resetFields();
|
||||
if (!this.schedule.value) {
|
||||
this.$refs.crontabResult.resultList = [];
|
||||
}
|
||||
removeGoBackListener(this.close);
|
||||
},
|
||||
intervalShortValidate() {
|
||||
if (this.getIntervalTime() < 3 * 60 * 1000) {
|
||||
// return false;
|
||||
this.$info(this.$t('schedule.cron_expression_interval_short_error'));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
resultListChange() {
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
getIntervalTime() {
|
||||
let resultList = this.$refs.crontabResult.resultList;
|
||||
let time1 = new Date(resultList[0]);
|
||||
let time2 = new Date(resultList[1]);
|
||||
return time2 - time1;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isTesterPermission() {
|
||||
return checkoutTestManagerOrTestUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.inp {
|
||||
width: 50%;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<el-button :disabled="disabled" plain :type="type" :icon="icon" :size="size" @click="exec()">
|
||||
{{ content }}
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { checkoutTestManagerOrTestUser } from '@/metersphere/common/js/utils'
|
||||
|
||||
export default {
|
||||
name: 'MsTableButton',
|
||||
props: {
|
||||
content: String,
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'el-icon-question'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
effect: {
|
||||
type: String,
|
||||
default: 'dark'
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'mini'
|
||||
},
|
||||
isTesterPermission: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
disabled: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.isTesterPermission && !checkoutTestManagerOrTestUser()) {
|
||||
this.disabled = true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
exec() {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-button {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
</style>
|
@ -1,148 +0,0 @@
|
||||
<template>
|
||||
|
||||
<div>
|
||||
<el-row v-if="title" class="table-title" type="flex" justify="space-between" align="middle">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</el-row>
|
||||
<el-row type="flex" justify="space-between" align="middle">
|
||||
<span class="operate-button">
|
||||
<ms-table-button
|
||||
v-if="showCreate"
|
||||
v-permission="permission.add"
|
||||
:is-tester-permission="isTesterPermission"
|
||||
icon="el-icon-circle-plus-outline"
|
||||
:content="createTip"
|
||||
@click="create"
|
||||
/>
|
||||
<ms-table-button
|
||||
v-if="showRun"
|
||||
:is-tester-permission="isTesterPermission"
|
||||
icon="el-icon-video-play"
|
||||
type="primary"
|
||||
:content="runTip"
|
||||
@click="runTest"
|
||||
/>
|
||||
<ms-table-button
|
||||
v-if="showRun"
|
||||
:is-tester-permission="isTesterPermission"
|
||||
icon="el-icon-circle-plus-outline"
|
||||
content="转场景测试"
|
||||
@click="historicalDataUpgrade"
|
||||
/>
|
||||
|
||||
<slot name="button" />
|
||||
</span>
|
||||
<span>
|
||||
<slot name="searchBarBefore" />
|
||||
<ms-table-search-bar :condition.sync="condition" class="search-bar" :tip="tip" @change="search" />
|
||||
<ms-table-adv-search-bar v-if="isCombine" :condition.sync="condition" @search="search" />
|
||||
</span>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTableSearchBar from './MsTableSearchBar'
|
||||
import MsTableButton from './MsTableButton'
|
||||
import MsTableAdvSearchBar from './search/MsTableAdvSearchBar'
|
||||
|
||||
export default {
|
||||
name: 'MsTableHeader',
|
||||
components: { MsTableAdvSearchBar, MsTableSearchBar, MsTableButton },
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$t('commons.name')
|
||||
}
|
||||
},
|
||||
showCreate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showRun: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
condition: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
createTip: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$t('commons.create')
|
||||
}
|
||||
},
|
||||
runTip: {
|
||||
type: String,
|
||||
default: null
|
||||
|
||||
},
|
||||
|
||||
isTesterPermission: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
tip: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$t('commons.search_by_name')
|
||||
}
|
||||
},
|
||||
permission: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
add: []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isCombine() {
|
||||
return this.condition.components !== undefined && this.condition.components.length > 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
search(value) {
|
||||
this.$emit('update:condition', this.condition)
|
||||
this.$emit('search', value)
|
||||
},
|
||||
create() {
|
||||
this.$emit('create')
|
||||
},
|
||||
runTest() {
|
||||
this.$emit('runTest')
|
||||
},
|
||||
historicalDataUpgrade() {
|
||||
this.$emit('historicalDataUpgrade')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.table-title {
|
||||
height: 40px;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.operate-button {
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
width: 240px
|
||||
}
|
||||
|
||||
</style>
|
@ -1,64 +0,0 @@
|
||||
<template>
|
||||
<span>
|
||||
<slot name="front" />
|
||||
<ms-table-operator-button v-permission="permission.edit" :is-tester-permission="isTesterPermission" :tip="tip1" icon="el-icon-edit" @exec="editClick" @click.stop="editClickStop" />
|
||||
<slot name="middle" />
|
||||
<ms-table-operator-button v-permission="permission.del" :is-tester-permission="isTesterPermission" :tip="tip2" icon="el-icon-delete" type="danger" @exec="deleteClick" @click.stop="deleteClickStop" />
|
||||
<slot name="behind" />
|
||||
</span>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTableOperatorButton from './MsTableOperatorButton'
|
||||
export default {
|
||||
name: 'MsTableOperator',
|
||||
components: { MsTableOperatorButton },
|
||||
props: {
|
||||
tip1: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$t('commons.edit')
|
||||
}
|
||||
},
|
||||
tip2: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$t('commons.delete')
|
||||
}
|
||||
},
|
||||
isTesterPermission: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
permission: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
|
||||
edit: [],
|
||||
del: []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editClick() {
|
||||
this.$emit('editClick')
|
||||
},
|
||||
editClickStop() {
|
||||
this.$emit('editClickStop')
|
||||
},
|
||||
deleteClick() {
|
||||
this.$emit('deleteClick')
|
||||
},
|
||||
deleteClickStop() {
|
||||
this.$emit('deleteClickStop')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,64 +0,0 @@
|
||||
<template>
|
||||
<ms-tip-button
|
||||
:disabled="disabled || isReadOnly"
|
||||
:type="type"
|
||||
:tip="tip"
|
||||
:icon="icon"
|
||||
size="mini"
|
||||
circle
|
||||
@click="exec"
|
||||
@clickStop="clickStop"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTipButton from './MsTipButton'
|
||||
import { checkoutTestManagerOrTestUser } from '@/metersphere/common/js/utils'
|
||||
export default {
|
||||
name: 'MsTableOperatorButton',
|
||||
components: { MsTipButton },
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'el-icon-question'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'primary'
|
||||
},
|
||||
tip: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isTesterPermission: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isReadOnly: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.isTesterPermission && !checkoutTestManagerOrTestUser()) {
|
||||
this.isReadOnly = true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
exec() {
|
||||
this.$emit('exec')
|
||||
},
|
||||
clickStop() {
|
||||
this.$emit('clickStop')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
@ -1,43 +0,0 @@
|
||||
<template>
|
||||
<span>
|
||||
<ms-table-operator-button v-for="(btn, index) in buttons" :key="index" :isTesterPermission="isTesterPermission(btn)"
|
||||
:tip="btn.tip" :icon="btn.icon" :type="btn.type"
|
||||
@exec="click(btn)" @click.stop="clickStop(btn)"/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTableOperatorButton from "./MsTableOperatorButton";
|
||||
|
||||
export default {
|
||||
name: "MsTableOperators",
|
||||
components: {MsTableOperatorButton},
|
||||
props: {
|
||||
row: Object,
|
||||
buttons: Array
|
||||
},
|
||||
methods: {
|
||||
click(btn) {
|
||||
if (btn.exec instanceof Function) {
|
||||
btn.exec(this.row);
|
||||
}
|
||||
},
|
||||
clickStop(btn) {
|
||||
if (btn.stop instanceof Function) {
|
||||
btn.stop(this.row);
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isTesterPermission() {
|
||||
return function (btn) {
|
||||
return btn.isTesterPermission !== false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,43 +0,0 @@
|
||||
<template>
|
||||
|
||||
<el-input
|
||||
v-model="condition.name"
|
||||
class="search"
|
||||
type="text"
|
||||
size="small"
|
||||
:placeholder="tip"
|
||||
prefix-icon="el-icon-search"
|
||||
maxlength="60"
|
||||
clearable
|
||||
@change="search"
|
||||
/>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsTableSearchBar',
|
||||
props: {
|
||||
condition: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
tip: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$t('commons.search_by_name')
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
this.$emit('update:condition', this.condition)
|
||||
this.$emit('change')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,30 +0,0 @@
|
||||
<template>
|
||||
<el-tag :type="type" :effect="effect" :color="color" size="mini">{{content}}</el-tag>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsTag",
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'primary',
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
content: {
|
||||
type: String
|
||||
},
|
||||
effect: {
|
||||
type: String,
|
||||
default: 'dark',
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<el-card>
|
||||
<template v-slot:header>
|
||||
<span class="title">{{$t('commons.calendar_heatmap')}}</span>
|
||||
</template>
|
||||
<calendar-heatmap :end-date="endDate" :values="values" :locale="locale"
|
||||
:tooltip-unit="unit"
|
||||
:range-color="colorRange"/>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsTestHeatmap",
|
||||
props: ['values'],
|
||||
data() {
|
||||
return {
|
||||
endDate: (new Date().getTime() + 7*24*60*60*1000),
|
||||
colorRange: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
locale() {
|
||||
return {
|
||||
months: [
|
||||
this.$t('commons.months_1'),
|
||||
this.$t('commons.months_2'),
|
||||
this.$t('commons.months_3'),
|
||||
this.$t('commons.months_4'),
|
||||
this.$t('commons.months_5'),
|
||||
this.$t('commons.months_6'),
|
||||
this.$t('commons.months_7'),
|
||||
this.$t('commons.months_8'),
|
||||
this.$t('commons.months_9'),
|
||||
this.$t('commons.months_10'),
|
||||
this.$t('commons.months_11'),
|
||||
this.$t('commons.months_12')
|
||||
],
|
||||
days: [
|
||||
this.$t('commons.weeks_0'),
|
||||
this.$t('commons.weeks_1'),
|
||||
this.$t('commons.weeks_2'),
|
||||
this.$t('commons.weeks_3'),
|
||||
this.$t('commons.weeks_4'),
|
||||
this.$t('commons.weeks_5'),
|
||||
this.$t('commons.weeks_6')
|
||||
],
|
||||
No: 'No',
|
||||
on: ',',
|
||||
less: 'Less',
|
||||
more: 'More'
|
||||
}
|
||||
},
|
||||
unit() {
|
||||
return this.$t('commons.test_unit')
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-card {
|
||||
height: 370px;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,62 +0,0 @@
|
||||
<template>
|
||||
|
||||
<el-tooltip
|
||||
:content="tip"
|
||||
placement="bottom"
|
||||
:enterable="false"
|
||||
:effect="effect"
|
||||
>
|
||||
<el-button
|
||||
circle
|
||||
:disabled="disabled"
|
||||
:type="type"
|
||||
:icon="icon"
|
||||
:size="size"
|
||||
@click="exec()"
|
||||
@click.stop="clickStop"
|
||||
@keydown.enter.native.prevent
|
||||
/>
|
||||
</el-tooltip>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsTipButton',
|
||||
props: {
|
||||
tip: String,
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'el-icon-question'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
effect: {
|
||||
type: String,
|
||||
default: 'dark'
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'mini'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
exec() {
|
||||
this.$emit('click')
|
||||
},
|
||||
clickStop() {
|
||||
this.$emit('clickStop')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,31 +0,0 @@
|
||||
<template>
|
||||
<div class="report-export">
|
||||
<ms-report-title :title="title" :type="type"/>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsReportTitle from "./MsReportTitle";
|
||||
export default {
|
||||
name: "MsReportExportTemplate",
|
||||
components: {MsReportTitle},
|
||||
props: {title: String, type: String},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.report-export {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.report-title {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.report-export {
|
||||
background: white;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,61 +0,0 @@
|
||||
<template>
|
||||
<div class="clearfix report-title">
|
||||
<div class="report-left">
|
||||
<div class="title">
|
||||
【{{type}}】- {{title}}
|
||||
</div>
|
||||
<div>
|
||||
<span class="time">{{new Date() | timestampFormatDate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="report-right">
|
||||
<img class="logo" src="@/assets/logo-MeterSphere.png">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsReportTitle",
|
||||
props: {title: String, type: String},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.report-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.report-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
vertical-align: middle
|
||||
}
|
||||
|
||||
|
||||
.report-left {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.time {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
@ -1,168 +0,0 @@
|
||||
<template>
|
||||
<span class="adv-search-bar">
|
||||
<el-link v-if="showLink" type="primary" @click="open">{{ $t('commons.adv_search.title') }}</el-link>
|
||||
<el-dialog
|
||||
:title="$t('commons.adv_search.combine')"
|
||||
:visible.sync="visible"
|
||||
custom-class="adv-dialog"
|
||||
:append-to-body="true"
|
||||
>
|
||||
<div>
|
||||
<div class="search-items">
|
||||
<component
|
||||
:is="component.name"
|
||||
v-for="(component, index) in config.components"
|
||||
:key="index"
|
||||
class="search-item"
|
||||
:component="component"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<template v-slot:footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="reset">{{ $t('commons.adv_search.reset') }}</el-button>
|
||||
<el-button type="primary" @click="search">{{ $t('commons.adv_search.search') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import components from './search-components'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
export default {
|
||||
components: { ...components },
|
||||
name: 'MsTableAdvSearchBar',
|
||||
props: {
|
||||
condition: Object,
|
||||
showLink: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
config: this.init()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const config = cloneDeep(this.condition)
|
||||
config.components.forEach(component => {
|
||||
const operator = component.operator.value
|
||||
component.operator.value = operator === undefined ? component.operator.options[0].value : operator
|
||||
})
|
||||
return config
|
||||
},
|
||||
search() {
|
||||
const condition = {}
|
||||
this.config.components.forEach(component => {
|
||||
const operator = component.operator.value
|
||||
const value = component.value
|
||||
if (Array.isArray(value)) {
|
||||
if (value.length > 0) {
|
||||
condition[component.key] = {
|
||||
operator: operator,
|
||||
value: value
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
condition[component.key] = {
|
||||
operator: operator,
|
||||
value: value
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 清除name
|
||||
if (this.condition.name) this.condition.name = undefined
|
||||
// 添加组合条件
|
||||
this.condition.combine = condition
|
||||
this.$emit('update:condition', this.condition)
|
||||
this.$emit('search', condition)
|
||||
this.visible = false
|
||||
},
|
||||
reset() {
|
||||
const source = this.condition.components
|
||||
this.config.components.forEach((component, index) => {
|
||||
if (component.operator.value !== undefined) {
|
||||
const operator = source[index].operator.value
|
||||
component.operator.value = operator === undefined ? component.operator.options[0].value : operator
|
||||
}
|
||||
if (component.value !== undefined) {
|
||||
component.value = source[index].value
|
||||
}
|
||||
})
|
||||
this.condition.combine = undefined
|
||||
this.$emit('update:condition', this.condition)
|
||||
this.$emit('search')
|
||||
},
|
||||
open() {
|
||||
this.visible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@media only screen and (min-width: 1870px) {
|
||||
.el-dialog.adv-dialog {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1650px) and (max-width: 1869px) {
|
||||
.el-dialog.adv-dialog {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1470px) and (max-width: 1649px) {
|
||||
.el-dialog.adv-dialog {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1469px) {
|
||||
.el-dialog.adv-dialog {
|
||||
width: 70%;
|
||||
min-width: 695px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.adv-search-bar {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.search-items {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1469px) {
|
||||
.search-item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1470px) {
|
||||
.search-item {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.search-item {
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
@ -1,73 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="search-label">{{ $t(component.label) }}</div>
|
||||
|
||||
<el-select
|
||||
v-model="component.operator.value"
|
||||
class="search-operator"
|
||||
:placeholder="$t('commons.please_select')"
|
||||
size="small"
|
||||
v-bind="component.operator.props"
|
||||
@change="change"
|
||||
@input="input"
|
||||
>
|
||||
<el-option v-for="o in operators" :key="o.value" :label="$t(o.label)" :value="o.value" />
|
||||
</el-select>
|
||||
|
||||
<div v-if="showContent" class="search-content">
|
||||
<slot :component="component" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsTableSearchComponent',
|
||||
props: ['component'],
|
||||
data() {
|
||||
return {
|
||||
operators: this.component.operator.options || []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showContent() {
|
||||
if (this.component.isShow) {
|
||||
return this.component.isShow(this.component.operator.value)
|
||||
}
|
||||
return true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
change(value) {
|
||||
if (this.component.operator.change) {
|
||||
this.component.operator.change(this.component, value)
|
||||
}
|
||||
this.$emit('change', value)
|
||||
},
|
||||
input(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.search-label {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
box-sizing: border-box;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.search-operator {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.search-content {
|
||||
display: inline-block;
|
||||
padding: 0 5px 0 10px;
|
||||
width: calc(100% - 240px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
@ -1,56 +0,0 @@
|
||||
<template>
|
||||
<ms-table-search-component v-model="component.operator.value" :component="component">
|
||||
<template v-slot="scope">
|
||||
<el-date-picker
|
||||
:key="type"
|
||||
v-model="scope.component.value"
|
||||
v-bind="scope.component.props"
|
||||
:placeholder="$t('commons.date.select_date')"
|
||||
size="small"
|
||||
:type="type"
|
||||
value-format="timestamp"
|
||||
:range-separator="$t('commons.date.range_separator')"
|
||||
:start-placeholder="$t('commons.date.start_date')"
|
||||
:end-placeholder="$t('commons.date.end_date')"
|
||||
/>
|
||||
</template>
|
||||
</ms-table-search-component>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTableSearchComponent from './MsTableSearchComponet'
|
||||
import { OPERATORS } from './search-components'
|
||||
|
||||
export default {
|
||||
name: 'MsTableSearchDatePicker',
|
||||
components: { MsTableSearchComponent },
|
||||
props: ['component'],
|
||||
computed: {
|
||||
type() {
|
||||
if (this.component.operator.value === OPERATORS.BETWEEN.value) {
|
||||
return 'daterange'
|
||||
} else {
|
||||
return 'date'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
change(value) {
|
||||
if (value === OPERATORS.BETWEEN.value) {
|
||||
if (!Array.isArray(this.component.value)) {
|
||||
this.component.value = []
|
||||
}
|
||||
} else {
|
||||
if (Array.isArray(this.component.value)) {
|
||||
this.component.value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,56 +0,0 @@
|
||||
<template>
|
||||
<ms-table-search-component v-model="component.operator.value" :component="component" @change="change">
|
||||
<template v-slot="scope">
|
||||
<el-date-picker
|
||||
:key="type"
|
||||
v-model="scope.component.value"
|
||||
v-bind="scope.component.props"
|
||||
:placeholder="$t('commons.date.select_date_time')"
|
||||
size="small"
|
||||
:type="type"
|
||||
value-format="timestamp"
|
||||
:range-separator="$t('commons.date.range_separator')"
|
||||
:start-placeholder="$t('commons.date.start_date_time')"
|
||||
:end-placeholder="$t('commons.date.end_date_time')"
|
||||
/>
|
||||
</template>
|
||||
</ms-table-search-component>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTableSearchComponent from './MsTableSearchComponet'
|
||||
import { OPERATORS } from './search-components'
|
||||
|
||||
export default {
|
||||
name: 'MsTableSearchDateTimePicker',
|
||||
components: { MsTableSearchComponent },
|
||||
props: ['component'],
|
||||
computed: {
|
||||
type() {
|
||||
if (this.component.operator.value === OPERATORS.BETWEEN.value) {
|
||||
return 'datetimerange'
|
||||
} else {
|
||||
return 'datetime'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
change(value) {
|
||||
if (value === OPERATORS.BETWEEN.value) {
|
||||
if (!Array.isArray(this.component.value)) {
|
||||
this.component.value = []
|
||||
}
|
||||
} else {
|
||||
if (Array.isArray(this.component.value)) {
|
||||
this.component.value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<ms-table-search-component v-model="component.operator.value" :component="component">
|
||||
<template v-slot="scope">
|
||||
<el-input
|
||||
v-model="scope.component.value"
|
||||
v-bind="props"
|
||||
:placeholder="$t('commons.input_content')"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
</ms-table-search-component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTableSearchComponent from './MsTableSearchComponet'
|
||||
|
||||
export default {
|
||||
name: 'MsTableSearchInput',
|
||||
components: { MsTableSearchComponent },
|
||||
props: ['component'],
|
||||
data() {
|
||||
return {
|
||||
props: {
|
||||
maxlength: '60',
|
||||
showWordLimit: true,
|
||||
...this.component.props
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<ms-table-search-component v-model="component.operator.value" :component="component">
|
||||
<template v-slot="scope">
|
||||
<el-select
|
||||
v-model="scope.component.value"
|
||||
:placeholder="$t('commons.please_select')"
|
||||
size="small"
|
||||
filterable
|
||||
v-bind="scope.component.props"
|
||||
class="search-select"
|
||||
>
|
||||
<el-option v-for="op in options" :key="op.value" :label="label(op)" :value="op.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</ms-table-search-component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTableSearchComponent from './MsTableSearchComponet'
|
||||
|
||||
export default {
|
||||
name: 'MsTableSearchSelect',
|
||||
components: { MsTableSearchComponent },
|
||||
props: ['component'],
|
||||
data() {
|
||||
return {
|
||||
options: !(this.component.options instanceof Array) ? [] : this.component.options || []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
label() {
|
||||
return op => {
|
||||
if (this.component.options.showLabel) {
|
||||
return this.component.options.showLabel(op)
|
||||
}
|
||||
return op.label.indexOf('.') !== -1 ? this.$t(op.label) : op.label
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (!(this.component.options instanceof Array) && this.component.options.url) {
|
||||
this.$get(this.component.options.url, response => {
|
||||
if (response.data) {
|
||||
response.data.forEach(item => {
|
||||
this.options.push({
|
||||
label: item[this.component.options.labelKey],
|
||||
value: item[this.component.options.valueKey]
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.search-select {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -1,463 +0,0 @@
|
||||
import MsTableSearchInput from './MsTableSearchInput'
|
||||
import MsTableSearchDateTimePicker from './MsTableSearchDateTimePicker'
|
||||
import MsTableSearchDatePicker from './MsTableSearchDatePicker'
|
||||
import MsTableSearchSelect from './MsTableSearchSelect'
|
||||
|
||||
export default {
|
||||
MsTableSearchInput, MsTableSearchDatePicker, MsTableSearchDateTimePicker, MsTableSearchSelect
|
||||
}
|
||||
|
||||
export const OPERATORS = {
|
||||
LIKE: {
|
||||
label: 'commons.adv_search.operators.like',
|
||||
value: 'like'
|
||||
},
|
||||
NOT_LIKE: {
|
||||
label: 'commons.adv_search.operators.not_like',
|
||||
value: 'not like'
|
||||
},
|
||||
IN: {
|
||||
label: 'commons.adv_search.operators.in',
|
||||
value: 'in'
|
||||
},
|
||||
NOT_IN: {
|
||||
label: 'commons.adv_search.operators.not_in',
|
||||
value: 'not in'
|
||||
},
|
||||
GT: {
|
||||
label: 'commons.adv_search.operators.gt',
|
||||
value: 'gt'
|
||||
},
|
||||
GE: {
|
||||
label: 'commons.adv_search.operators.ge',
|
||||
value: 'ge'
|
||||
},
|
||||
LT: {
|
||||
label: 'commons.adv_search.operators.lt',
|
||||
value: 'lt'
|
||||
},
|
||||
LE: {
|
||||
label: 'commons.adv_search.operators.le',
|
||||
value: 'le'
|
||||
},
|
||||
EQ: {
|
||||
label: 'commons.adv_search.operators.equals',
|
||||
value: 'eq'
|
||||
},
|
||||
BETWEEN: {
|
||||
label: 'commons.adv_search.operators.between',
|
||||
value: 'between'
|
||||
},
|
||||
CURRENT_USER: {
|
||||
label: 'commons.adv_search.operators.current_user',
|
||||
value: 'current user'
|
||||
}
|
||||
}
|
||||
|
||||
export const NAME = {
|
||||
key: 'name', // 返回结果Map的key
|
||||
name: 'MsTableSearchInput', // Vue控件名称
|
||||
label: 'commons.name', // 显示名称
|
||||
operator: { // 运算符设置
|
||||
value: OPERATORS.LIKE.value, // 如果未设置value初始值,则value初始值为options[0]
|
||||
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE] // 运算符候选项
|
||||
}
|
||||
}
|
||||
|
||||
export const UPDATE_TIME = {
|
||||
key: 'updateTime',
|
||||
name: 'MsTableSearchDateTimePicker',
|
||||
label: 'commons.update_time',
|
||||
operator: {
|
||||
options: [OPERATORS.BETWEEN, OPERATORS.GT, OPERATORS.GE, OPERATORS.LT, OPERATORS.LE, OPERATORS.EQ]
|
||||
}
|
||||
}
|
||||
export const PROJECT_NAME = {
|
||||
key: 'projectName',
|
||||
name: 'MsTableSearchInput',
|
||||
label: 'commons.adv_search.project',
|
||||
operator: {
|
||||
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE]
|
||||
}
|
||||
}
|
||||
export const TEST_NAME = {
|
||||
key: 'testName',
|
||||
name: 'MsTableSearchInput',
|
||||
label: 'commons.adv_search.test',
|
||||
operator: {
|
||||
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE]
|
||||
}
|
||||
}
|
||||
export const TEST_PLAN_NAME = {
|
||||
key: 'testPlanName',
|
||||
name: 'MsTableSearchInput',
|
||||
label: 'test_track.report.list.test_plan',
|
||||
operator: {
|
||||
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE]
|
||||
}
|
||||
}
|
||||
export const CREATE_TIME = {
|
||||
key: 'createTime',
|
||||
name: 'MsTableSearchDateTimePicker',
|
||||
label: 'commons.create_time',
|
||||
operator: {
|
||||
options: [OPERATORS.BETWEEN, OPERATORS.GT, OPERATORS.GE, OPERATORS.LT, OPERATORS.LE, OPERATORS.EQ]
|
||||
}
|
||||
}
|
||||
|
||||
export const STATUS = {
|
||||
key: 'status',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'commons.status',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ label: 'Saved', value: 'Saved' }, { label: 'Starting', value: 'Starting' },
|
||||
{ label: 'Running', value: 'Running' }, { label: 'Reporting', value: 'Reporting' },
|
||||
{ label: 'Completed', value: 'Completed' }, { label: 'Error', value: 'Error' },
|
||||
{ label: 'Success', value: 'Success' }
|
||||
],
|
||||
props: { // 尾部控件的props,一般为element ui控件的props
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const API_STATUS = {
|
||||
key: 'status',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'commons.status',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ value: 'Prepare', label: '未开始' },
|
||||
{ value: 'Underway', label: '进行中' },
|
||||
{ value: 'Completed', label: '已完成' }
|
||||
],
|
||||
props: { // 尾部控件的props,一般为element ui控件的props
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
export const API_CASE_PRIORITY = {
|
||||
key: 'priority',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.case.priority',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ value: 'P0', label: 'P0' },
|
||||
{ value: 'P1', label: 'P1' },
|
||||
{ value: 'P2', label: 'P2' },
|
||||
{ value: 'P3', label: 'P3' }
|
||||
],
|
||||
props: { // 尾部控件的props,一般为element ui控件的props
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
export const API_CASE_RESULT = {
|
||||
key: 'status',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.plan_view.execute_result',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ value: 'success', label: 'api_test.automation.success' },
|
||||
{ value: 'error', label: 'api_test.automation.fail' }
|
||||
],
|
||||
props: { // 尾部控件的props,一般为element ui控件的props
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const API_SCENARIO_RESULT = {
|
||||
key: 'status',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.plan_view.execute_result',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ value: 'Success', label: 'api_test.automation.success' },
|
||||
{ value: 'Fail', label: 'api_test.automation.fail' }
|
||||
],
|
||||
props: { // 尾部控件的props,一般为element ui控件的props
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const API_METHOD = {
|
||||
key: 'method',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'api_test.definition.api_type',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ value: 'GET', label: 'GET' },
|
||||
{ value: 'POST', label: 'POST' },
|
||||
{ value: 'PUT', label: 'PUT' },
|
||||
{ value: 'PATCH', label: 'PATCH' },
|
||||
{ value: 'DELETE', label: 'DELETE' },
|
||||
{ value: 'OPTIONS', label: 'OPTIONS' },
|
||||
{ value: 'HEAD', label: 'HEAD' },
|
||||
{ value: 'CONNECT', label: 'CONNECT' },
|
||||
{ value: 'DUBBO', label: 'DUBBO' },
|
||||
{ value: 'dubbo://', label: 'dubbo://' },
|
||||
{ value: 'SQL', label: 'SQL' },
|
||||
{ value: 'TCP', label: 'TCP' }
|
||||
],
|
||||
props: { // 尾部控件的props,一般为element ui控件的props
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const API_PATH = {
|
||||
key: 'path', // 返回结果Map的key
|
||||
name: 'MsTableSearchInput', // Vue控件名称
|
||||
label: 'api_test.definition.api_path', // 显示名称
|
||||
operator: { // 运算符设置
|
||||
value: OPERATORS.LIKE.value, // 如果未设置value初始值,则value初始值为options[0]
|
||||
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE] // 运算符候选项
|
||||
}
|
||||
}
|
||||
|
||||
export const API_TAGS = {
|
||||
key: 'tags', // 返回结果Map的key
|
||||
name: 'MsTableSearchInput', // Vue控件名称
|
||||
label: 'commons.tag', // 显示名称
|
||||
operator: { // 运算符设置
|
||||
value: OPERATORS.LIKE.value, // 如果未设置value初始值,则value初始值为options[0]
|
||||
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE] // 运算符候选项
|
||||
}
|
||||
}
|
||||
|
||||
export const CREATOR = {
|
||||
key: 'creator',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'api_test.creator',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN, OPERATORS.CURRENT_USER],
|
||||
change: function(component, value) { // 运算符change事件
|
||||
if (value === OPERATORS.CURRENT_USER.value) {
|
||||
component.value = value
|
||||
}
|
||||
}
|
||||
},
|
||||
options: { // 异步获取候选项
|
||||
url: '/user/list',
|
||||
labelKey: 'name',
|
||||
valueKey: 'id',
|
||||
showLabel: option => {
|
||||
return option.label + '(' + option.value + ')'
|
||||
}
|
||||
},
|
||||
props: {
|
||||
multiple: true
|
||||
},
|
||||
isShow: operator => {
|
||||
return operator !== OPERATORS.CURRENT_USER.value
|
||||
}
|
||||
}
|
||||
|
||||
export const EXECUTOR = {
|
||||
key: 'executor',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.plan_view.executor',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN, OPERATORS.CURRENT_USER],
|
||||
change: function(component, value) { // 运算符change事件
|
||||
if (value === OPERATORS.CURRENT_USER.value) {
|
||||
component.value = value
|
||||
}
|
||||
}
|
||||
},
|
||||
options: { // 异步获取候选项
|
||||
url: '/user/list',
|
||||
labelKey: 'name',
|
||||
valueKey: 'id',
|
||||
showLabel: option => {
|
||||
return option.label + '(' + option.value + ')'
|
||||
}
|
||||
},
|
||||
props: {
|
||||
multiple: true
|
||||
},
|
||||
isShow: operator => {
|
||||
return operator !== OPERATORS.CURRENT_USER.value
|
||||
}
|
||||
}
|
||||
|
||||
export const TRIGGER_MODE = {
|
||||
key: 'triggerMode',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'commons.trigger_mode.name',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ label: 'commons.trigger_mode.manual', value: 'MANUAL' },
|
||||
{ label: 'commons.trigger_mode.schedule', value: 'SCHEDULE' },
|
||||
{ label: 'commons.trigger_mode.api', value: 'API' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const PRIORITY = {
|
||||
key: 'priority',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.case.priority',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ label: 'P0', value: 'P0' },
|
||||
{ label: 'P1', value: 'P1' },
|
||||
{ label: 'P2', value: 'P2' },
|
||||
{ label: 'P3', value: 'P3' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const TYPE = {
|
||||
key: 'type',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.case.type',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ label: 'commons.functional', value: 'functional' },
|
||||
{ label: 'commons.performance', value: 'performance' },
|
||||
{ label: 'commons.api', value: 'api' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const METHOD = {
|
||||
key: 'method',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.case.method',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ label: 'test_track.case.manual', value: 'manual' },
|
||||
{ label: 'test_track.case.auto', value: 'auto' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const MODULE = {
|
||||
key: 'module',
|
||||
name: 'MsTableSearchInput',
|
||||
label: 'test_track.case.module',
|
||||
operator: {
|
||||
value: OPERATORS.LIKE.value,
|
||||
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE]
|
||||
}
|
||||
}
|
||||
|
||||
export const PRINCIPAL = {
|
||||
key: 'principal',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.plan.plan_principal',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN, OPERATORS.CURRENT_USER],
|
||||
change: function(component, value) { // 运算符change事件
|
||||
if (value === OPERATORS.CURRENT_USER.value) {
|
||||
component.value = value
|
||||
}
|
||||
}
|
||||
},
|
||||
options: { // 异步获取候选项
|
||||
url: '/user/list',
|
||||
labelKey: 'name',
|
||||
valueKey: 'id',
|
||||
showLabel: option => {
|
||||
return option.label + '(' + option.value + ')'
|
||||
}
|
||||
},
|
||||
props: {
|
||||
multiple: true
|
||||
},
|
||||
isShow: operator => {
|
||||
return operator !== OPERATORS.CURRENT_USER.value
|
||||
}
|
||||
}
|
||||
|
||||
export const STAGE = {
|
||||
key: 'stage',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.plan.plan_stage',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ label: 'test_track.plan.smoke_test', value: 'smoke' },
|
||||
{ label: 'test_track.plan.regression_test', value: 'regression' },
|
||||
{ label: 'test_track.plan.system_test', value: 'system' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const TEST_PLAN_STATUS = {
|
||||
key: 'status',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.plan.plan_status',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ label: 'test_track.plan.plan_status_prepare', value: 'Prepare' },
|
||||
{ label: 'test_track.plan.plan_status_running', value: 'Underway' },
|
||||
{ label: 'test_track.plan.plan_status_completed', value: 'Completed' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const TEST_PLAN_TRIGGER_MODE = {
|
||||
key: 'triggerMode',
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.report.list.trigger_mode',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{ label: 'test_track.report.trigger_mode.manual', value: 'manual' },
|
||||
{ label: 'test_track.report.trigger_mode.automation', value: 'automation' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const TEST_CONFIGS = [NAME, UPDATE_TIME, CREATE_TIME, STATUS, CREATOR]
|
||||
|
||||
export const REPORT_CONFIGS = [NAME, TEST_NAME, CREATE_TIME, STATUS, CREATOR, TRIGGER_MODE]
|
||||
|
||||
export const TEST_CASE_CONFIGS = [NAME, API_TAGS, MODULE, PRIORITY, CREATE_TIME, TYPE, UPDATE_TIME, METHOD, CREATOR, EXECUTOR]
|
||||
|
||||
export const TEST_PLAN_CONFIGS = [NAME, UPDATE_TIME, CREATE_TIME, PRINCIPAL, TEST_PLAN_STATUS, STAGE]
|
||||
|
||||
export const API_DEFINITION_CONFIGS = [NAME, API_METHOD, API_PATH, API_STATUS, API_TAGS, UPDATE_TIME, CREATE_TIME, CREATOR]
|
||||
|
||||
export const API_CASE_CONFIGS = [NAME, API_CASE_PRIORITY, API_TAGS, API_CASE_RESULT, UPDATE_TIME, CREATE_TIME, CREATOR]
|
||||
|
||||
export const API_SCENARIO_CONFIGS = [NAME, API_CASE_PRIORITY, API_TAGS, API_SCENARIO_RESULT, UPDATE_TIME, CREATE_TIME, CREATOR]
|
||||
|
||||
export const TEST_PLAN_REPORT_CONFIGS = [NAME, TEST_PLAN_NAME, CREATOR, CREATE_TIME, TEST_PLAN_TRIGGER_MODE, TEST_PLAN_STATUS]
|
@ -1,25 +0,0 @@
|
||||
<template>
|
||||
<el-table-column width="1" :resizable="false" align="center">
|
||||
<el-popover slot="header" placement="right" trigger="click" style="margin-right: 0px;">
|
||||
<el-link @click.native.stop="$emit('selectAll')">{{$t('api_test.batch_menus.select_all_data',[total])}}</el-link>
|
||||
<br/>
|
||||
<el-link @click.native.stop="$emit('selectPageAll')">{{$t('api_test.batch_menus.select_show_data',[pageSize])}}</el-link>
|
||||
<i class="el-icon-arrow-down" slot="reference"></i>
|
||||
</el-popover>
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsTableSelectAll",
|
||||
props: ['total', 'pageSize'],
|
||||
data() {
|
||||
return {
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,28 +0,0 @@
|
||||
<template>
|
||||
<el-table-column width="1" :resizable="false" align="center">
|
||||
<el-dropdown slot="header">
|
||||
<span class="el-dropdown-link">
|
||||
<i class="el-icon-arrow-down"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item @click.native.stop="$emit('selectAll')">
|
||||
{{$t('api_test.batch_menus.select_all_data',[total])}}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click.native.stop="$emit('selectPageAll')">
|
||||
{{$t('api_test.batch_menus.select_show_data',[pageSize])}}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsTableSelectAll",
|
||||
props: ['total', 'pageSize']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,429 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane :label="$t('schedule.cron.seconds')" v-if="shouldHide('second')">
|
||||
<crontab-second
|
||||
@update="updateContabValue"
|
||||
:check="checkNumber"
|
||||
ref="cronsecond"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="$t('schedule.cron.minutes')" v-if="shouldHide('min')">
|
||||
<crontab-min
|
||||
@update="updateContabValue"
|
||||
:check="checkNumber"
|
||||
:cron="contabValueObj"
|
||||
ref="cronmin"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="$t('schedule.cron.hours')" v-if="shouldHide('hour')">
|
||||
<crontab-hour
|
||||
@update="updateContabValue"
|
||||
:check="checkNumber"
|
||||
:cron="contabValueObj"
|
||||
ref="cronhour"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="$t('schedule.cron.day')" v-if="shouldHide('day')">
|
||||
<crontab-day
|
||||
@update="updateContabValue"
|
||||
:check="checkNumber"
|
||||
:cron="contabValueObj"
|
||||
ref="cronday"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="$t('schedule.cron.month')" v-if="shouldHide('mouth')">
|
||||
<crontab-mouth
|
||||
@update="updateContabValue"
|
||||
:check="checkNumber"
|
||||
:cron="contabValueObj"
|
||||
ref="cronmouth"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="$t('schedule.cron.weeks')" v-if="shouldHide('week')">
|
||||
<crontab-week
|
||||
@update="updateContabValue"
|
||||
:check="checkNumber"
|
||||
:cron="contabValueObj"
|
||||
ref="cronweek"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="$t('schedule.cron.years')" v-if="shouldHide('year')">
|
||||
<crontab-year @update="updateContabValue"
|
||||
:check="checkNumber"
|
||||
:cron="contabValueObj"
|
||||
ref="cronyear"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<div class="popup-main">
|
||||
<div class="popup-result-container">
|
||||
<p class="title">{{$t('schedule.cron.time_expression')}}</p>
|
||||
<table>
|
||||
<thead>
|
||||
<th v-for="item of tabTitles" width="40" :key="item">{{item}}</th>
|
||||
<th>{{$t('schedule.cron.complete_expression')}}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<td>
|
||||
<span>{{contabValueObj.second}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{contabValueObj.min}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{contabValueObj.hour}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{contabValueObj.day}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{contabValueObj.mouth}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{contabValueObj.week}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{contabValueObj.year}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{contabValueString}}</span>
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<crontab-result :ex="contabValueString" ref="crontabResult"/>
|
||||
|
||||
<div class="pop_btn">
|
||||
<el-button size="small" type="primary" @click="submitFill">{{$t('commons.confirm')}}</el-button>
|
||||
<el-button size="small" type="warning" @click="clearCron">{{$t('api_test.reset')}}</el-button>
|
||||
<el-button size="small" @click="hidePopup">{{$t('commons.cancel')}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CrontabSecond from "./CrontabSecond.vue";
|
||||
import CrontabMin from "./CrontabMin.vue";
|
||||
import CrontabHour from "./CrontabHour.vue";
|
||||
import CrontabDay from "./CrontabDay.vue";
|
||||
import CrontabMouth from "./CrontabMouth.vue";
|
||||
import CrontabWeek from "./CrontabWeek.vue";
|
||||
import CrontabYear from "./CrontabYear.vue";
|
||||
import CrontabResult from "./CrontabResult.vue";
|
||||
|
||||
export default {
|
||||
name: "Crontab",
|
||||
data() {
|
||||
return {
|
||||
tabTitles: [
|
||||
this.$t('schedule.cron.seconds'),
|
||||
this.$t('schedule.cron.minutes'),
|
||||
this.$t('schedule.cron.hours'),
|
||||
this.$t('schedule.cron.day'),
|
||||
this.$t('schedule.cron.month'),
|
||||
this.$t('schedule.cron.weeks'),
|
||||
this.$t('schedule.cron.years')],
|
||||
tabActive: 0,
|
||||
myindex: 0,
|
||||
contabValueObj: {
|
||||
second: "*",
|
||||
min: "*",
|
||||
hour: "*",
|
||||
day: "*",
|
||||
mouth: "*",
|
||||
week: "?",
|
||||
year: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
props: ["expression", "hideComponent"],
|
||||
methods: {
|
||||
shouldHide(key) {
|
||||
if (this.hideComponent && this.hideComponent.includes(key)) return false;
|
||||
return true;
|
||||
},
|
||||
resolveExp() {
|
||||
//反解析 表达式
|
||||
if (this.expression) {
|
||||
let arr = this.expression.split(" ");
|
||||
if (arr.length >= 6) {
|
||||
//6 位以上是合法表达式
|
||||
let obj = {
|
||||
second: arr[0],
|
||||
min: arr[1],
|
||||
hour: arr[2],
|
||||
day: arr[3],
|
||||
mouth: arr[4],
|
||||
week: arr[5],
|
||||
year: arr[6] ? arr[6] : "",
|
||||
};
|
||||
this.contabValueObj = {
|
||||
...obj,
|
||||
};
|
||||
for (let i in obj) {
|
||||
if (obj[i]) this.changeRadio(i, obj[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//没有传入的表达式 则还原
|
||||
this.clearCron();
|
||||
}
|
||||
},
|
||||
// tab切换值
|
||||
tabCheck(index) {
|
||||
this.tabActive = index;
|
||||
},
|
||||
// 由子组件触发,更改表达式组成的字段值
|
||||
updateContabValue(name, value, from) {
|
||||
"updateContabValue", name, value, from;
|
||||
this.contabValueObj[name] = value;
|
||||
if (from && from !== name) {
|
||||
// console.log(`来自组件 ${from} 改变了 ${name} ${value}`);
|
||||
this.changeRadio(name, value);
|
||||
}
|
||||
},
|
||||
//赋值到组件
|
||||
changeRadio(name, value) {
|
||||
let arr = ["second", "min", "hour", "mouth"],
|
||||
refName = "cron" + name,
|
||||
insVlaue;
|
||||
|
||||
if (!this.$refs[refName]) return;
|
||||
|
||||
if (arr.includes(name)) {
|
||||
if (value === "*") {
|
||||
insVlaue = 1;
|
||||
} else if (value.indexOf("-") > -1) {
|
||||
let indexArr = value.split("-");
|
||||
isNaN(indexArr[0])
|
||||
? (this.$refs[refName].cycle01 = 0)
|
||||
: (this.$refs[refName].cycle01 = indexArr[0]);
|
||||
this.$refs[refName].cycle02 = indexArr[1];
|
||||
insVlaue = 2;
|
||||
} else if (value.indexOf("/") > -1) {
|
||||
let indexArr = value.split("/");
|
||||
isNaN(indexArr[0])
|
||||
? (this.$refs[refName].average01 = 0)
|
||||
: (this.$refs[refName].average01 = indexArr[0]);
|
||||
this.$refs[refName].average02 = indexArr[1];
|
||||
insVlaue = 3;
|
||||
} else {
|
||||
insVlaue = 4;
|
||||
this.$refs[refName].checkboxList = value.split(",");
|
||||
}
|
||||
} else if (name == "day") {
|
||||
if (value === "*") {
|
||||
insVlaue = 1;
|
||||
} else if (value == "?") {
|
||||
insVlaue = 2;
|
||||
} else if (value.indexOf("-") > -1) {
|
||||
let indexArr = value.split("-");
|
||||
isNaN(indexArr[0])
|
||||
? (this.$refs[refName].cycle01 = 0)
|
||||
: (this.$refs[refName].cycle01 = indexArr[0]);
|
||||
this.$refs[refName].cycle02 = indexArr[1];
|
||||
insVlaue = 3;
|
||||
} else if (value.indexOf("/") > -1) {
|
||||
let indexArr = value.split("/");
|
||||
isNaN(indexArr[0])
|
||||
? (this.$refs[refName].average01 = 0)
|
||||
: (this.$refs[refName].average01 = indexArr[0]);
|
||||
this.$refs[refName].average02 = indexArr[1];
|
||||
insVlaue = 4;
|
||||
} else if (value.indexOf("W") > -1) {
|
||||
let indexArr = value.split("W");
|
||||
isNaN(indexArr[0])
|
||||
? (this.$refs[refName].workday = 0)
|
||||
: (this.$refs[refName].workday = indexArr[0]);
|
||||
insVlaue = 5;
|
||||
} else if (value === "L") {
|
||||
insVlaue = 6;
|
||||
} else {
|
||||
this.$refs[refName].checkboxList = value.split(",");
|
||||
insVlaue = 7;
|
||||
}
|
||||
} else if (name == "week") {
|
||||
if (value === "*") {
|
||||
insVlaue = 1;
|
||||
} else if (value == "?") {
|
||||
insVlaue = 2;
|
||||
} else if (value.indexOf("-") > -1) {
|
||||
let indexArr = value.split("-");
|
||||
isNaN(indexArr[0])
|
||||
? (this.$refs[refName].cycle01 = 0)
|
||||
: (this.$refs[refName].cycle01 = indexArr[0]);
|
||||
this.$refs[refName].cycle02 = indexArr[1];
|
||||
insVlaue = 3;
|
||||
} else if (value.indexOf("#") > -1) {
|
||||
let indexArr = value.split("#");
|
||||
isNaN(indexArr[0])
|
||||
? (this.$refs[refName].average01 = 1)
|
||||
: (this.$refs[refName].average01 = indexArr[0]);
|
||||
this.$refs[refName].average02 = indexArr[1];
|
||||
insVlaue = 4;
|
||||
} else if (value.indexOf("L") > -1) {
|
||||
let indexArr = value.split("L");
|
||||
isNaN(indexArr[0])
|
||||
? (this.$refs[refName].weekday = 1)
|
||||
: (this.$refs[refName].weekday = indexArr[0]);
|
||||
insVlaue = 5;
|
||||
} else {
|
||||
this.$refs[refName].checkboxList = value.split(",");
|
||||
insVlaue = 7;
|
||||
}
|
||||
} else if (name == "year") {
|
||||
if (value == "") {
|
||||
insVlaue = 1;
|
||||
} else if (value == "*") {
|
||||
insVlaue = 2;
|
||||
} else if (value.indexOf("-") > -1) {
|
||||
insVlaue = 3;
|
||||
} else if (value.indexOf("/") > -1) {
|
||||
insVlaue = 4;
|
||||
} else {
|
||||
this.$refs[refName].checkboxList = value.split(",");
|
||||
insVlaue = 5;
|
||||
}
|
||||
}
|
||||
this.$refs[refName].radioValue = insVlaue;
|
||||
},
|
||||
// 表单选项的子组件校验数字格式(通过-props传递)
|
||||
checkNumber(value, minLimit, maxLimit) {
|
||||
//检查必须为整数
|
||||
value = Math.floor(value);
|
||||
if (value < minLimit) {
|
||||
value = minLimit;
|
||||
} else if (value > maxLimit) {
|
||||
value = maxLimit;
|
||||
}
|
||||
return value;
|
||||
},
|
||||
// 隐藏弹窗
|
||||
hidePopup() {
|
||||
this.$emit("hide");
|
||||
},
|
||||
// 填充表达式
|
||||
submitFill() {
|
||||
this.$emit("fill", this.contabValueString, this.$refs.crontabResult.resultList);
|
||||
this.hidePopup();
|
||||
},
|
||||
clearCron() {
|
||||
// 还原选择项
|
||||
// ("准备还原");
|
||||
this.contabValueObj = {
|
||||
second: "*",
|
||||
min: "*",
|
||||
hour: "*",
|
||||
day: "*",
|
||||
mouth: "*",
|
||||
week: "?",
|
||||
year: "",
|
||||
};
|
||||
for (let j in this.contabValueObj) {
|
||||
this.changeRadio(j, this.contabValueObj[j]);
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
contabValueString: function() {
|
||||
let obj = this.contabValueObj;
|
||||
let str =
|
||||
obj.second +
|
||||
" " +
|
||||
obj.min +
|
||||
" " +
|
||||
obj.hour +
|
||||
" " +
|
||||
obj.day +
|
||||
" " +
|
||||
obj.mouth +
|
||||
" " +
|
||||
obj.week +
|
||||
(obj.year == "" ? "" : " " + obj.year);
|
||||
return str;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
CrontabSecond,
|
||||
CrontabMin,
|
||||
CrontabHour,
|
||||
CrontabDay,
|
||||
CrontabMouth,
|
||||
CrontabWeek,
|
||||
CrontabYear,
|
||||
CrontabResult,
|
||||
},
|
||||
watch: {
|
||||
expression: "resolveExp",
|
||||
hideComponent(value) {
|
||||
// 隐藏部分组件
|
||||
},
|
||||
},
|
||||
mounted: function() {
|
||||
this.resolveExp();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.pop_btn {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.popup-main {
|
||||
position: relative;
|
||||
margin: 10px auto;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.popup-title {
|
||||
overflow: hidden;
|
||||
line-height: 34px;
|
||||
padding-top: 6px;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
.popup-result-container {
|
||||
box-sizing: border-box;
|
||||
line-height: 24px;
|
||||
margin: 25px auto;
|
||||
padding: 15px 10px 10px;
|
||||
border: 1px solid #ccc;
|
||||
position: relative;
|
||||
}
|
||||
.popup-result-container .title {
|
||||
position: absolute;
|
||||
top: -28px;
|
||||
left: 50%;
|
||||
width: 140px;
|
||||
font-size: 14px;
|
||||
margin-left: -70px;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
background: #fff;
|
||||
}
|
||||
.popup-result-container table {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.popup-result-container table span {
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-family: arial;
|
||||
line-height: 30px;
|
||||
height: 30px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,179 +0,0 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="1">
|
||||
{{$t('schedule.cron.day')}},{{$t('schedule.cron.day_allowed_wildcards')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="2">
|
||||
{{$t('schedule.cron.not_specify')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="3">
|
||||
{{$t('schedule.cron.period')}} {{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='cycle01' :min="0" :max="31" /> -
|
||||
<el-input-number v-model='cycle02' :min="0" :max="31" /> {{$t('schedule.cron.day')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="4">
|
||||
{{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='average01' :min="0" :max="31" /> {{$t('schedule.cron.day_unit')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||
<el-input-number v-model='average02' :min="0" :max="31" /> {{$t('schedule.cron.day')}}{{$t('schedule.cron.execute_once')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="5">
|
||||
{{$t('schedule.cron.every')}}{{$t('schedule.cron.month')}}
|
||||
<el-input-number v-model='workday' :min="0" :max="31" /> {{$t('schedule.cron.day_unit')}}{{$t('schedule.cron.last_working_day')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="6">
|
||||
{{$t('schedule.cron.last_working_day')}}{{$t('schedule.cron.last_day_of_the_month')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="7">
|
||||
{{$t('schedule.cron.specify')}}
|
||||
<el-select clearable v-model="checkboxList" :placeholder="$t('schedule.cron.multi_select')" multiple style="width:100%">
|
||||
<el-option v-for="item in 31" :key="item" :value="item">{{item}}</el-option>
|
||||
</el-select>
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
radioValue: 1,
|
||||
workday: 1,
|
||||
cycle01: 1,
|
||||
cycle02: 2,
|
||||
average01: 1,
|
||||
average02: 1,
|
||||
checkboxList: [],
|
||||
checkNum: this.$options.propsData.check
|
||||
}
|
||||
},
|
||||
name: 'CrontabDay',
|
||||
props: ['check', 'cron'],
|
||||
methods: {
|
||||
// 单选按钮值变化时
|
||||
radioChange() {
|
||||
('day rachange');
|
||||
if (this.radioValue === 1) {
|
||||
this.$emit('update', 'day', '*', 'day');
|
||||
this.$emit('update', 'week', '?', 'day');
|
||||
this.$emit('update', 'mouth', '*', 'day');
|
||||
} else {
|
||||
if (this.cron.hour === '*') {
|
||||
this.$emit('update', 'hour', '0', 'day');
|
||||
}
|
||||
if (this.cron.min === '*') {
|
||||
this.$emit('update', 'min', '0', 'day');
|
||||
}
|
||||
if (this.cron.second === '*') {
|
||||
this.$emit('update', 'second', '0', 'day');
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.radioValue) {
|
||||
case 2:
|
||||
this.$emit('update', 'day', '?');
|
||||
break;
|
||||
case 3:
|
||||
this.$emit('update', 'day', this.cycle01 + '-' + this.cycle02);
|
||||
break;
|
||||
case 4:
|
||||
this.$emit('update', 'day', this.average01 + '/' + this.average02);
|
||||
break;
|
||||
case 5:
|
||||
this.$emit('update', 'day', this.workday + 'W');
|
||||
break;
|
||||
case 6:
|
||||
this.$emit('update', 'day', 'L');
|
||||
break;
|
||||
case 7:
|
||||
this.$emit('update', 'day', this.checkboxString);
|
||||
break;
|
||||
}
|
||||
('day rachange end');
|
||||
},
|
||||
// 周期两个值变化时
|
||||
cycleChange() {
|
||||
if (this.radioValue == '3') {
|
||||
this.$emit('update', 'day', this.cycleTotal);
|
||||
}
|
||||
},
|
||||
// 平均两个值变化时
|
||||
averageChange() {
|
||||
if (this.radioValue == '4') {
|
||||
this.$emit('update', 'day', this.averageTotal);
|
||||
}
|
||||
},
|
||||
// 最近工作日值变化时
|
||||
workdayChange() {
|
||||
if (this.radioValue == '5') {
|
||||
this.$emit('update', 'day', this.workday + 'W');
|
||||
}
|
||||
},
|
||||
// checkbox值变化时
|
||||
checkboxChange() {
|
||||
if (this.radioValue == '7') {
|
||||
this.$emit('update', 'day', this.checkboxString);
|
||||
}
|
||||
},
|
||||
// 父组件传递的week发生变化触发
|
||||
weekChange() {
|
||||
//判断week值与day不能同时为“?”
|
||||
if (this.cron.week == '?' && this.radioValue == '2') {
|
||||
this.radioValue = '1';
|
||||
} else if (this.cron.week !== '?' && this.radioValue != '2') {
|
||||
this.radioValue = '2';
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"radioValue": "radioChange",
|
||||
'cycleTotal': 'cycleChange',
|
||||
'averageTotal': 'averageChange',
|
||||
'workdayCheck': 'workdayChange',
|
||||
'checkboxString': 'checkboxChange',
|
||||
},
|
||||
computed: {
|
||||
// 计算两个周期值
|
||||
cycleTotal: function () {
|
||||
this.checkNum(this.cycle01, 1, 31)
|
||||
this.checkNum(this.cycle02, 1, 31)
|
||||
return this.cycle01 + '-' + this.cycle02;
|
||||
},
|
||||
// 计算平均用到的值
|
||||
averageTotal: function () {
|
||||
this.checkNum(this.average01, 1, 31)
|
||||
this.checkNum(this.average02, 1, 31)
|
||||
return this.average01 + '/' + this.average02;
|
||||
},
|
||||
// 计算工作日格式
|
||||
workdayCheck: function () {
|
||||
this.checkNum(this.workday, 1, 31)
|
||||
return this.workday;
|
||||
},
|
||||
// 计算勾选的checkbox值合集
|
||||
checkboxString: function () {
|
||||
let str = this.checkboxList.join();
|
||||
return str == '' ? '*' : str;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,122 +0,0 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="1">
|
||||
{{$t('schedule.cron.hours')}},{{$t('schedule.cron.allowed_wildcards')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="2">
|
||||
{{$t('schedule.cron.period')}} {{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='cycle01' :min="0" :max="24" /> -
|
||||
<el-input-number v-model='cycle02' :min="0" :max="24" /> 小时
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="3">
|
||||
{{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='average01' :min="0" :max="24" /> {{$t('schedule.cron.hours')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||
<el-input-number v-model='average02' :min="0" :max="24" /> {{$t('schedule.cron.hours')}}{{$t('schedule.cron.execute_once')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="4">
|
||||
{{$t('schedule.cron.specify')}}
|
||||
<el-select clearable v-model="checkboxList" :placeholder="$t('schedule.cron.multi_select')" multiple style="width:100%">
|
||||
<el-option v-for="item in 24" :key="item" :value="item-1">{{item-1}}</el-option>
|
||||
</el-select>
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
radioValue: 1,
|
||||
cycle01: 0,
|
||||
cycle02: 1,
|
||||
average01: 0,
|
||||
average02: 1,
|
||||
checkboxList: [],
|
||||
checkNum: this.$options.propsData.check
|
||||
}
|
||||
},
|
||||
name: 'CrontabHour',
|
||||
props: ['check', 'cron'],
|
||||
methods: {
|
||||
// 单选按钮值变化时
|
||||
radioChange() {
|
||||
if (this.radioValue === 1) {
|
||||
this.$emit('update', 'hour', '*', 'hour');
|
||||
this.$emit('update', 'day', '*', 'hour');
|
||||
} else {
|
||||
if (this.cron.min === '*') {
|
||||
this.$emit('update', 'min', '0', 'hour');
|
||||
}
|
||||
if (this.cron.second === '*') {
|
||||
this.$emit('update', 'second', '0', 'hour');
|
||||
}
|
||||
}
|
||||
switch (this.radioValue) {
|
||||
case 2:
|
||||
this.$emit('update', 'hour', this.cycle01 + '-' + this.cycle02);
|
||||
break;
|
||||
case 3:
|
||||
this.$emit('update', 'hour', this.average01 + '/' + this.average02);
|
||||
break;
|
||||
case 4:
|
||||
this.$emit('update', 'hour', this.checkboxString);
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 周期两个值变化时
|
||||
cycleChange() {
|
||||
if (this.radioValue == '2') {
|
||||
this.$emit('update', 'hour', this.cycleTotal);
|
||||
}
|
||||
},
|
||||
// 平均两个值变化时
|
||||
averageChange() {
|
||||
if (this.radioValue == '3') {
|
||||
this.$emit('update', 'hour', this.averageTotal);
|
||||
}
|
||||
},
|
||||
// checkbox值变化时
|
||||
checkboxChange() {
|
||||
if (this.radioValue == '4') {
|
||||
this.$emit('update', 'hour', this.checkboxString);
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"radioValue": "radioChange",
|
||||
'cycleTotal': 'cycleChange',
|
||||
'averageTotal': 'averageChange',
|
||||
'checkboxString': 'checkboxChange'
|
||||
},
|
||||
computed: {
|
||||
// 计算两个周期值
|
||||
cycleTotal: function () {
|
||||
this.checkNum(this.cycle01, 0, 23)
|
||||
this.checkNum(this.cycle02, 0, 23)
|
||||
return this.cycle01 + '-' + this.cycle02;
|
||||
},
|
||||
// 计算平均用到的值
|
||||
averageTotal: function () {
|
||||
this.checkNum(this.average01, 0, 23)
|
||||
this.checkNum(this.average02, 1, 23)
|
||||
return this.average01 + '/' + this.average02;
|
||||
},
|
||||
// 计算勾选的checkbox值合集
|
||||
checkboxString: function () {
|
||||
let str = this.checkboxList.join();
|
||||
return str == '' ? '*' : str;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,120 +0,0 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="1">
|
||||
{{$t('schedule.cron.minutes')}},{{$t('schedule.cron.allowed_wildcards')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="2">
|
||||
{{$t('schedule.cron.period')}} {{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='cycle01' :min="0" :max="59" /> -
|
||||
<el-input-number v-model='cycle02' :min="0" :max="59" /> {{$t('schedule.cron.minutes')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="3">
|
||||
{{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='average01' :min="0" :max="59" /> {{$t('schedule.cron.minutes')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||
<el-input-number v-model='average02' :min="0" :max="60" /> {{$t('schedule.cron.minutes')}}{{$t('schedule.cron.execute_once')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="4">
|
||||
{{$t('schedule.cron.specify')}}
|
||||
<el-select clearable v-model="checkboxList" :placeholder="$t('schedule.cron.multi_select')" multiple style="width:100%">
|
||||
<el-option v-for="item in 60" :key="item" :value="item-1">{{item-1}}</el-option>
|
||||
</el-select>
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
radioValue: 1,
|
||||
cycle01: 1,
|
||||
cycle02: 2,
|
||||
average01: 0,
|
||||
average02: 1,
|
||||
checkboxList: [],
|
||||
checkNum: this.$options.propsData.check
|
||||
}
|
||||
},
|
||||
name: 'CrontabMin',
|
||||
props: ['check', 'cron'],
|
||||
methods: {
|
||||
// 单选按钮值变化时
|
||||
radioChange() {
|
||||
if (this.radioValue !== 1 && this.cron.second === '*') {
|
||||
this.$emit('update', 'second', '0', 'min');
|
||||
}
|
||||
switch (this.radioValue) {
|
||||
case 1:
|
||||
this.$emit('update', 'min', '*', 'min');
|
||||
this.$emit('update', 'hour', '*', 'min');
|
||||
break;
|
||||
case 2:
|
||||
this.$emit('update', 'min', this.cycle01 + '-' + this.cycle02, 'min');
|
||||
break;
|
||||
case 3:
|
||||
this.$emit('update', 'min', this.average01 + '/' + this.average02, 'min');
|
||||
break;
|
||||
case 4:
|
||||
this.$emit('update', 'min', this.checkboxString, 'min');
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 周期两个值变化时
|
||||
cycleChange() {
|
||||
if (this.radioValue == '2') {
|
||||
this.$emit('update', 'min', this.cycleTotal, 'min');
|
||||
}
|
||||
},
|
||||
// 平均两个值变化时
|
||||
averageChange() {
|
||||
if (this.radioValue == '3') {
|
||||
this.$emit('update', 'min', this.averageTotal, 'min');
|
||||
}
|
||||
},
|
||||
// checkbox值变化时
|
||||
checkboxChange() {
|
||||
if (this.radioValue == '4') {
|
||||
this.$emit('update', 'min', this.checkboxString, 'min');
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
watch: {
|
||||
"radioValue": "radioChange",
|
||||
'cycleTotal': 'cycleChange',
|
||||
'averageTotal': 'averageChange',
|
||||
'checkboxString': 'checkboxChange',
|
||||
},
|
||||
computed: {
|
||||
// 计算两个周期值
|
||||
cycleTotal: function () {
|
||||
this.checkNum(this.cycle01, 0, 59)
|
||||
this.checkNum(this.cycle02, 0, 59)
|
||||
return this.cycle01 + '-' + this.cycle02;
|
||||
},
|
||||
// 计算平均用到的值
|
||||
averageTotal: function () {
|
||||
this.checkNum(this.average01, 0, 59)
|
||||
this.checkNum(this.average02, 1, 59)
|
||||
return this.average01 + '/' + this.average02;
|
||||
},
|
||||
// 计算勾选的checkbox值合集
|
||||
checkboxString: function () {
|
||||
let str = this.checkboxList.join();
|
||||
return str == '' ? '*' : str;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,128 +0,0 @@
|
||||
<template>
|
||||
<el-form size='small'>
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="1">
|
||||
{{$t('schedule.cron.month')}},{{$t('schedule.cron.allowed_wildcards')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="2">
|
||||
{{$t('schedule.cron.period')}} {{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='cycle01' :min="1" :max="12" /> -
|
||||
<el-input-number v-model='cycle02' :min="1" :max="12" /> {{$t('schedule.cron.month')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="3">
|
||||
{{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='average01' :min="1" :max="12" /> {{$t('schedule.cron.month')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||
<el-input-number v-model='average02' :min="1" :max="12" /> {{$t('schedule.cron.month')}}{{$t('schedule.cron.execute_once')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="4">
|
||||
{{$t('schedule.cron.specify')}}
|
||||
<el-select clearable v-model="checkboxList" :placeholder="$t('schedule.cron.multi_select')" multiple style="width:100%">
|
||||
<el-option v-for="item in 12" :key="item" :value="item">{{item}}</el-option>
|
||||
</el-select>
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
radioValue: 1,
|
||||
cycle01: 1,
|
||||
cycle02: 2,
|
||||
average01: 1,
|
||||
average02: 1,
|
||||
checkboxList: [],
|
||||
checkNum: this.check
|
||||
}
|
||||
},
|
||||
name: 'CrontabMouth',
|
||||
props: ['check', 'cron'],
|
||||
methods: {
|
||||
// 单选按钮值变化时
|
||||
radioChange() {
|
||||
if (this.radioValue === 1) {
|
||||
this.$emit('update', 'mouth', '*');
|
||||
this.$emit('update', 'year', '*');
|
||||
} else {
|
||||
if (this.cron.day === '*') {
|
||||
this.$emit('update', 'day', '1', 'mouth');
|
||||
}
|
||||
if (this.cron.hour === '*') {
|
||||
this.$emit('update', 'hour', '0', 'mouth');
|
||||
}
|
||||
if (this.cron.min === '*') {
|
||||
this.$emit('update', 'min', '0', 'mouth');
|
||||
}
|
||||
if (this.cron.second === '*') {
|
||||
this.$emit('update', 'second', '0', 'mouth');
|
||||
}
|
||||
}
|
||||
switch (this.radioValue) {
|
||||
case 2:
|
||||
this.$emit('update', 'mouth', this.cycle01 + '-' + this.cycle02);
|
||||
break;
|
||||
case 3:
|
||||
this.$emit('update', 'mouth', this.average01 + '/' + this.average02);
|
||||
break;
|
||||
case 4:
|
||||
this.$emit('update', 'mouth', this.checkboxString);
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 周期两个值变化时
|
||||
cycleChange() {
|
||||
if (this.radioValue == '2') {
|
||||
this.$emit('update', 'mouth', this.cycleTotal);
|
||||
}
|
||||
},
|
||||
// 平均两个值变化时
|
||||
averageChange() {
|
||||
if (this.radioValue == '3') {
|
||||
this.$emit('update', 'mouth', this.averageTotal);
|
||||
}
|
||||
},
|
||||
// checkbox值变化时
|
||||
checkboxChange() {
|
||||
if (this.radioValue == '4') {
|
||||
this.$emit('update', 'mouth', this.checkboxString);
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"radioValue": "radioChange",
|
||||
'cycleTotal': 'cycleChange',
|
||||
'averageTotal': 'averageChange',
|
||||
'checkboxString': 'checkboxChange'
|
||||
},
|
||||
computed: {
|
||||
// 计算两个周期值
|
||||
cycleTotal: function () {
|
||||
this.checkNum(this.cycle01, 1, 12)
|
||||
this.checkNum(this.cycle02, 1, 12)
|
||||
return this.cycle01 + '-' + this.cycle02;
|
||||
},
|
||||
// 计算平均用到的值
|
||||
averageTotal: function () {
|
||||
this.checkNum(this.average01, 1, 12)
|
||||
this.checkNum(this.average02, 1, 12)
|
||||
return this.average01 + '/' + this.average02;
|
||||
},
|
||||
// 计算勾选的checkbox值合集
|
||||
checkboxString: function () {
|
||||
let str = this.checkboxList.join();
|
||||
return str == '' ? '*' : str;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,604 +0,0 @@
|
||||
<template>
|
||||
<span>
|
||||
<span v-if="enableSimpleMode">{{resultList && resultList.length > 0 ? resultList[0] : ''}}</span>
|
||||
<div v-if="!enableSimpleMode" class="popup-result">
|
||||
<p class="title">{{$t('schedule.cron.recent_run_time')}}</p>
|
||||
<ul class="popup-result-scroll">
|
||||
<template>
|
||||
<li v-for='item in resultList' :key="item">{{item}}</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {cronValidate} from "../../../../common/js/cron";
|
||||
|
||||
export default {
|
||||
name: 'CrontabResult',
|
||||
data() {
|
||||
return {
|
||||
dayRule: '',
|
||||
dayRuleSup: '',
|
||||
dateArr: [],
|
||||
resultList: [],
|
||||
isShow: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'ex': 'expressionChange'
|
||||
},
|
||||
props: {
|
||||
ex: String,
|
||||
enableSimpleMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
// 初始化 获取一次结果
|
||||
this.expressionChange();
|
||||
},
|
||||
methods: {
|
||||
// 表达式值变化时,开始去计算 结果
|
||||
expressionChange() {
|
||||
// 计算开始-隐藏结果
|
||||
this.isShow = false;
|
||||
if (!cronValidate(this.ex)) {
|
||||
this.resultList = [];
|
||||
this.$emit("resultListChange", this.resultList);
|
||||
return;
|
||||
}
|
||||
// 获取规则数组[0秒、1分、2时、3日、4月、5星期、6年]
|
||||
let ruleArr = this.$options.propsData.ex.split(' ');
|
||||
// 用于记录进入循环的次数
|
||||
let nums = 0;
|
||||
// 用于暂时存符号时间规则结果的数组
|
||||
let resultArr = [];
|
||||
// 获取当前时间精确至[年、月、日、时、分、秒]
|
||||
let nTime = new Date();
|
||||
let nYear = nTime.getFullYear();
|
||||
let nMouth = nTime.getMonth() + 1;
|
||||
let nDay = nTime.getDate();
|
||||
let nHour = nTime.getHours();
|
||||
let nMin = nTime.getMinutes();
|
||||
let nSecond = nTime.getSeconds();
|
||||
// 根据规则获取到近100年可能年数组、月数组等等
|
||||
this.getSecondArr(ruleArr[0]);
|
||||
this.getMinArr(ruleArr[1]);
|
||||
this.getHourArr(ruleArr[2]);
|
||||
this.getDayArr(ruleArr[3]);
|
||||
this.getMouthArr(ruleArr[4]);
|
||||
this.getWeekArr(ruleArr[5]);
|
||||
this.getYearArr(ruleArr[6], nYear);
|
||||
// 将获取到的数组赋值-方便使用
|
||||
let sDate = this.dateArr[0];
|
||||
let mDate = this.dateArr[1];
|
||||
let hDate = this.dateArr[2];
|
||||
let DDate = this.dateArr[3];
|
||||
let MDate = this.dateArr[4];
|
||||
let YDate = this.dateArr[5];
|
||||
// 获取当前时间在数组中的索引
|
||||
let sIdx = this.getIndex(sDate, nSecond);
|
||||
let mIdx = this.getIndex(mDate, nMin);
|
||||
let hIdx = this.getIndex(hDate, nHour);
|
||||
let DIdx = this.getIndex(DDate, nDay);
|
||||
let MIdx = this.getIndex(MDate, nMouth);
|
||||
let YIdx = this.getIndex(YDate, nYear);
|
||||
// 重置月日时分秒的函数(后面用的比较多)
|
||||
const resetSecond = function () {
|
||||
sIdx = 0;
|
||||
nSecond = sDate[sIdx]
|
||||
}
|
||||
const resetMin = function () {
|
||||
mIdx = 0;
|
||||
nMin = mDate[mIdx]
|
||||
resetSecond();
|
||||
}
|
||||
const resetHour = function () {
|
||||
hIdx = 0;
|
||||
nHour = hDate[hIdx]
|
||||
resetMin();
|
||||
}
|
||||
const resetDay = function () {
|
||||
DIdx = 0;
|
||||
nDay = DDate[DIdx]
|
||||
resetHour();
|
||||
}
|
||||
const resetMouth = function () {
|
||||
MIdx = 0;
|
||||
nMouth = MDate[MIdx]
|
||||
resetDay();
|
||||
}
|
||||
// 如果当前年份不为数组中当前值
|
||||
if (nYear !== YDate[YIdx]) {
|
||||
resetMouth();
|
||||
}
|
||||
// 如果当前月份不为数组中当前值
|
||||
if (nMouth !== MDate[MIdx]) {
|
||||
resetDay();
|
||||
}
|
||||
// 如果当前“日”不为数组中当前值
|
||||
if (nDay !== DDate[DIdx]) {
|
||||
resetHour();
|
||||
}
|
||||
// 如果当前“时”不为数组中当前值
|
||||
if (nHour !== hDate[hIdx]) {
|
||||
resetMin();
|
||||
}
|
||||
// 如果当前“分”不为数组中当前值
|
||||
if (nMin !== mDate[mIdx]) {
|
||||
resetSecond();
|
||||
}
|
||||
|
||||
// 循环年份数组
|
||||
goYear: for (let Yi = YIdx; Yi < YDate.length; Yi++) {
|
||||
let YY = YDate[Yi];
|
||||
// 如果到达最大值时
|
||||
if (nMouth > MDate[MDate.length - 1]) {
|
||||
resetMouth();
|
||||
continue;
|
||||
}
|
||||
// 循环月份数组
|
||||
goMouth: for (let Mi = MIdx; Mi < MDate.length; Mi++) {
|
||||
// 赋值、方便后面运算
|
||||
let MM = MDate[Mi];
|
||||
MM = MM < 10 ? '0' + MM : MM;
|
||||
// 如果到达最大值时
|
||||
if (nDay > DDate[DDate.length - 1]) {
|
||||
resetDay();
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMouth();
|
||||
continue goYear;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// 循环日期数组
|
||||
goDay: for (let Di = DIdx; Di < DDate.length; Di++) {
|
||||
// 赋值、方便后面运算
|
||||
let DD = DDate[Di];
|
||||
let thisDD = DD < 10 ? '0' + DD : DD;
|
||||
|
||||
// 如果到达最大值时
|
||||
if (nHour > hDate[hDate.length - 1]) {
|
||||
resetHour();
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay();
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMouth();
|
||||
continue goYear;
|
||||
}
|
||||
continue goMouth;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断日期的合法性,不合法的话也是跳出当前循环
|
||||
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true && this.dayRule !== 'workDay' && this.dayRule !== 'lastWeek' && this.dayRule !== 'lastDay') {
|
||||
resetDay();
|
||||
continue goMouth;
|
||||
}
|
||||
// 如果日期规则中有值时
|
||||
if (this.dayRule == 'lastDay') {
|
||||
//如果不是合法日期则需要将前将日期调到合法日期即月末最后一天
|
||||
|
||||
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
DD--;
|
||||
|
||||
thisDD = DD < 10 ? '0' + DD : DD;
|
||||
}
|
||||
}
|
||||
} else if (this.dayRule == 'workDay') {
|
||||
//校验并调整如果是2月30号这种日期传进来时需调整至正常月底
|
||||
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
DD--;
|
||||
thisDD = DD < 10 ? '0' + DD : DD;
|
||||
}
|
||||
}
|
||||
// 获取达到条件的日期是星期X
|
||||
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
|
||||
// 当星期日时
|
||||
if (thisWeek == 0) {
|
||||
//先找下一个日,并判断是否为月底
|
||||
DD++;
|
||||
thisDD = DD < 10 ? '0' + DD : DD;
|
||||
//判断下一日已经不是合法日期
|
||||
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
DD -= 3;
|
||||
}
|
||||
} else if (thisWeek == 6) {
|
||||
//当星期6时只需判断不是1号就可进行操作
|
||||
if (this.dayRuleSup !== 1) {
|
||||
DD--;
|
||||
} else {
|
||||
DD += 2;
|
||||
}
|
||||
}
|
||||
} else if (this.dayRule == 'weekDay') {
|
||||
//如果指定了是星期几
|
||||
//获取当前日期是属于星期几
|
||||
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
|
||||
//校验当前星期是否在星期池(dayRuleSup)中
|
||||
if (Array.indexOf(this.dayRuleSup, thisWeek) < 0) {
|
||||
// 如果到达最大值时
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay();
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMouth();
|
||||
continue goYear;
|
||||
}
|
||||
continue goMouth;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else if (this.dayRule == 'assWeek') {
|
||||
//如果指定了是第几周的星期几
|
||||
//获取每月1号是属于星期几
|
||||
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
|
||||
if (this.dayRuleSup[1] >= thisWeek) {
|
||||
DD = (this.dayRuleSup[0] - 1) * 7 + this.dayRuleSup[1] - thisWeek + 1;
|
||||
} else {
|
||||
DD = this.dayRuleSup[0] * 7 + this.dayRuleSup[1] - thisWeek + 1;
|
||||
}
|
||||
} else if (this.dayRule == 'lastWeek') {
|
||||
//如果指定了每月最后一个星期几
|
||||
//校验并调整如果是2月30号这种日期传进来时需调整至正常月底
|
||||
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
DD--;
|
||||
thisDD = DD < 10 ? '0' + DD : DD;
|
||||
}
|
||||
}
|
||||
//获取月末最后一天是星期几
|
||||
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
|
||||
//找到要求中最近的那个星期几
|
||||
if (this.dayRuleSup < thisWeek) {
|
||||
DD -= thisWeek - this.dayRuleSup;
|
||||
} else if (this.dayRuleSup > thisWeek) {
|
||||
DD -= 7 - (this.dayRuleSup - thisWeek)
|
||||
}
|
||||
}
|
||||
// 判断时间值是否小于10置换成“05”这种格式
|
||||
DD = DD < 10 ? '0' + DD : DD;
|
||||
|
||||
// 循环“时”数组
|
||||
goHour: for (let hi = hIdx; hi < hDate.length; hi++) {
|
||||
let hh = hDate[hi] < 10 ? '0' + hDate[hi] : hDate[hi]
|
||||
|
||||
// 如果到达最大值时
|
||||
if (nMin > mDate[mDate.length - 1]) {
|
||||
resetMin();
|
||||
if (hi == hDate.length - 1) {
|
||||
resetHour();
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay();
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMouth();
|
||||
continue goYear;
|
||||
}
|
||||
continue goMouth;
|
||||
}
|
||||
continue goDay;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// 循环"分"数组
|
||||
goMin: for (let mi = mIdx; mi < mDate.length; mi++) {
|
||||
let mm = mDate[mi] < 10 ? '0' + mDate[mi] : mDate[mi];
|
||||
|
||||
// 如果到达最大值时
|
||||
if (nSecond > sDate[sDate.length - 1]) {
|
||||
resetSecond();
|
||||
if (mi == mDate.length - 1) {
|
||||
resetMin();
|
||||
if (hi == hDate.length - 1) {
|
||||
resetHour();
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay();
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMouth();
|
||||
continue goYear;
|
||||
}
|
||||
continue goMouth;
|
||||
}
|
||||
continue goDay;
|
||||
}
|
||||
continue goHour;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// 循环"秒"数组
|
||||
goSecond: for (let si = sIdx; si <= sDate.length - 1; si++) {
|
||||
let ss = sDate[si] < 10 ? '0' + sDate[si] : sDate[si];
|
||||
// 添加当前时间(时间合法性在日期循环时已经判断)
|
||||
if (MM !== '00' && DD !== '00') {
|
||||
resultArr.push(YY + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss)
|
||||
nums++;
|
||||
}
|
||||
//如果条数满了就退出循环
|
||||
if (nums == 5) break goYear;
|
||||
//如果到达最大值时
|
||||
if (si == sDate.length - 1) {
|
||||
resetSecond();
|
||||
if (mi == mDate.length - 1) {
|
||||
resetMin();
|
||||
if (hi == hDate.length - 1) {
|
||||
resetHour();
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay();
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMouth();
|
||||
continue goYear;
|
||||
}
|
||||
continue goMouth;
|
||||
}
|
||||
continue goDay;
|
||||
}
|
||||
continue goHour;
|
||||
}
|
||||
continue goMin;
|
||||
}
|
||||
} //goSecond
|
||||
} //goMin
|
||||
}//goHour
|
||||
}//goDay
|
||||
}//goMouth
|
||||
}
|
||||
// 判断100年内的结果条数
|
||||
if (resultArr.length == 0) {
|
||||
this.resultList = [this.$t('schedule.cron.no_qualifying_results')];
|
||||
} else {
|
||||
this.resultList = resultArr;
|
||||
// if (resultArr.length !== 5) {
|
||||
// this.resultList.push('最近100年内只有上面' + resultArr.length + '条结果!')
|
||||
// }
|
||||
}
|
||||
|
||||
this.$emit("resultListChange", this.resultList);
|
||||
// 计算完成-显示结果
|
||||
this.isShow = true;
|
||||
|
||||
},
|
||||
//用于计算某位数字在数组中的索引
|
||||
getIndex(arr, value) {
|
||||
if (value <= arr[0] || value > arr[arr.length - 1]) {
|
||||
return 0;
|
||||
} else {
|
||||
for (let i = 0; i < arr.length - 1; i++) {
|
||||
if (value > arr[i] && value <= arr[i + 1]) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 获取"年"数组
|
||||
getYearArr(rule, year) {
|
||||
this.dateArr[5] = this.getOrderArr(year, year + 100);
|
||||
if (rule !== undefined) {
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
this.dateArr[5] = this.getCycleArr(rule, year + 100, false)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
this.dateArr[5] = this.getAverageArr(rule, year + 100)
|
||||
} else if (rule !== '*') {
|
||||
this.dateArr[5] = this.getAssignArr(rule)
|
||||
}
|
||||
}
|
||||
},
|
||||
// 获取"月"数组
|
||||
getMouthArr(rule) {
|
||||
this.dateArr[4] = this.getOrderArr(1, 12);
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
this.dateArr[4] = this.getCycleArr(rule, 12, false)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
this.dateArr[4] = this.getAverageArr(rule, 12)
|
||||
} else if (rule !== '*') {
|
||||
this.dateArr[4] = this.getAssignArr(rule)
|
||||
}
|
||||
},
|
||||
// 获取"日"数组-主要为日期规则
|
||||
getWeekArr(rule) {
|
||||
//只有当日期规则的两个值均为“”时则表达日期是有选项的
|
||||
if (this.dayRule == '' && this.dayRuleSup == '') {
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
this.dayRule = 'weekDay';
|
||||
this.dayRuleSup = this.getCycleArr(rule, 7, false)
|
||||
} else if (rule.indexOf('#') >= 0) {
|
||||
this.dayRule = 'assWeek';
|
||||
let matchRule = rule.match(/[0-9]{1}/g);
|
||||
this.dayRuleSup = [Number(matchRule[0]), Number(matchRule[1])];
|
||||
this.dateArr[3] = [1];
|
||||
if (this.dayRuleSup[1] == 7) {
|
||||
this.dayRuleSup[1] = 0;
|
||||
}
|
||||
} else if (rule.indexOf('L') >= 0) {
|
||||
this.dayRule = 'lastWeek';
|
||||
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
|
||||
this.dateArr[3] = [31];
|
||||
if (this.dayRuleSup == 7) {
|
||||
this.dayRuleSup = 0;
|
||||
}
|
||||
} else if (rule !== '*' && rule !== '?') {
|
||||
this.dayRule = 'weekDay';
|
||||
this.dayRuleSup = this.getAssignArr(rule)
|
||||
}
|
||||
//如果weekDay时将7调整为0【week值0即是星期日】
|
||||
if (this.dayRule == 'weekDay') {
|
||||
for (let i = 0; i < this.dayRuleSup.length; i++) {
|
||||
if (this.dayRuleSup[i] == 7) {
|
||||
this.dayRuleSup[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 获取"日"数组-少量为日期规则
|
||||
getDayArr(rule) {
|
||||
this.dateArr[3] = this.getOrderArr(1, 31);
|
||||
this.dayRule = '';
|
||||
this.dayRuleSup = '';
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
this.dateArr[3] = this.getCycleArr(rule, 31, false)
|
||||
this.dayRuleSup = 'null';
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
this.dateArr[3] = this.getAverageArr(rule, 31)
|
||||
this.dayRuleSup = 'null';
|
||||
} else if (rule.indexOf('W') >= 0) {
|
||||
this.dayRule = 'workDay';
|
||||
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
|
||||
this.dateArr[3] = [this.dayRuleSup];
|
||||
} else if (rule.indexOf('L') >= 0) {
|
||||
this.dayRule = 'lastDay';
|
||||
this.dayRuleSup = 'null';
|
||||
this.dateArr[3] = [31];
|
||||
} else if (rule !== '*' && rule !== '?') {
|
||||
this.dateArr[3] = this.getAssignArr(rule)
|
||||
this.dayRuleSup = 'null';
|
||||
} else if (rule == '*') {
|
||||
this.dayRuleSup = 'null';
|
||||
}
|
||||
},
|
||||
// 获取"时"数组
|
||||
getHourArr(rule) {
|
||||
this.dateArr[2] = this.getOrderArr(0, 23);
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
this.dateArr[2] = this.getCycleArr(rule, 24, true)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
this.dateArr[2] = this.getAverageArr(rule, 23)
|
||||
} else if (rule !== '*') {
|
||||
this.dateArr[2] = this.getAssignArr(rule)
|
||||
}
|
||||
},
|
||||
// 获取"分"数组
|
||||
getMinArr(rule) {
|
||||
this.dateArr[1] = this.getOrderArr(0, 59);
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
this.dateArr[1] = this.getCycleArr(rule, 60, true)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
this.dateArr[1] = this.getAverageArr(rule, 59)
|
||||
} else if (rule !== '*') {
|
||||
this.dateArr[1] = this.getAssignArr(rule)
|
||||
}
|
||||
},
|
||||
// 获取"秒"数组
|
||||
getSecondArr(rule) {
|
||||
this.dateArr[0] = this.getOrderArr(0, 59);
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
this.dateArr[0] = this.getCycleArr(rule, 60, true)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
this.dateArr[0] = this.getAverageArr(rule, 59)
|
||||
} else if (rule !== '*') {
|
||||
this.dateArr[0] = this.getAssignArr(rule)
|
||||
}
|
||||
},
|
||||
// 根据传进来的min-max返回一个顺序的数组
|
||||
getOrderArr(min, max) {
|
||||
let arr = [];
|
||||
for (let i = min; i <= max; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
// 根据规则中指定的零散值返回一个数组
|
||||
getAssignArr(rule) {
|
||||
let arr = [];
|
||||
let assiginArr = rule.split(',');
|
||||
for (let i = 0; i < assiginArr.length; i++) {
|
||||
arr[i] = Number(assiginArr[i])
|
||||
}
|
||||
arr.sort(this.compare)
|
||||
return arr;
|
||||
},
|
||||
// 根据一定算术规则计算返回一个数组
|
||||
getAverageArr(rule, limit) {
|
||||
let arr = [];
|
||||
let agArr = rule.split('/');
|
||||
let min = Number(agArr[0]);
|
||||
let step = Number(agArr[1]);
|
||||
while (min <= limit) {
|
||||
arr.push(min);
|
||||
min += step;
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
// 根据规则返回一个具有周期性的数组
|
||||
getCycleArr(rule, limit, status) {
|
||||
//status--表示是否从0开始(则从1开始)
|
||||
let arr = [];
|
||||
let cycleArr = rule.split('-');
|
||||
let min = Number(cycleArr[0]);
|
||||
let max = Number(cycleArr[1]);
|
||||
if (min > max) {
|
||||
max += limit;
|
||||
}
|
||||
for (let i = min; i <= max; i++) {
|
||||
let add = 0;
|
||||
if (status == false && i % limit == 0) {
|
||||
add = limit;
|
||||
}
|
||||
arr.push(Math.round(i % limit + add))
|
||||
}
|
||||
arr.sort(this.compare)
|
||||
return arr;
|
||||
},
|
||||
//比较数字大小(用于Array.sort)
|
||||
compare(value1, value2) {
|
||||
if (value2 - value1 > 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
// 格式化日期格式如:2017-9-19 18:04:33
|
||||
formatDate(value, type) {
|
||||
// 计算日期相关值
|
||||
let time = typeof value == 'number' ? new Date(value) : value;
|
||||
let Y = time.getFullYear();
|
||||
let M = time.getMonth() + 1;
|
||||
let D = time.getDate();
|
||||
let h = time.getHours();
|
||||
let m = time.getMinutes();
|
||||
let s = time.getSeconds();
|
||||
let week = time.getDay();
|
||||
// 如果传递了type的话
|
||||
if (type == undefined) {
|
||||
return Y + '-' + (M < 10 ? '0' + M : M) + '-' + (D < 10 ? '0' + D : D) + ' ' + (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
|
||||
} else if (type == 'week') {
|
||||
return week;
|
||||
}
|
||||
},
|
||||
// 检查日期是否存在
|
||||
checkDate(value) {
|
||||
let time = new Date(value);
|
||||
let format = this.formatDate(time)
|
||||
return value == format ? true : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.popup-result-scroll {
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
height: 10em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.popup-result {
|
||||
box-sizing: border-box;
|
||||
line-height: 24px;
|
||||
margin: 10px auto;
|
||||
padding: 15px 10px 10px;
|
||||
border: 1px solid #ccc;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,133 +0,0 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="1">
|
||||
{{$t('schedule.cron.seconds')}},{{$t('schedule.cron.allowed_wildcards')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="2">
|
||||
{{$t('schedule.cron.period')}} {{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='cycle01' :min="0" :max="59" /> -
|
||||
<el-input-number v-model='cycle02' :min="0" :max="59" /> {{$t('schedule.cron.seconds')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="3">
|
||||
{{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='average01' :min="0" :max="59" /> {{$t('schedule.cron.seconds')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||
<el-input-number v-model='average02' :min="0" :max="60" /> {{$t('schedule.cron.seconds')}}{{$t('schedule.cron.execute_once')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="4">
|
||||
{{$t('schedule.cron.specify')}}
|
||||
<el-select clearable v-model="checkboxList" :placeholder="$t('schedule.cron.multi_select')" multiple style="width:100%">
|
||||
<el-option v-for="item in 60" :key="item" :value="item-1">{{item-1}}</el-option>
|
||||
</el-select>
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
radioValue: 1,
|
||||
cycle01: 1,
|
||||
cycle02: 2,
|
||||
average01: 0,
|
||||
average02: 1,
|
||||
checkboxList: [],
|
||||
checkNum: this.$options.propsData.check
|
||||
}
|
||||
},
|
||||
name: 'CrontabSecond',
|
||||
props: ['check', 'radioParent'],
|
||||
methods: {
|
||||
// 单选按钮值变化时
|
||||
radioChange() {
|
||||
switch (this.radioValue) {
|
||||
case 1:
|
||||
this.$emit('update', 'second', '*', 'second');
|
||||
this.$emit('update', 'min', '*', 'second');
|
||||
break;
|
||||
case 2:
|
||||
this.$emit('update', 'second', this.cycle01 + '-' + this.cycle02);
|
||||
break;
|
||||
case 3:
|
||||
this.$emit('update', 'second', this.average01 + '/' + this.average02);
|
||||
break;
|
||||
case 4:
|
||||
this.$emit('update', 'second', this.checkboxString);
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 周期两个值变化时
|
||||
cycleChange() {
|
||||
if (this.radioValue == '2') {
|
||||
this.$emit('update', 'second', this.cycleTotal);
|
||||
}
|
||||
},
|
||||
// 平均两个值变化时
|
||||
averageChange() {
|
||||
if (this.radioValue == '3') {
|
||||
this.$emit('update', 'second', this.averageTotal);
|
||||
}
|
||||
},
|
||||
// checkbox值变化时
|
||||
checkboxChange() {
|
||||
if (this.radioValue == '4') {
|
||||
this.$emit('update', 'second', this.checkboxString);
|
||||
}
|
||||
},
|
||||
othChange() {
|
||||
//反解析
|
||||
let ins = this.cron.second
|
||||
// ('反解析 second', ins);
|
||||
if (ins === '*') {
|
||||
this.radioValue = 1;
|
||||
} else if (ins.indexOf('-') > -1) {
|
||||
this.radioValue = 2
|
||||
} else if (ins.indexOf('/') > -1) {
|
||||
this.radioValue = 3
|
||||
} else {
|
||||
this.radioValue = 4
|
||||
this.checkboxList = ins.split(',')
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"radioValue": "radioChange",
|
||||
'cycleTotal': 'cycleChange',
|
||||
'averageTotal': 'averageChange',
|
||||
'checkboxString': 'checkboxChange',
|
||||
radioParent() {
|
||||
this.radioValue = this.radioParent
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 计算两个周期值
|
||||
cycleTotal: function () {
|
||||
this.checkNum(this.cycle01, 0, 59);
|
||||
this.checkNum(this.cycle02, 0, 59);
|
||||
return this.cycle01 + '-' + this.cycle02;
|
||||
},
|
||||
// 计算平均用到的值
|
||||
averageTotal: function () {
|
||||
this.checkNum(this.average01, 0, 59)
|
||||
this.checkNum(this.average02, 1, 59)
|
||||
return this.average01 + '/' + this.average02;
|
||||
},
|
||||
// 计算勾选的checkbox值合集
|
||||
checkboxString: function () {
|
||||
let str = this.checkboxList.join();
|
||||
return str == '' ? '*' : str;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,174 +0,0 @@
|
||||
<template>
|
||||
<el-form size='small'>
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="1">
|
||||
{{$t('schedule.cron.weeks')}},{{$t('schedule.cron.weeks_allowed_wildcards')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="2">
|
||||
{{$t('schedule.cron.not_specify')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="3">
|
||||
{{$t('schedule.cron.period')}} {{$t('schedule.cron.from')}}{{$t('schedule.cron.week')}}
|
||||
<el-input-number v-model='cycle01' :min="1" :max="7" /> -
|
||||
<el-input-number v-model='cycle02' :min="1" :max="7" />
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="4">
|
||||
{{$t('schedule.cron.num')}}
|
||||
<el-input-number v-model='average01' :min="1" :max="4" /> {{$t('schedule.cron.week_of_weeks')}}
|
||||
<el-input-number v-model='average02' :min="1" :max="7" />
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="5">
|
||||
{{$t('schedule.cron.last_week_of_the_month')}}
|
||||
<el-input-number v-model='weekday' :min="1" :max="7" />
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model='radioValue' :label="6">
|
||||
{{$t('schedule.cron.specify')}}
|
||||
<el-select clearable v-model="checkboxList" :placeholder="$t('schedule.cron.multi_select')" multiple style="width:100%">
|
||||
<el-option v-for="(item,index) of weekList" :key="index" :value="index+1">{{item}}</el-option>
|
||||
</el-select>
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
radioValue: 2,
|
||||
weekday: 1,
|
||||
cycle01: 1,
|
||||
cycle02: 2,
|
||||
average01: 1,
|
||||
average02: 1,
|
||||
checkboxList: [],
|
||||
weekList: [this.$t('commons.weeks_1'),
|
||||
this.$t('commons.weeks_2'),
|
||||
this.$t('commons.weeks_3'),
|
||||
this.$t('commons.weeks_4'),
|
||||
this.$t('commons.weeks_5'),
|
||||
this.$t('commons.weeks_6'),
|
||||
this.$t('commons.weeks_0'),
|
||||
],
|
||||
checkNum: this.$options.propsData.check
|
||||
}
|
||||
},
|
||||
name: 'CrontabWeek',
|
||||
props: ['check', 'cron'],
|
||||
methods: {
|
||||
// 单选按钮值变化时
|
||||
radioChange() {
|
||||
if (this.radioValue === 1) {
|
||||
this.$emit('update', 'week', '*');
|
||||
this.$emit('update', 'year', '*');
|
||||
} else {
|
||||
if (this.cron.mouth === '*') {
|
||||
this.$emit('update', 'mouth', '1', 'week');
|
||||
}
|
||||
if (this.cron.day === '*') {
|
||||
this.$emit('update', 'day', '1', 'week');
|
||||
}
|
||||
if (this.cron.hour === '*') {
|
||||
this.$emit('update', 'hour', '0', 'week');
|
||||
}
|
||||
if (this.cron.min === '*') {
|
||||
this.$emit('update', 'min', '0', 'week');
|
||||
}
|
||||
if (this.cron.second === '*') {
|
||||
this.$emit('update', 'second', '0', 'week');
|
||||
}
|
||||
}
|
||||
switch (this.radioValue) {
|
||||
case 2:
|
||||
this.$emit('update', 'week', '?');
|
||||
break;
|
||||
case 3:
|
||||
this.$emit('update', 'week', this.cycle01 + '-' + this.cycle02);
|
||||
break;
|
||||
case 4:
|
||||
this.$emit('update', 'week', this.average01 + '#' + this.average02);
|
||||
break;
|
||||
case 5:
|
||||
this.$emit('update', 'week', this.weekday + 'L');
|
||||
break;
|
||||
case 6:
|
||||
this.$emit('update', 'week', this.checkboxString);
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 根据互斥事件,更改radio的值
|
||||
|
||||
// 周期两个值变化时
|
||||
cycleChange() {
|
||||
if (this.radioValue == '3') {
|
||||
this.$emit('update', 'week', this.cycleTotal);
|
||||
}
|
||||
},
|
||||
// 平均两个值变化时
|
||||
averageChange() {
|
||||
if (this.radioValue == '4') {
|
||||
this.$emit('update', 'week', this.averageTotal);
|
||||
}
|
||||
},
|
||||
// 最近工作日值变化时
|
||||
weekdayChange() {
|
||||
if (this.radioValue == '5') {
|
||||
this.$emit('update', 'week', this.weekday + 'L');
|
||||
}
|
||||
},
|
||||
// checkbox值变化时
|
||||
checkboxChange() {
|
||||
if (this.radioValue == '6') {
|
||||
this.$emit('update', 'week', this.checkboxString);
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"radioValue": "radioChange",
|
||||
'cycleTotal': 'cycleChange',
|
||||
'averageTotal': 'averageChange',
|
||||
'weekdayCheck': 'weekdayChange',
|
||||
'checkboxString': 'checkboxChange',
|
||||
},
|
||||
computed: {
|
||||
// 计算两个周期值
|
||||
cycleTotal: function () {
|
||||
this.checkNum(this.cycle01, 1, 7)
|
||||
this.checkNum(this.cycle02, 1, 7)
|
||||
return this.cycle01 + '-' + this.cycle02;
|
||||
},
|
||||
// 计算平均用到的值
|
||||
averageTotal: function () {
|
||||
this.checkNum(this.average01, 1, 4)
|
||||
this.checkNum(this.average02, 1, 7)
|
||||
return this.average01 + '#' + this.average02;
|
||||
},
|
||||
// 最近的工作日(格式)
|
||||
weekdayCheck: function () {
|
||||
this.checkNum(this.weekday, 1, 7)
|
||||
return this.weekday;
|
||||
},
|
||||
// 计算勾选的checkbox值合集
|
||||
checkboxString: function () {
|
||||
let str = this.checkboxList.join();
|
||||
return str == '' ? '?' : str;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,144 +0,0 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio :label="1" v-model='radioValue'>
|
||||
{{$t('schedule.cron.not_fill')}},{{$t('schedule.cron.allowed_wildcards')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio :label="2" v-model='radioValue'>
|
||||
{{$t('schedule.cron.every')}}{{$t('schedule.cron.years')}}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio :label="3" v-model='radioValue'>
|
||||
{{$t('schedule.cron.period')}} {{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='cycle01' :min='fullYear' /> -
|
||||
<el-input-number v-model='cycle02' :min='fullYear' />
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio :label="4" v-model='radioValue'>
|
||||
{{$t('schedule.cron.from')}}
|
||||
<el-input-number v-model='average01' :min='fullYear' /> {{$t('schedule.cron.years')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||
<el-input-number v-model='average02' :min='fullYear' /> {{$t('schedule.cron.years')}}{{$t('schedule.cron.execute_once')}}
|
||||
</el-radio>
|
||||
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio :label="5" v-model='radioValue'>
|
||||
指定
|
||||
<el-select clearable v-model="checkboxList" :placeholder="$t('schedule.cron.multi_select')" multiple>
|
||||
<el-option v-for="item in 9" :key="item" :value="item - 1 + fullYear" :label="item -1 + fullYear" />
|
||||
</el-select>
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
fullYear: 0,
|
||||
radioValue: 1,
|
||||
cycle01: 0,
|
||||
cycle02: 0,
|
||||
average01: 0,
|
||||
average02: 1,
|
||||
checkboxList: [],
|
||||
checkNum: this.$options.propsData.check
|
||||
}
|
||||
},
|
||||
name: 'CrontabYear',
|
||||
props: ['check', 'mouth', 'cron'],
|
||||
methods: {
|
||||
// 单选按钮值变化时
|
||||
radioChange() {
|
||||
if (this.cron.mouth === '*') {
|
||||
this.$emit('update', 'mouth', '1', 'year');
|
||||
}
|
||||
if (this.cron.day === '*') {
|
||||
this.$emit('update', 'day', '1', 'year');
|
||||
}
|
||||
if (this.cron.hour === '*') {
|
||||
this.$emit('update', 'hour', '0', 'year');
|
||||
}
|
||||
if (this.cron.min === '*') {
|
||||
this.$emit('update', 'min', '0', 'year');
|
||||
}
|
||||
if (this.cron.second === '*') {
|
||||
this.$emit('update', 'second', '0', 'year');
|
||||
}
|
||||
switch (this.radioValue) {
|
||||
case 1:
|
||||
this.$emit('update', 'year', '');
|
||||
break;
|
||||
case 2:
|
||||
this.$emit('update', 'year', '*');
|
||||
break;
|
||||
case 3:
|
||||
this.$emit('update', 'year', this.cycle01 + '-' + this.cycle02);
|
||||
break;
|
||||
case 4:
|
||||
this.$emit('update', 'year', this.average01 + '/' + this.average02);
|
||||
break;
|
||||
case 5:
|
||||
this.$emit('update', 'year', this.checkboxString);
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 周期两个值变化时
|
||||
cycleChange() {
|
||||
if (this.radioValue == '3') {
|
||||
this.$emit('update', 'year', this.cycleTotal);
|
||||
}
|
||||
},
|
||||
// 平均两个值变化时
|
||||
averageChange() {
|
||||
if (this.radioValue == '4') {
|
||||
this.$emit('update', 'year', this.averageTotal);
|
||||
}
|
||||
},
|
||||
// checkbox值变化时
|
||||
checkboxChange() {
|
||||
if (this.radioValue == '5') {
|
||||
this.$emit('update', 'year', this.checkboxString);
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"radioValue": "radioChange",
|
||||
'cycleTotal': 'cycleChange',
|
||||
'averageTotal': 'averageChange',
|
||||
'checkboxString': 'checkboxChange'
|
||||
},
|
||||
computed: {
|
||||
// 计算两个周期值
|
||||
cycleTotal: function () {
|
||||
this.checkNum(this.cycle01, this.fullYear, this.fullYear + 100)
|
||||
this.checkNum(this.cycle02, this.fullYear + 1, this.fullYear + 101)
|
||||
return this.cycle01 + '-' + this.cycle02;
|
||||
},
|
||||
// 计算平均用到的值
|
||||
averageTotal: function () {
|
||||
this.checkNum(this.average01, this.fullYear, this.fullYear + 100)
|
||||
this.checkNum(this.average02, 1, 10)
|
||||
return this.average01 + '/' + this.average02;
|
||||
},
|
||||
// 计算勾选的checkbox值合集
|
||||
checkboxString: function () {
|
||||
let str = this.checkboxList.join();
|
||||
return str;
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
// 仅获取当前年份
|
||||
this.fullYear = Number(new Date().getFullYear());
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,3 +0,0 @@
|
||||
@import './main.css';
|
||||
/* @import './menu-header.css';
|
||||
@import '../theme/index.css'; */
|
@ -1,204 +0,0 @@
|
||||
.container {
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* body {
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
} */
|
||||
|
||||
/* 解决 document.body.clientHeight 为0 */
|
||||
html,body {
|
||||
height:100%
|
||||
}
|
||||
|
||||
.main-content span.title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-top: 0;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 解决高度塌陷和边距重叠 */
|
||||
.clearfix:before, .clearfix:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* 解决富文本框中link显示问题 */
|
||||
.ck-rounded-corners .ck.ck-balloon-panel, .ck.ck-balloon-panel.ck-rounded-corners {
|
||||
z-index: 10055 !important;
|
||||
}
|
||||
|
||||
.table-card > .el-card__body {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
/* Safari 表格不错位 */
|
||||
.el-table__body {
|
||||
width: 100%;
|
||||
table-layout: fixed !important;
|
||||
}
|
||||
|
||||
/* <-- 表格拖拽表头调整宽度,在 t-bable 上添加 border 属性,并添加 adjust-table 类名 */
|
||||
.adjust-table td {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.adjust-table th {
|
||||
border-right-color: white;
|
||||
}
|
||||
|
||||
.adjust-table {
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
.adjust-table:after {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.adjust-table th:not([class*="el-table-column--selection"]):hover:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 25%;
|
||||
right: 0;
|
||||
height: 50%;
|
||||
width: 2px;
|
||||
background-color: #EBEEF5;
|
||||
}
|
||||
|
||||
.adjust-table tr:hover td {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
/* 表格拖拽表头调整宽度 --> */
|
||||
|
||||
/* <-- 表格 input 编辑效果 */
|
||||
.table-edit-input .el-textarea__inner {
|
||||
border-style: hidden;
|
||||
}
|
||||
|
||||
.table-edit-input.is-disabled .el-textarea__inner {
|
||||
background-color: white;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.el-table .current-row .table-edit-input {
|
||||
border: 1px solid #DCDFE6;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.table-edit-input .el-textarea__inner:focus {
|
||||
border: 1px solid #409EFF;
|
||||
}
|
||||
|
||||
/* 表格 input 编辑效果 --> */
|
||||
|
||||
.ms-border {
|
||||
padding: 10px;
|
||||
border: #DCDFE6 solid 1px;
|
||||
margin: 5px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* 修复带长度限制的文本框,内容太长造成的无法查看内容的问题 */
|
||||
|
||||
.el-input__inner[maxlength] {
|
||||
padding-right: 60px;
|
||||
}
|
||||
|
||||
/* 滚动条样式 */
|
||||
::-webkit-scrollbar{
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
position: fixed;
|
||||
}
|
||||
::-webkit-scrollbar-thumb{
|
||||
border-radius: 1em;
|
||||
background-color: rgba(50,50,50,.3);
|
||||
position: fixed;
|
||||
}
|
||||
::-webkit-scrollbar-track{
|
||||
border-radius: 1em;
|
||||
background-color: transparent;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
/* <-- 表格全选样式 */
|
||||
.ms-select-all th:first-child.el-table-column--selection {
|
||||
border: 1px solid #DCDFE6;
|
||||
border-radius:5px;
|
||||
padding: 0px;
|
||||
margin-top: 10px;
|
||||
display: inline-block;
|
||||
/*margin-top: 25px;*/
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.ms-select-all th:nth-child(2) {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.ms-select-all th:first-child.el-table-column--selection>.cell {
|
||||
padding: 5px;
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
.ms-select-all th:nth-child(2)>.cell {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.ms-select-all th:nth-child(2) .el-icon-arrow-down {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
top: -7px;
|
||||
left: -38px;
|
||||
width: 30px;
|
||||
}
|
||||
/* 表格全选样式 --> */
|
||||
|
||||
/* <-- 表格全选样式 (列固定表格样式) */
|
||||
.ms-select-all-fixed th:first-child.el-table-column--selection {
|
||||
border: 1px solid #DCDFE6;
|
||||
border-radius:5px;
|
||||
padding: 0px;
|
||||
margin-top: 10px;
|
||||
display: inline-block;
|
||||
/*margin-top: 25px;*/
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.ms-select-all-fixed th:nth-child(2) {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.ms-select-all-fixed th:first-child.el-table-column--selection>.cell {
|
||||
padding: 5px;
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
.ms-select-all-fixed th:nth-child(2)>.cell {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.ms-select-all-fixed th:nth-child(2) .el-icon-arrow-down {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
top: -9px;
|
||||
left: -30px;
|
||||
width: 30px;
|
||||
}
|
||||
/* 表格全选样式 --> */
|
@ -1,22 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(./material.woff2) format('woff2');
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
-webkit-font-feature-settings: 'liga';
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
Binary file not shown.
@ -1,38 +0,0 @@
|
||||
.header-menu.el-menu--horizontal > li {
|
||||
height: 39px;
|
||||
line-height: 40px;
|
||||
color: dimgray;
|
||||
}
|
||||
|
||||
.header-menu.el-menu--horizontal > li.el-submenu > * {
|
||||
height: 39px;
|
||||
line-height: 40px;
|
||||
color: dimgray;
|
||||
}
|
||||
|
||||
.header-user-menu.el-menu--horizontal > li.el-submenu > * {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
.header-top-menus.el-menu--horizontal > li {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.header-top-menus.el-menu--horizontal > li.el-submenu > * {
|
||||
height: 39px;
|
||||
line-height: 40px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.header-top-menus.el-menu--horizontal > li.is-active {
|
||||
background: #595591 !important;
|
||||
}
|
||||
|
||||
.el-menu.el-menu--horizontal {
|
||||
border-bottom: none;
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
const ReportStyle = `.body{
|
||||
font-size: 14px;
|
||||
color: #7B0274;
|
||||
}
|
||||
.container {
|
||||
height: 100vh;
|
||||
background: #F5F5F5;
|
||||
}
|
||||
.preview {
|
||||
position: relative;
|
||||
}
|
||||
/* <-- 表格拖拽表头调整宽度,在 t-bable 上添加 border 属性,并添加 adjust-table 类名*/
|
||||
.adjust-table td {
|
||||
border-right-color: white;
|
||||
}
|
||||
|
||||
.adjust-table th {
|
||||
border-right-color: white;
|
||||
}
|
||||
|
||||
.adjust-table {
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
.adjust-table:after {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.adjust-table th:hover:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 25%;
|
||||
right: 0;
|
||||
height: 50%;
|
||||
width: 3px;
|
||||
background-color: #EBEEF5;
|
||||
}
|
||||
span {
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.el-col span:first-child {
|
||||
font-weight: bold;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.el-row {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.select-time span {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.el-date-editor {
|
||||
width: 150px;
|
||||
}
|
||||
`
|
||||
|
||||
export default ReportStyle;
|
@ -1,108 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="$t('commons.about_us')"
|
||||
:visible.sync="dialogVisible" class="about-us">
|
||||
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-link :underline="false" :href="websiteUrl" target="_blank">
|
||||
<img class="logo" src="../../../../assets/favicon-彩色.png"/>
|
||||
</el-link>
|
||||
<el-link class="url" :href="websiteUrl" target="_blank">
|
||||
<span>{{websiteUrl}}</span>
|
||||
</el-link>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col>
|
||||
<div class="github">
|
||||
<el-link :underline="false" :href="githubUrl" target="_blank">
|
||||
<font-awesome-icon class="github-icon" :icon="['fab', 'github-square']"/>
|
||||
</el-link>
|
||||
</div>
|
||||
<el-link class="url" :href="githubUrl" target="_blank">
|
||||
<span>{{githubUrl}}</span>
|
||||
</el-link>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col class="version">
|
||||
<span>版本:</span>
|
||||
<span>{{version}}</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "AboutUs",
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
githubUrl: 'https://github.com/metersphere/metersphere',
|
||||
websiteUrl: 'https://metersphere.io',
|
||||
version: '1.0.1'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getVersion();
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
getVersion() {
|
||||
// this.$get('/system/version', response => {
|
||||
// this.version = response.data;
|
||||
// });
|
||||
this.version = "1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.logo {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
vertical-align: middle
|
||||
}
|
||||
|
||||
.version {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.github-icon {
|
||||
font-size: 20px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.github {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
line-height: 30px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
.el-row {
|
||||
margin-bottom: 3%;
|
||||
}
|
||||
|
||||
.url {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.about-us >>> .el-dialog {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,22 +0,0 @@
|
||||
<template>
|
||||
<el-menu-item :index="this.index">
|
||||
<el-button type="text" class="create-button">{{this.title}}</el-button>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsCreateButton",
|
||||
props: {
|
||||
index: String,
|
||||
title: String,
|
||||
click: Function
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.create-button {
|
||||
padding-left: 18px;
|
||||
}
|
||||
</style>
|
@ -1,32 +0,0 @@
|
||||
<template>
|
||||
<router-link class="create-test" :to="this.to" v-permission="this.permission">
|
||||
<el-button type="primary" size="small">{{this.title}}</el-button>
|
||||
</router-link>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsCreateTest",
|
||||
props: {
|
||||
to: [String, Object],
|
||||
title: {
|
||||
type: String,
|
||||
default: function () {
|
||||
return this.$t('load_test.create');
|
||||
}
|
||||
},
|
||||
permission: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return ['test_user', 'test_manager'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.create-test {
|
||||
line-height: 38px;
|
||||
}
|
||||
</style>
|
@ -1,232 +0,0 @@
|
||||
<template>
|
||||
<el-menu
|
||||
:unique-opened="true"
|
||||
mode="horizontal"
|
||||
router
|
||||
class="header-user-menu align-right"
|
||||
background-color="#2c2a48"
|
||||
active-text-color="#fff"
|
||||
default-active="1"
|
||||
text-color="#fff"
|
||||
>
|
||||
<el-menu-item v-show="false" index="1">Placeholder</el-menu-item>
|
||||
<el-submenu
|
||||
v-roles="['org_admin', 'test_manager', 'test_user', 'test_viewer']"
|
||||
index="1"
|
||||
popper-class="org-ws-submenu"
|
||||
>
|
||||
<template v-slot:title>{{ $t('commons.organization') }}: {{ currentOrganizationName }}</template>
|
||||
<el-input
|
||||
v-model="searchOrg"
|
||||
:placeholder="$t('project.search_by_name')"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
class="search-input"
|
||||
size="small"
|
||||
/>
|
||||
<div class="org-ws-menu">
|
||||
<el-menu-item v-for="(item,index) in organizationList" :key="index" @click="changeOrg(item)">
|
||||
{{ item.name }}
|
||||
<i
|
||||
v-if="item.id === currentUserInfo.lastOrganizationId"
|
||||
class="el-icon-check"
|
||||
/>
|
||||
</el-menu-item>
|
||||
</div>
|
||||
</el-submenu>
|
||||
<el-submenu v-roles="['test_manager', 'test_user', 'test_viewer']" index="2" popper-class="submenu">
|
||||
<template v-slot:title>{{ $t('commons.workspace') }}: {{ currentWorkspaceName }}</template>
|
||||
<el-input
|
||||
v-model="searchWs"
|
||||
:placeholder="$t('project.search_by_name')"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
class="search-input"
|
||||
size="small"
|
||||
/>
|
||||
<div class="org-ws-menu">
|
||||
<el-menu-item v-for="(item,index) in workspaceList" :key="index" @click="changeWs(item)">
|
||||
{{ item.name }}
|
||||
<i v-if="item.id === currentUserInfo.lastWorkspaceId" class="el-icon-check" />
|
||||
</el-menu-item>
|
||||
</div>
|
||||
</el-submenu>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
PROJECT_ID,
|
||||
ROLE_ORG_ADMIN,
|
||||
ROLE_TEST_MANAGER,
|
||||
ROLE_TEST_USER,
|
||||
ROLE_TEST_VIEWER,
|
||||
WORKSPACE_ID
|
||||
} from '@/metersphere/common/js/constants'
|
||||
import { getCurrentUser, hasRoles, saveLocalStorage } from '@/metersphere/common/js/utils'
|
||||
|
||||
export default {
|
||||
name: 'MsHeaderOrgWs',
|
||||
data() {
|
||||
return {
|
||||
organizationList: [
|
||||
{ name: this.$t('organization.none') }
|
||||
],
|
||||
workspaceList: [
|
||||
{ name: this.$t('workspace.none') }
|
||||
],
|
||||
currentUserInfo: {},
|
||||
currentUserId: getCurrentUser().id,
|
||||
workspaceIds: [],
|
||||
currentOrganizationName: '',
|
||||
currentWorkspaceName: '',
|
||||
searchOrg: '',
|
||||
searchWs: '',
|
||||
orgListCopy: [{ name: this.$t('organization.none') }],
|
||||
wsListCopy: [{ name: this.$t('workspace.none') }]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentUser: () => {
|
||||
return getCurrentUser()
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchOrg(val) {
|
||||
this.query('org', val)
|
||||
},
|
||||
searchWs(val) {
|
||||
this.query('ws', val)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initMenuData()
|
||||
this.getCurrentUserInfo()
|
||||
},
|
||||
methods: {
|
||||
initMenuData() {
|
||||
if (hasRoles(ROLE_ORG_ADMIN, ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.$get('/organization/list/userorg/' + encodeURIComponent(this.currentUserId), response => {
|
||||
const data = response.data
|
||||
this.organizationList = data
|
||||
this.orgListCopy = data
|
||||
const org = data.filter(r => r.id === this.currentUser.lastOrganizationId)
|
||||
if (org.length > 0) {
|
||||
this.currentOrganizationName = org[0].name
|
||||
}
|
||||
})
|
||||
}
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
if (!this.currentUser.lastOrganizationId) {
|
||||
return false
|
||||
}
|
||||
this.$get('/workspace/list/orgworkspace/', response => {
|
||||
const data = response.data
|
||||
if (data.length === 0) {
|
||||
this.workspaceList = [{ name: this.$t('workspace.none') }]
|
||||
} else {
|
||||
this.workspaceList = data
|
||||
this.wsListCopy = data
|
||||
const workspace = data.filter(r => r.id === this.currentUser.lastWorkspaceId)
|
||||
if (workspace.length > 0) {
|
||||
this.currentWorkspaceName = workspace[0].name
|
||||
localStorage.setItem(WORKSPACE_ID, workspace[0].id)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
getCurrentUserInfo() {
|
||||
this.$get('/user/info/' + encodeURIComponent(this.currentUserId), response => {
|
||||
this.currentUserInfo = response.data
|
||||
})
|
||||
},
|
||||
changeOrg(data) {
|
||||
const orgId = data.id
|
||||
if (!orgId) {
|
||||
return false
|
||||
}
|
||||
this.$post('/user/switch/source/org/' + orgId, {}, response => {
|
||||
saveLocalStorage(response)
|
||||
if (response.data.workspaceId) {
|
||||
localStorage.setItem('workspace_id', response.data.workspaceId)
|
||||
}
|
||||
localStorage.removeItem(PROJECT_ID)
|
||||
this.$router.push('/').then(() => {
|
||||
window.location.reload()
|
||||
}).catch(err => err)
|
||||
})
|
||||
},
|
||||
changeWs(data) {
|
||||
const workspaceId = data.id
|
||||
if (!workspaceId) {
|
||||
return false
|
||||
}
|
||||
this.$post('/user/switch/source/ws/' + workspaceId, {}, response => {
|
||||
saveLocalStorage(response)
|
||||
localStorage.setItem('workspace_id', workspaceId)
|
||||
localStorage.removeItem(PROJECT_ID)
|
||||
this.$router.push('/').then(() => {
|
||||
window.location.reload()
|
||||
}).catch(err => err)
|
||||
})
|
||||
},
|
||||
query(sign, queryString) {
|
||||
if (sign === 'org') {
|
||||
this.organizationList = queryString ? this.orgListCopy.filter(this.createFilter(queryString)) : this.orgListCopy
|
||||
}
|
||||
if (sign === 'ws') {
|
||||
this.workspaceList = queryString ? this.wsListCopy.filter(this.createFilter(queryString)) : this.wsListCopy
|
||||
}
|
||||
},
|
||||
createFilter(queryString) {
|
||||
return item => {
|
||||
return (item.name.toLowerCase().indexOf(queryString.toLowerCase()) !== -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-icon-check {
|
||||
color: #44b349;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 1em;
|
||||
background-color: #595591;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 1em;
|
||||
background-color: transparent;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.org-ws-menu {
|
||||
height: 180px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
padding: 0;
|
||||
margin-top: -4px;
|
||||
background-color: #595591;
|
||||
}
|
||||
|
||||
.search-input >>> .el-input__inner {
|
||||
border-radius: 0;
|
||||
background-color: #2d2a49;
|
||||
color: #d2ced8;
|
||||
border-color: #b4aebe;
|
||||
}
|
||||
</style>
|
@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<el-menu mode="horizontal" menu-trigger="click"
|
||||
background-color="#2c2a48"
|
||||
class="header-top-menus"
|
||||
text-color="#F2F2F2"
|
||||
active-text-color="#fff"
|
||||
:default-active="activeIndex"
|
||||
@select="handleSelect"
|
||||
router>
|
||||
|
||||
<!-- <el-menu-item index="/track" v-permission="['test_manager','test_user','test_viewer']">
|
||||
{{ $t('test_track.test_track') }}
|
||||
</el-menu-item> -->
|
||||
<el-menu-item index="/chart" @click="active()" >
|
||||
{{ $t('commons.api') }}
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/dataset" onselectstart="return false"
|
||||
>
|
||||
{{ $t('commons.dataset') }}
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/setting" onselectstart="return false">
|
||||
{{ $t('commons.system_setting') }}
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsTopMenus",
|
||||
data() {
|
||||
return {
|
||||
activeIndex: '/'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$route'(to) {
|
||||
if (to.matched.length > 0) {
|
||||
this.activeIndex = to.matched[0].path;
|
||||
}
|
||||
this.handleSelect(this.activeIndex);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.$route.matched.length > 0) {
|
||||
this.activeIndex = this.$route.matched[0].path;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSelect(index) {
|
||||
this.activeIndex = index
|
||||
},
|
||||
active() {
|
||||
if (this.activeIndex === '/api') {
|
||||
if (this.$store.state.switch.value == 'new') {
|
||||
window.location.href = "/#/api/home";
|
||||
} else if (this.$store.state.switch.value == 'old') {
|
||||
window.location.href = "/#/api/home_obsolete";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
.el-menu >>> .el-menu-item {
|
||||
box-sizing: border-box;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,111 +0,0 @@
|
||||
<template>
|
||||
<el-dropdown size="medium" @command="handleCommand" class="align-right">
|
||||
<span class="dropdown-link">
|
||||
{{ currentUser.username }}<i class="el-icon-caret-bottom el-icon--right"/>
|
||||
</span>
|
||||
<template v-slot:dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="personal">{{ $t('commons.personal_information') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="about">{{ $t('commons.about_us') }} <i class="el-icon-info"/></el-dropdown-item>
|
||||
<el-dropdown-item command="help">{{ $t('commons.help_documentation') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="ApiHelp">{{ $t('commons.api_help_documentation') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="old" v-show=isReadOnly @click.native="changeBar('old')">
|
||||
{{ $t('commons.cut_back_old_version') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="new" v-show=!isReadOnly @click.native="changeBar('new')">
|
||||
{{ $t('commons.cut_back_new_version') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="logout">{{ $t('commons.exit_system') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
|
||||
<about-us ref="aboutUs"/>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getUserInfo} from "@/common/js/utils";
|
||||
import AboutUs from "./AboutUs";
|
||||
import axios from "axios";
|
||||
import {removeToken} from '@/utils/auth'
|
||||
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
|
||||
const auth = requireComponent.keys().length > 0 ? requireComponent("./auth/Auth.vue") : {};
|
||||
|
||||
export default {
|
||||
name: "MsUser",
|
||||
components: {AboutUs},
|
||||
data() {
|
||||
return {
|
||||
isReadOnly: this.$store.state.isReadOnly.flag
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentUser: () => {
|
||||
return getUserInfo();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
logout: function () {
|
||||
axios.get("/signout").then(response => {
|
||||
if (response.data.success) {
|
||||
localStorage.clear();
|
||||
removeToken();
|
||||
window.location.href = "/login";
|
||||
}
|
||||
}).catch(error => {
|
||||
localStorage.clear();
|
||||
window.location.href = "/login";
|
||||
});
|
||||
},
|
||||
handleCommand(command) {
|
||||
switch (command) {
|
||||
case "personal":
|
||||
// TODO 优化路由跳转,避免重复添加路由
|
||||
this.$router.push('/setting/personsetting').catch(error => error);
|
||||
break;
|
||||
case "logout":
|
||||
this.logout();
|
||||
break;
|
||||
case "about":
|
||||
this.$refs.aboutUs.open();
|
||||
break;
|
||||
case "help":
|
||||
window.location.href = "https://metersphere.io/docs/index.html";
|
||||
break;
|
||||
case "ApiHelp":
|
||||
window.open('/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config', "_blank");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
changeBar(item) {
|
||||
this.isReadOnly = !this.isReadOnly
|
||||
this.$store.commit('setFlag', this.isReadOnly);
|
||||
this.$store.commit('setValue', item);
|
||||
if (item == "old") {
|
||||
window.location.href = "/#/api/home_obsolete";
|
||||
} else {
|
||||
window.location.href = "/#/api/home";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dropdown-link {
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: rgb(245, 245, 245);
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
@ -1,102 +0,0 @@
|
||||
<template>
|
||||
<el-menu
|
||||
:unique-opened="true"
|
||||
class="header-user-menu align-right"
|
||||
mode="horizontal"
|
||||
background-color="#2c2a48"
|
||||
text-color="#fff"
|
||||
active-text-color="#fff"
|
||||
>
|
||||
<el-submenu index="1">
|
||||
<template slot="title">
|
||||
<font-awesome-icon class="icon global" :icon="['fas', 'globe']" />
|
||||
<span>{{ language }}</span>
|
||||
</template>
|
||||
<el-menu-item v-for="(value, key) in languageMap" :key="key" @click="changeLanguage(key)">
|
||||
{{ value }} <i v-if="language === value" class="el-icon-check" />
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DEFAULT_LANGUAGE, EN_US, TokenKey, ZH_CN, ZH_TW } from '@/metersphere/common/js/constants'
|
||||
import { getCurrentUser } from '@/metersphere/common/js/utils'
|
||||
|
||||
export default {
|
||||
name: 'MsLanguageSwitch',
|
||||
data() {
|
||||
return {
|
||||
currentUserInfo: {},
|
||||
language: '',
|
||||
languageMap: {
|
||||
[ZH_CN]: '简体中文',
|
||||
[EN_US]: 'English',
|
||||
[ZH_TW]: '繁體中文'
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
let lang = this.currentUser().language
|
||||
this.currentUserInfo = this.currentUser()
|
||||
if (!lang) {
|
||||
lang = localStorage.getItem(DEFAULT_LANGUAGE)
|
||||
}
|
||||
this.checkLanguage(lang)
|
||||
},
|
||||
methods: {
|
||||
checkLanguage(lang) {
|
||||
if (!lang) return
|
||||
this.$setLang(lang)
|
||||
switch (lang) {
|
||||
case ZH_CN:
|
||||
this.language = this.languageMap[ZH_CN]
|
||||
break
|
||||
case ZH_TW:
|
||||
this.language = this.languageMap[ZH_TW]
|
||||
break
|
||||
case EN_US:
|
||||
this.language = this.languageMap[EN_US]
|
||||
break
|
||||
default:
|
||||
this.language = this.languageMap[ZH_CN]
|
||||
break
|
||||
}
|
||||
},
|
||||
currentUser: () => {
|
||||
return getCurrentUser()
|
||||
},
|
||||
changeLanguage(language) {
|
||||
const user = {
|
||||
id: this.currentUser().id,
|
||||
language: language
|
||||
}
|
||||
this.checkLanguage(language)
|
||||
this.result = this.$post('/user/update/current', user, response => {
|
||||
localStorage.setItem(TokenKey, JSON.stringify(response.data))
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-icon-check {
|
||||
color: #44b349;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.global {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
@ -1,7 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
export const LIST_CHANGE = 'LIST_CHANGE';
|
||||
|
||||
export let ApiEvent = new Vue();
|
||||
export let TrackEvent = new Vue();
|
||||
export let PerformanceEvent = new Vue();
|
@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" default-active="1" router>
|
||||
<!-- 不激活项目路由-->
|
||||
<el-menu-item v-show="false" index="1">Placeholder</el-menu-item>
|
||||
<el-submenu v-permission="['test_manager','test_user','test_viewer']" index="2" popper-class="submenu">
|
||||
<template v-slot:title>
|
||||
<span class="project-name" :title="currentProject">
|
||||
{{ $t('commons.project') }}: {{ currentProject }}
|
||||
</span>
|
||||
</template>
|
||||
<search-list :current-project.sync="currentProject" />
|
||||
<el-divider />
|
||||
<el-menu-item :index="'/setting/project/create'">
|
||||
<font-awesome-icon :icon="['fa', 'plus']" />
|
||||
<span style="padding-left: 7px;">{{ $t("project.create") }}</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item :index="'/setting/project/all'">
|
||||
<font-awesome-icon :icon="['fa', 'list-ul']" />
|
||||
<span style="padding-left: 7px;">{{ $t('commons.show_all') }}</span>
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SearchList from '@/metersphere/components/common/head/SearchList'
|
||||
import { PROJECT_NAME } from '@/metersphere/common/js/constants'
|
||||
|
||||
export default {
|
||||
name: 'ProjectSwitch',
|
||||
components: { SearchList },
|
||||
props: {
|
||||
projectName: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentProject: this.projectName
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
currentProject() {
|
||||
localStorage.setItem(PROJECT_NAME, this.currentProject)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.project-name {
|
||||
display: inline-block;
|
||||
width: 130px;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
|
||||
.el-divider--horizontal {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
@ -1,101 +0,0 @@
|
||||
<template>
|
||||
<div v-loading="result.loading">
|
||||
<div class="recent-text">
|
||||
<i class="el-icon-time" />
|
||||
<span>{{ options.title }}</span>
|
||||
<i class="el-icon-refresh" @click="recent" />
|
||||
</div>
|
||||
<el-menu-item v-for="i in items" :key="i.id" :index="getIndex(i)" :route="getRouter(i)">
|
||||
<template slot="title">
|
||||
<div class="title">{{ i.name }}</div>
|
||||
<div v-if="options.showTime && i.updateTime" class="time">{{ i.updateTime | timestampFormatDate }}</div>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { hasRoles } from '@/metersphere/common/js/utils'
|
||||
import { ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER } from '@/metersphere/common/js/constants'
|
||||
|
||||
export default {
|
||||
name: 'MsRecentList',
|
||||
props: {
|
||||
options: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
items: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getIndex: function() {
|
||||
return function(item) {
|
||||
return this.options.index(item)
|
||||
}
|
||||
},
|
||||
getRouter: function() {
|
||||
return function(item) {
|
||||
if (this.options.router) {
|
||||
return this.options.router(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.recent()
|
||||
},
|
||||
|
||||
methods: {
|
||||
recent: function() {
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.result = this.$get(this.options.url, (response) => {
|
||||
this.items = response.data
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.recent-text {
|
||||
padding: 0 10px;
|
||||
margin-top: -5px;
|
||||
line-height: 36px;
|
||||
color: #777777;
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
.recent-text span {
|
||||
padding-left: 6px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.recent-text .el-icon-refresh {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.recent-text .el-icon-refresh:hover {
|
||||
color: #BBBBBB;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: inline-block;
|
||||
padding-left: 20px;
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.time {
|
||||
color: #C0C4CC;
|
||||
display: inline-block;
|
||||
padding-left: 20px;
|
||||
float: right;
|
||||
}
|
||||
</style>
|
@ -1,157 +0,0 @@
|
||||
<template>
|
||||
<div v-loading="result.loading">
|
||||
<el-input :placeholder="$t('project.search_by_name')"
|
||||
prefix-icon="el-icon-search"
|
||||
v-model="searchString"
|
||||
clearable
|
||||
class="search-input"
|
||||
size="small"/>
|
||||
<div v-if="items.length === 0" style="text-align: center; margin: 15px 0">
|
||||
<span style="font-size: 15px; color: #8a8b8d;">
|
||||
{{ $t('project.no_data') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else style="height: 150px;overflow: auto">
|
||||
<el-menu-item :key="i.id" v-for="i in items" @click="change(i.id)">
|
||||
<template slot="title">
|
||||
<div class="title">
|
||||
{{ i.name }}
|
||||
</div>
|
||||
<i class="el-icon-check" v-if="i.id === currentProjectId"></i>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getCurrentProjectID, getCurrentUser, hasRoles} from "@/common/js/utils";
|
||||
import {PROJECT_ID, ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "@/common/js/constants";
|
||||
|
||||
export default {
|
||||
name: "SearchList",
|
||||
props: {
|
||||
options: Object,
|
||||
currentProject: String
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
computed: {
|
||||
currentProjectId() {
|
||||
return localStorage.getItem(PROJECT_ID)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
items: [],
|
||||
searchArray: [],
|
||||
searchString: '',
|
||||
userId: getCurrentUser().id,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchString(val) {
|
||||
this.query(val)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init: function () {
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.result = this.$get("/project/listAll", response => {
|
||||
this.items = response.data;
|
||||
this.searchArray = response.data;
|
||||
let userLastProjectId = getCurrentUser().lastProjectId;
|
||||
if (userLastProjectId) {
|
||||
// id 是否存在
|
||||
if (this.searchArray.length > 0 && this.searchArray.map(p => p.id).indexOf(userLastProjectId) !== -1) {
|
||||
localStorage.setItem(PROJECT_ID, userLastProjectId);
|
||||
}
|
||||
}
|
||||
let projectId = getCurrentProjectID();
|
||||
if (projectId) {
|
||||
// 保存的 projectId 在当前项目列表是否存在; 切换工作空间后
|
||||
if (this.searchArray.length > 0 && this.searchArray.map(p => p.id).indexOf(projectId) === -1) {
|
||||
this.change(this.items[0].id);
|
||||
}
|
||||
} else {
|
||||
if (this.items.length > 0) {
|
||||
this.change(this.items[0].id);
|
||||
}
|
||||
}
|
||||
this.changeProjectName(projectId);
|
||||
})
|
||||
}
|
||||
},
|
||||
query(queryString) {
|
||||
this.items = queryString ? this.searchArray.filter(this.createFilter(queryString)) : this.searchArray;
|
||||
},
|
||||
createFilter(queryString) {
|
||||
return item => {
|
||||
return (item.name.toLowerCase().indexOf(queryString.toLowerCase()) !== -1);
|
||||
};
|
||||
},
|
||||
change(projectId) {
|
||||
let currentProjectId = getCurrentProjectID();
|
||||
if (projectId === currentProjectId) {
|
||||
return;
|
||||
}
|
||||
this.$post("/user/update/current", {id: this.userId, lastProjectId: projectId}, () => {
|
||||
localStorage.setItem(PROJECT_ID, projectId);
|
||||
let path = this.$route.matched[0].path ? this.$route.matched[0].path : '/';
|
||||
if (path === '/api') {
|
||||
if (this.$store.state.switch.value === 'new') {
|
||||
path = "/api/home";
|
||||
} else if (this.$store.state.switch.value === 'old') {
|
||||
path = "/api/home_obsolete";
|
||||
} else {
|
||||
path = '/';
|
||||
}
|
||||
}
|
||||
this.$router.push(path).then(() => {
|
||||
window.location.reload()
|
||||
}).catch(err => err);
|
||||
this.changeProjectName(projectId);
|
||||
});
|
||||
},
|
||||
changeProjectName(projectId) {
|
||||
if (projectId) {
|
||||
let project = this.searchArray.filter(p => p.id === projectId);
|
||||
if (project.length > 0) {
|
||||
this.$emit("update:currentProject", project[0].name);
|
||||
}
|
||||
} else {
|
||||
this.$emit("update:currentProject", this.$t('project.select'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.search-input {
|
||||
padding: 0;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.search-input >>> .el-input__inner {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: inline-block;
|
||||
padding-left: 15px;
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.el-icon-check {
|
||||
color: #773888;
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
@ -1,29 +0,0 @@
|
||||
<template>
|
||||
<el-menu-item :index="this.index" @click="changeRoute">
|
||||
<font-awesome-icon :icon="['fa', 'list-ul']"/>
|
||||
<span>{{ $t('commons.show_all') }}</span>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsShowAll",
|
||||
props: {
|
||||
index: String
|
||||
},
|
||||
methods: {
|
||||
changeRoute() {
|
||||
// 解决在列表页面点击 显示全部 无效的问题(点击显示全部后改变路由)
|
||||
if (this.$route.path === this.index) {
|
||||
this.$router.replace({path: this.index, query: {type: 'all'}});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
svg + span {
|
||||
padding-left: 5px;
|
||||
}
|
||||
</style>
|
@ -1,159 +0,0 @@
|
||||
export const TokenKey = 'Authorization'
|
||||
export const LicenseKey = 'License'
|
||||
export const DEFAULT_LANGUAGE = 'default_language'
|
||||
|
||||
export const ROLE_ADMIN = 'admin'
|
||||
export const ROLE_ORG_ADMIN = 'org_admin'
|
||||
export const ROLE_TEST_MANAGER = 'test_manager'
|
||||
export const ROLE_TEST_USER = 'test_user'
|
||||
export const ROLE_TEST_VIEWER = 'test_viewer'
|
||||
|
||||
export const WORKSPACE_ID = 'workspace_id'
|
||||
export const CURRENT_PROJECT = 'current_project'
|
||||
export const PROJECT_ID = 'project_id'
|
||||
export const PROJECT_NAME = 'project_name'
|
||||
|
||||
export const REFRESH_SESSION_USER_URL = 'user/refresh'
|
||||
export const WORKSPACE = 'workspace'
|
||||
export const ORGANIZATION = 'organization'
|
||||
export const MENU = 'menu'
|
||||
export const DEFAULT = 'default'
|
||||
|
||||
export const ZH_CN = 'zh_CN'
|
||||
export const ZH_TW = 'zh_TW'
|
||||
export const EN_US = 'en_US'
|
||||
|
||||
export const TAPD = 'Tapd'
|
||||
export const JIRA = 'Jira'
|
||||
export const ZEN_TAO = 'Zentao'
|
||||
|
||||
export const SCHEDULE_TYPE = {
|
||||
API_TEST: 'API_TEST',
|
||||
PERFORMANCE_TEST: 'PERFORMANCE_TEST'
|
||||
}
|
||||
|
||||
export const REQUEST_HEADERS = [
|
||||
{ value: 'Accept' },
|
||||
{ value: 'Accept-Charset' },
|
||||
{ value: 'Accept-Language' },
|
||||
{ value: 'Accept-Datetime' },
|
||||
{ value: 'Authorization' },
|
||||
{ value: 'Cache-Control' },
|
||||
{ value: 'Connection' },
|
||||
{ value: 'Cookie' },
|
||||
{ value: 'Content-Length' },
|
||||
{ value: 'Content-MD5' },
|
||||
{ value: 'Content-Type' },
|
||||
{ value: 'Date' },
|
||||
{ value: 'Expect' },
|
||||
{ value: 'From' },
|
||||
{ value: 'Host' },
|
||||
{ value: 'If-Match' },
|
||||
{ value: 'If-Modified-Since' },
|
||||
{ value: 'If-None-Match' },
|
||||
{ value: 'If-Range' },
|
||||
{ value: 'If-Unmodified-Since' },
|
||||
{ value: 'Max-Forwards' },
|
||||
{ value: 'Origin' },
|
||||
{ value: 'Pragma' },
|
||||
{ value: 'Proxy-Authorization' },
|
||||
{ value: 'Range' },
|
||||
{ value: 'Referer' },
|
||||
{ value: 'TE' },
|
||||
{ value: 'User-Agent' },
|
||||
{ value: 'Upgrade' },
|
||||
{ value: 'Via' },
|
||||
{ value: 'Warning' }
|
||||
]
|
||||
|
||||
export const MOCKJS_FUNC = [
|
||||
{ name: '@boolean' },
|
||||
{ name: '@natural' },
|
||||
{ name: '@integer' },
|
||||
{ name: '@float' },
|
||||
{ name: '@character' },
|
||||
{ name: '@string' },
|
||||
{ name: '@range' },
|
||||
{ name: '@date' },
|
||||
{ name: '@time' },
|
||||
{ name: '@datetime' },
|
||||
{ name: '@now' },
|
||||
{ name: '@img' },
|
||||
{ name: '@dataImage' },
|
||||
{ name: '@color' },
|
||||
{ name: '@hex' },
|
||||
{ name: '@rgb' },
|
||||
{ name: '@rgba' },
|
||||
{ name: '@hsl' },
|
||||
{ name: '@paragraph' },
|
||||
{ name: '@sentence' },
|
||||
{ name: '@word' },
|
||||
{ name: '@title' },
|
||||
{ name: '@cparagraph' },
|
||||
{ name: '@csentence' },
|
||||
{ name: '@cword' },
|
||||
{ name: '@ctitle' },
|
||||
{ name: '@first' },
|
||||
{ name: '@last' },
|
||||
{ name: '@name' },
|
||||
{ name: '@cfirst' },
|
||||
{ name: '@clast' },
|
||||
{ name: '@cname' },
|
||||
{ name: '@url' },
|
||||
{ name: '@domain' },
|
||||
{ name: '@protocol' },
|
||||
{ name: '@tld' },
|
||||
{ name: '@email' },
|
||||
{ name: '@ip' },
|
||||
{ name: '@region' },
|
||||
{ name: '@province' },
|
||||
{ name: '@city' },
|
||||
{ name: '@county' },
|
||||
{ name: '@zip' },
|
||||
{ name: '@capitalize' },
|
||||
{ name: '@upper' },
|
||||
{ name: '@lower' },
|
||||
{ name: '@pick' },
|
||||
{ name: '@shuffle' },
|
||||
{ name: '@guid' },
|
||||
{ name: '@id' },
|
||||
{ name: '@increment' }
|
||||
]
|
||||
|
||||
export const JMETER_FUNC = [
|
||||
{ type: 'Information', name: '${__threadNum}', description: 'get thread number' },
|
||||
{ type: 'Information', name: '${__samplerName}', description: 'get the sampler name (label)' },
|
||||
{ type: 'Information', name: '${__machineIP}', description: 'get the local machine IP address' },
|
||||
{ type: 'Information', name: '${__machineName}', description: 'get the local machine name' },
|
||||
{ type: 'Information', name: '${__time}', description: 'return current time in various formats' },
|
||||
{ type: 'Information', name: '${__log}', description: 'log (or display) a message (and return the value)' },
|
||||
{ type: 'Information', name: '${__logn}', description: 'log (or display) a message (empty return value)' },
|
||||
{ type: 'Input', name: '${__StringFromFile}', description: 'read a line from a file' },
|
||||
{ type: 'Input', name: '${__FileToString}', description: 'read an entire file' },
|
||||
{ type: 'Input', name: '${__CSVRead}', description: 'read from CSV definitioned file' },
|
||||
{ type: 'Input', name: '${__XPath}', description: 'Use an XPath expression to read from a file' },
|
||||
{ type: 'Calculation', name: '${__counter}', description: 'generate an incrementing number' },
|
||||
{ type: 'Calculation', name: '${__intSum}', description: 'add int numbers' },
|
||||
{ type: 'Calculation', name: '${__longSum}', description: 'add long numbers' },
|
||||
{ type: 'Calculation', name: '${__Random}', description: 'generate a random number' },
|
||||
{ type: 'Calculation', name: '${__RandomString}', description: 'generate a random string' },
|
||||
{ type: 'Calculation', name: '${__UUID}', description: 'generate a random type 4 UUID' },
|
||||
{ type: 'Scripting', name: '${__BeanShell}', description: 'run a BeanShell script' },
|
||||
{ type: 'Scripting', name: '${__javaScript}', description: 'process JavaScript (Mozilla Rhino)' },
|
||||
{ type: 'Scripting', name: '${__jexl}', description: 'evaluate a Commons Jexl expression' },
|
||||
{ type: 'Scripting', name: '${__jexl2}', description: 'evaluate a Commons Jexl expression' },
|
||||
{ type: 'Properties', name: '${__property}', description: 'read a property' },
|
||||
{ type: 'Properties', name: '${__P}', description: 'read a property (shorthand method)' },
|
||||
{ type: 'Properties', name: '${__setProperty}', description: 'set a JMeter property' },
|
||||
{ type: 'Variables', name: '${__split}', description: 'Split a string into variables' },
|
||||
{ type: 'Variables', name: '${__V}', description: 'evaluate a variable name' },
|
||||
{ type: 'Variables', name: '${__eval}', description: 'evaluate a variable expression' },
|
||||
{ type: 'Variables', name: '${__evalVar}', description: 'evaluate an expression stored in a variable' },
|
||||
{ type: 'String', name: '${__regexFunction}', description: 'parse previous response using a regular expression' },
|
||||
{ type: 'String', name: '${__escapeOroRegexpChars}', description: 'quote meta chars used by ORO regular expression' },
|
||||
{ type: 'String', name: '${__char}', description: 'generate Unicode char values from a list of numbers' },
|
||||
{ type: 'String', name: '${__unescape}', description: 'Process strings containing Java escapes (e.g. & )' },
|
||||
{ type: 'String', name: '${__unescapeHtml}', description: 'Decode HTML-encoded strings' },
|
||||
{ type: 'String', name: '${__escapeHtml}', description: 'Encode strings using HTML encoding' },
|
||||
{ type: 'String', name: '${__TestPlanName}', description: 'Return name of current test plan' }
|
||||
]
|
@ -1,59 +0,0 @@
|
||||
export const left2RightDrag = {
|
||||
inserted(el, binding) {
|
||||
el.onmousedown = function(e) {
|
||||
const init = e.clientX
|
||||
const parent = el.parentNode
|
||||
const initWidth = parent.offsetWidth
|
||||
document.onmousemove = function(e) {
|
||||
const end = e.clientX
|
||||
const newWidth = end - init + initWidth
|
||||
if (newWidth < document.body.clientWidth - 10 && newWidth > 10) {
|
||||
parent.style.width = newWidth + 'px'
|
||||
}
|
||||
}
|
||||
document.onmouseup = function() {
|
||||
document.onmousemove = document.onmouseup = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const right2LeftDrag = {
|
||||
inserted(el, binding) {
|
||||
el.onmousedown = function(e) {
|
||||
const init = e.clientX
|
||||
const parent = el.parentNode
|
||||
const initWidth = parent.offsetWidth
|
||||
document.onmousemove = function(e) {
|
||||
const end = e.clientX
|
||||
const newWidth = initWidth - (end - init)
|
||||
if (newWidth < document.body.clientWidth - 10 && newWidth > 10) {
|
||||
parent.style.width = newWidth + 'px'
|
||||
}
|
||||
}
|
||||
document.onmouseup = function() {
|
||||
document.onmousemove = document.onmouseup = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const bottom2TopDrag = {
|
||||
inserted(el, binding) {
|
||||
el.onmousedown = function(e) {
|
||||
const init = e.clientY
|
||||
const parent = el.parentNode
|
||||
const initHeight = parent.offsetHeight
|
||||
document.onmousemove = function(e) {
|
||||
const end = e.clientY
|
||||
const newHeight = initHeight - (end - init)
|
||||
if (newHeight < document.body.clientHeight - 10 && newHeight > 10) {
|
||||
parent.style.height = newHeight + 'px'
|
||||
}
|
||||
}
|
||||
document.onmouseup = function() {
|
||||
document.onmousemove = document.onmouseup = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
import { Message } from 'element-ui'
|
||||
|
||||
export default {
|
||||
install(Vue) {
|
||||
if (!Message) {
|
||||
window.console.error('You have to install Message of ElementUI')
|
||||
return
|
||||
}
|
||||
|
||||
Vue.prototype.$success = function(message) {
|
||||
Message.success({
|
||||
message: message,
|
||||
type: 'success',
|
||||
showClose: true,
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
|
||||
Vue.prototype.$info = function(message, duration) {
|
||||
Message.info({
|
||||
message: message,
|
||||
type: 'info',
|
||||
showClose: true,
|
||||
duration: duration || 3000
|
||||
})
|
||||
}
|
||||
|
||||
Vue.prototype.$warning = function(message) {
|
||||
Message.warning({
|
||||
message: message,
|
||||
type: 'warning',
|
||||
showClose: true,
|
||||
duration: 5000
|
||||
})
|
||||
}
|
||||
|
||||
Vue.prototype.$error = function(message, duration) {
|
||||
Message.error({
|
||||
message: message,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
duration: duration || 10000
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export const PHONE_REGEX = '^1(3|4|5|6|7|8|9)\\d{9}$'
|
@ -1,292 +0,0 @@
|
||||
import {
|
||||
LicenseKey,
|
||||
PROJECT_ID,
|
||||
REFRESH_SESSION_USER_URL,
|
||||
ROLE_ADMIN,
|
||||
ROLE_ORG_ADMIN,
|
||||
ROLE_TEST_MANAGER,
|
||||
ROLE_TEST_USER,
|
||||
ROLE_TEST_VIEWER
|
||||
} from './constants'
|
||||
import axios from 'axios'
|
||||
|
||||
export function hasRole(role) {
|
||||
const user = getCurrentUser()
|
||||
const roles = user.roles.map(r => r.id)
|
||||
return roles.indexOf(role) > -1
|
||||
}
|
||||
|
||||
// 是否含有某个角色
|
||||
export function hasRoles(...roles) {
|
||||
const user = getCurrentUser()
|
||||
const rs = user.roles.map(r => r.id)
|
||||
for (const item of roles) {
|
||||
if (rs.indexOf(item) > -1) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function hasRolePermission(role) {
|
||||
const user = getCurrentUser()
|
||||
for (const ur of user.userRoles) {
|
||||
if (role === ur.roleId) {
|
||||
if (ur.roleId === ROLE_ADMIN) {
|
||||
return true
|
||||
} else if (ur.roleId === ROLE_ORG_ADMIN && user.lastOrganizationId === ur.sourceId) {
|
||||
return true
|
||||
} else if (user.lastWorkspaceId === ur.sourceId) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function hasLicense() {
|
||||
const v = localStorage.getItem(LicenseKey)
|
||||
return v === 'valid'
|
||||
}
|
||||
|
||||
// 是否含有对应组织或工作空间的角色
|
||||
export function hasRolePermissions(...roles) {
|
||||
for (const role of roles) {
|
||||
if (hasRolePermission(role)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function checkoutCurrentOrganization() {
|
||||
// 查看当前用户是否是 lastOrganizationId 的组织管理员
|
||||
return hasRolePermissions(ROLE_ORG_ADMIN)
|
||||
}
|
||||
|
||||
export function checkoutCurrentWorkspace() {
|
||||
// 查看当前用户是否是 lastWorkspaceId 的工作空间用户
|
||||
return hasRolePermissions(ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER)
|
||||
}
|
||||
|
||||
export function checkoutTestManagerOrTestUser() {
|
||||
return hasRolePermissions(ROLE_TEST_MANAGER, ROLE_TEST_USER)
|
||||
}
|
||||
|
||||
export function getCurrentOrganizationId() {
|
||||
const user = getCurrentUser()
|
||||
return user.lastOrganizationId
|
||||
}
|
||||
|
||||
export function getCurrentWorkspaceId() {
|
||||
const user = getCurrentUser()
|
||||
return user.lastWorkspaceId
|
||||
}
|
||||
|
||||
export function getCurrentUser() {
|
||||
// return JSON.parse(localStorage.getItem(TokenKey));
|
||||
return getUserInfo()
|
||||
}
|
||||
|
||||
export function getCurrentProjectID() {
|
||||
return localStorage.getItem(PROJECT_ID)
|
||||
}
|
||||
|
||||
// export function saveLocalStorage(response) {
|
||||
// // 登录信息保存 cookie
|
||||
// //localStorage.setItem(TokenKey, JSON.stringify(response.data));
|
||||
// let rolesArray = response.data.roles;
|
||||
// let roles = rolesArray.map(r => r.id);
|
||||
// // 保存角色
|
||||
// localStorage.setItem("roles", roles);
|
||||
// }
|
||||
|
||||
export function saveLocalStorage(response) {
|
||||
// 登录信息保存 cookie
|
||||
// localStorage.setItem(TokenKey, JSON.stringify(response.data));
|
||||
const rolesArray = response.data.roles
|
||||
const roles = rolesArray.map(r => r.id)
|
||||
// 保存角色
|
||||
localStorage.setItem('roles', roles)
|
||||
}
|
||||
|
||||
export function saveLicense(data) {
|
||||
// 保存License
|
||||
localStorage.setItem(LicenseKey, data)
|
||||
}
|
||||
|
||||
export function refreshSessionAndCookies(sign, sourceId) {
|
||||
axios.post(REFRESH_SESSION_USER_URL + '/' + sign + '/' + sourceId).then(r => {
|
||||
saveLocalStorage(r.data)
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
|
||||
export function jsonToMap(jsonStr) {
|
||||
const obj = JSON.parse(jsonStr)
|
||||
const strMap = new Map()
|
||||
for (const k of Object.keys(obj)) {
|
||||
strMap.set(k, obj[k])
|
||||
}
|
||||
return strMap
|
||||
}
|
||||
|
||||
export function mapToJson(strMap) {
|
||||
const obj = Object.create(null)
|
||||
for (const [k, v] of strMap) {
|
||||
obj[k] = v
|
||||
}
|
||||
return JSON.stringify(obj)
|
||||
}
|
||||
|
||||
// 驼峰转换下划线
|
||||
export function humpToLine(name) {
|
||||
return name.replace(/([A-Z])/g, '_$1').toLowerCase()
|
||||
}
|
||||
|
||||
export function downloadFile(name, content) {
|
||||
const blob = new Blob([content])
|
||||
if ('download' in document.createElement('a')) {
|
||||
// 非IE下载
|
||||
// chrome/firefox
|
||||
const aTag = document.createElement('a')
|
||||
aTag.download = name
|
||||
aTag.href = URL.createObjectURL(blob)
|
||||
aTag.click()
|
||||
URL.revokeObjectURL(aTag.href)
|
||||
} else {
|
||||
// IE10+下载
|
||||
navigator.msSaveBlob(blob, name)
|
||||
}
|
||||
}
|
||||
|
||||
export function listenGoBack(callback) {
|
||||
// 监听浏览器返回操作,关闭该对话框
|
||||
if (window.history && window.history.pushState) {
|
||||
history.pushState(null, null, document.URL)
|
||||
window.addEventListener('popstate', callback)
|
||||
}
|
||||
}
|
||||
|
||||
export function removeGoBackListener(callback) {
|
||||
window.removeEventListener('popstate', callback)
|
||||
}
|
||||
|
||||
export const uuid = function() {
|
||||
let d = new Date().getTime()
|
||||
let d2 = (performance && performance.now && (performance.now() * 1000)) || 0
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random() * 16
|
||||
if (d > 0) {
|
||||
r = (d + r) % 16 | 0
|
||||
d = Math.floor(d / 16)
|
||||
} else {
|
||||
r = (d2 + r) % 16 | 0
|
||||
d2 = Math.floor(d2 / 16)
|
||||
}
|
||||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
|
||||
})
|
||||
}
|
||||
|
||||
export function getUUID() {
|
||||
function S4() {
|
||||
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
|
||||
}
|
||||
|
||||
return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
|
||||
}
|
||||
|
||||
export function windowPrint(id, zoom) {
|
||||
// 根据div标签ID拿到div中的局部内容
|
||||
const bdhtml = window.document.body.innerHTML
|
||||
const el = document.getElementById(id)
|
||||
var jubuData = el.innerHTML
|
||||
document.getElementsByTagName('body')[0].style.zoom = zoom
|
||||
// 把获取的 局部div内容赋给body标签, 相当于重置了 body里的内容
|
||||
window.document.body.innerHTML = jubuData
|
||||
// 调用打印功能
|
||||
window.print()
|
||||
window.document.body.innerHTML = bdhtml// 重新给页面内容赋值;
|
||||
return false
|
||||
}
|
||||
|
||||
export function getBodyUploadFiles(obj, runData) {
|
||||
const bodyUploadFiles = []
|
||||
obj.bodyUploadIds = []
|
||||
if (runData) {
|
||||
if (runData instanceof Array) {
|
||||
runData.forEach(request => {
|
||||
_getBodyUploadFiles(request, bodyUploadFiles, obj)
|
||||
})
|
||||
} else {
|
||||
_getBodyUploadFiles(runData, bodyUploadFiles, obj)
|
||||
}
|
||||
}
|
||||
return bodyUploadFiles
|
||||
}
|
||||
|
||||
export function _getBodyUploadFiles(request, bodyUploadFiles, obj) {
|
||||
let body = null
|
||||
if (request.hashTree && request.hashTree.length > 0 && request.hashTree[0].body) {
|
||||
body = request.hashTree[0].body
|
||||
} else if (request.body) {
|
||||
body = request.body
|
||||
}
|
||||
if (body) {
|
||||
if (body.kvs) {
|
||||
body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
const fileId = getUUID().substring(0, 12)
|
||||
item.name = item.file.name
|
||||
item.id = fileId
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id)
|
||||
bodyUploadFiles.push(item.file)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
if (body.binary) {
|
||||
body.binary.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
const fileId = getUUID().substring(0, 12)
|
||||
item.name = item.file.name
|
||||
item.id = fileId
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id)
|
||||
bodyUploadFiles.push(item.file)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
export function handleCtrlSEvent(event, func) {
|
||||
if (event.keyCode === 83 && event.ctrlKey) {
|
||||
// console.log('拦截到 ctrl + s');//ctrl+s
|
||||
func()
|
||||
event.preventDefault()
|
||||
event.returnValue = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- dataEase新增
|
||||
export function setUserInfo(userInfo) {
|
||||
localStorage.setItem('userInfo', JSON.stringify(userInfo))
|
||||
}
|
||||
export function getUserInfo() {
|
||||
return JSON.parse(localStorage.getItem('userInfo'))
|
||||
}
|
||||
export function getRoles() {
|
||||
const uinfo = getUserInfo()
|
||||
return uinfo && uinfo['roles']
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
<template>
|
||||
<div id="app" v-loading="loading">
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane :label="$t('organization.message.template')" name="apiTemplate">
|
||||
<el-button type="primary" size="mini" style="margin: 10px 10px 0px" @click="openOneClickOperation">导入</el-button>
|
||||
<div style="min-height: 200px">
|
||||
<json-schema-editor class="schema" :value="schema" lang="zh_CN" custom/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('schema.preview')" name="preview">
|
||||
<div style="min-height: 200px">
|
||||
<pre>{{this.preview}}</pre>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<ms-import-json ref="importJson" @jsonData="jsonData"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {schemaToJson} from './common';
|
||||
import MsImportJson from './import/ImportJson';
|
||||
|
||||
const GenerateSchema = require('generate-schema/src/schemas/json.js');
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {MsImportJson},
|
||||
props: {
|
||||
body: {},
|
||||
},
|
||||
created() {
|
||||
if (!this.body.jsonSchema && this.body.raw && this.checkIsJson(this.body.raw)) {
|
||||
let obj = {"root": GenerateSchema(JSON.parse(this.body.raw))}
|
||||
this.schema = obj;
|
||||
}
|
||||
else if (this.body.jsonSchema) {
|
||||
this.schema = {"root": this.body.jsonSchema};
|
||||
}
|
||||
this.body.jsonSchema = this.schema.root;
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
schema:
|
||||
{
|
||||
"root": {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
}
|
||||
},
|
||||
loading: false,
|
||||
preview: null,
|
||||
activeName: "apiTemplate",
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
if (this.activeName === 'preview') {
|
||||
// 前端转换
|
||||
//this.preview = schemaToJson(this.schema.root);
|
||||
this.loading = true;
|
||||
// 后台转换
|
||||
this.$post('/api/definition/preview', this.schema.root, response => {
|
||||
this.preview = response.data;
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
openOneClickOperation() {
|
||||
this.$refs.importJson.openOneClickOperation();
|
||||
},
|
||||
checkIsJson(json) {
|
||||
try {
|
||||
JSON.parse(json);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
jsonData(data) {
|
||||
let obj = {"root": data}
|
||||
this.schema = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
||||
</style>
|
@ -1,32 +0,0 @@
|
||||
const Mock = require('mockjs');
|
||||
const jsf = require('json-schema-faker');
|
||||
|
||||
jsf.extend('mock', function () {
|
||||
return {
|
||||
mock: function (xx) {
|
||||
if (xx && xx.startsWith("@")) {
|
||||
return Mock.mock(xx);
|
||||
}
|
||||
return xx;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const defaultOptions = {
|
||||
failOnInvalidTypes: false,
|
||||
failOnInvalidFormat: false
|
||||
};
|
||||
|
||||
export const schemaToJson = (schema, options = {}) => {
|
||||
Object.assign(options, defaultOptions);
|
||||
|
||||
jsf.option(options);
|
||||
let result;
|
||||
try {
|
||||
result = jsf.generate(schema);
|
||||
} catch (err) {
|
||||
result = err.message;
|
||||
}
|
||||
jsf.option(defaultOptions);
|
||||
return result;
|
||||
};
|
@ -1,117 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="导入"
|
||||
:visible.sync="importVisible"
|
||||
width="50%"
|
||||
append-to-body
|
||||
show-close
|
||||
:close-on-click-modal="false"
|
||||
@closed="handleClose">
|
||||
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane label="JSON" name="JSON">
|
||||
<div style="height: 400px">
|
||||
<ms-code-edit :mode="mode"
|
||||
:data.sync="json" theme="eclipse" :modes="[]"
|
||||
ref="codeEdit"/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="JSON-SCHEMA" name="JSON-SCHEMA">
|
||||
<div style="height: 400px">
|
||||
<ms-code-edit :mode="mode"
|
||||
:data.sync="jsonSchema" theme="eclipse" :modes="[]"
|
||||
ref="codeEdit"/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<ms-dialog-footer
|
||||
@cancel="importVisible = false"
|
||||
@confirm="saveConfirm"/>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsDialogFooter from '../../../common/components/MsDialogFooter'
|
||||
import MsCodeEdit from "../../../common/components/MsCodeEdit";
|
||||
import json5 from 'json5';
|
||||
|
||||
const GenerateSchema = require('generate-schema/src/schemas/json.js');
|
||||
|
||||
export default {
|
||||
name: "MsImportJson",
|
||||
components: {MsDialogFooter, MsCodeEdit},
|
||||
data() {
|
||||
return {
|
||||
importVisible: false,
|
||||
activeName: "JSON",
|
||||
mode: "json",
|
||||
json: "",
|
||||
jsonSchema: "",
|
||||
};
|
||||
},
|
||||
watch: {},
|
||||
props: {},
|
||||
methods: {
|
||||
openOneClickOperation() {
|
||||
this.importVisible = true;
|
||||
},
|
||||
checkIsJson(json) {
|
||||
try {
|
||||
json5.parse(json);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
checkIsJsonSchema(json) {
|
||||
try {
|
||||
json = json5.parse(json);
|
||||
if (json.properties && typeof json.properties === 'object' && !json.type) {
|
||||
json.type = 'object';
|
||||
}
|
||||
if (json.items && typeof json.items === 'object' && !json.type) {
|
||||
json.type = 'array';
|
||||
}
|
||||
if (!json.type) {
|
||||
return false;
|
||||
}
|
||||
json.type = json.type.toLowerCase();
|
||||
let types = ['object', 'string', 'number', 'array', 'boolean', 'integer'];
|
||||
if (types.indexOf(json.type) === -1) {
|
||||
return false;
|
||||
}
|
||||
return JSON.stringify(json);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
saveConfirm() {
|
||||
if (this.activeName === 'JSON') {
|
||||
if (!this.checkIsJson(this.json)) {
|
||||
this.$error("导入的数据非JSON格式");
|
||||
return;
|
||||
}
|
||||
let jsonData = GenerateSchema(json5.parse(this.json));
|
||||
this.$emit('jsonData', jsonData);
|
||||
} else {
|
||||
if (!this.checkIsJsonSchema(this.jsonSchema)) {
|
||||
this.$error("导入的数据非JSON-SCHEMA 格式");
|
||||
return;
|
||||
}
|
||||
let obj = json5.parse(this.jsonSchema);
|
||||
this.$emit('jsonData', obj);
|
||||
}
|
||||
this.importVisible = false;
|
||||
},
|
||||
handleClose() {
|
||||
this.importVisible = false;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,7 +0,0 @@
|
||||
import JsonSchemaEditor from './main.vue'
|
||||
|
||||
JsonSchemaEditor.install = function (Vue) {
|
||||
Vue.component(JsonSchemaEditor.name, JsonSchemaEditor)
|
||||
}
|
||||
|
||||
export default JsonSchemaEditor
|
@ -1,400 +0,0 @@
|
||||
<template>
|
||||
<div class="json-schema-editor">
|
||||
<el-row class="row" :gutter="20">
|
||||
<el-col :span="8" class="ms-col-name">
|
||||
<div :style="{marginLeft:`${10*deep}px`}" class="ms-col-name-c"/>
|
||||
<span v-if="pickValue.type==='object'" :class="hidden? 'el-icon-caret-left ms-transform':
|
||||
'el-icon-caret-bottom'" @click="hidden = !hidden"/>
|
||||
<span v-else style="width:10px;display:inline-block"></span>
|
||||
<input class="el-input el-input__inner" style="height: 32px" :disabled="disabled || root" :value="pickKey" @blur="onInputName" size="small"/>
|
||||
|
||||
<el-tooltip v-if="root" :content="$t('schema.checked_all')" placement="top">
|
||||
<input type="checkbox" :disabled="!isObject && !isArray" class="ms-col-name-required" @change="onRootCheck"/>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-else :content="$t('schema.required')" placement="top">
|
||||
<input type="checkbox" :disabled="isItem" :checked="checked" class="ms-col-name-required" @change="onCheck"/>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-select v-model="pickValue.type" :disabled="disabledType" class="ms-col-type" @change="onChangeType" size="small">
|
||||
<el-option :key="t" :value="t" :label="t" v-for="t in TYPE_NAME"/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<ms-mock :disabled="pickValue.type==='object'" :schema="pickValue"/>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input v-model="pickValue.description" class="ms-col-title" :placeholder="$t('schema.description')" size="small"/>
|
||||
</el-col>
|
||||
<el-col :span="4" class="col-item-setting">
|
||||
<el-tooltip class="item" effect="dark" :content="$t('schema.adv_setting')" placement="top">
|
||||
<i class="el-icon-setting" @click="onSetting"/>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="isObject" :content="$t('schema.add_child_node')" placement="top">
|
||||
<i class="el-icon-plus" @click="addChild" style="margin-left: 10px"/>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="!root && !isItem" :content="$t('schema.remove_node')" placement="top">
|
||||
<i class="el-icon-close" @click="removeNode" style="margin-left: 10px"/>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<template v-if="!hidden&&pickValue.properties && !isArray">
|
||||
<json-schema-editor v-for="(item,key,index) in pickValue.properties" :value="{[key]:item}" :parent="pickValue" :key="index" :deep="deep+1" :root="false" class="children" :lang="lang" :custom="custom"/>
|
||||
</template>
|
||||
<template v-if="isArray">
|
||||
<json-schema-editor :value="{items:pickValue.items}" :deep="deep+1" disabled isItem :root="false" class="children" :lang="lang" :custom="custom"/>
|
||||
</template>
|
||||
<!-- 高级设置-->
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :title="$t('schema.adv_setting')" :visible.sync="modalVisible" :destroy-on-close="true"
|
||||
@close="handleClose">
|
||||
<p class="tip">基础设置 </p>
|
||||
<el-form :inline="true" v-model="advancedValue" class="ms-advanced-search-form">
|
||||
<el-row :gutter="6">
|
||||
<el-col :span="8" v-for="(item,key) in advancedValue" :key="key" style="float: right">
|
||||
<el-form-item>
|
||||
<div>{{ $t('schema.'+key)}}</div>
|
||||
<el-input-number v-model="advancedValue[key]" v-if="advancedAttr[key].type === 'integer'" style="width:100%" :placeholder="key" size="small"/>
|
||||
<el-input-number v-model="advancedValue[key]" v-else-if="advancedAttr[key].type === 'number'" style="width:100%" :placeholder="key" size="small"/>
|
||||
<span v-else-if="advancedAttr[key].type === 'boolean'" style="display:inline-block;width:100%">
|
||||
<el-switch v-model="advancedValue[key]"/>
|
||||
</span>
|
||||
<el-select v-else-if="advancedAttr[key].type === 'array'" v-model="advancedValue[key]" style="width:100%" size="small">
|
||||
<el-option value="" :label="$t('schema.nothing')"></el-option>
|
||||
<el-option :key="t" :value="t" :label="t" v-for="t in advancedAttr[key].enums"/>
|
||||
</el-select>
|
||||
<el-input v-model="advancedValue[key]" v-else style="width:100%;" :placeholder="key" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<!--<h3 v-text="$t('schema.add_custom')" v-show="custom">添加自定义属性</h3>
|
||||
<el-form class="ms-advanced-search-form" v-show="custom">
|
||||
<el-row :gutter="6">
|
||||
<el-col :span="8" v-for="item in customProps" :key="item.key">
|
||||
<el-form-item :label="item.key">
|
||||
<el-input v-model="item.value" style="width:calc(100% - 30px)" size="small"/>
|
||||
<el-button icon="close" type="link" @click="customProps.splice(customProps.indexOf(item),1)" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" v-show="addProp.key != undefined">
|
||||
<el-form-item>
|
||||
<el-input slot="label" v-model="addProp.key" size="small"/>
|
||||
<el-input v-model="addProp.value" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item>
|
||||
<el-button icon="check" type="link" @click="confirmAddCustomNode" v-if="customing"/>
|
||||
<el-tooltip content="$t('schema.add_custom')" v-else>
|
||||
<el-button icon="el-icon-plus" type="link" @click="addCustomNode"/>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>-->
|
||||
<p class="tip">{{$t('schema.preview')}} </p>
|
||||
<pre style="width:100%">{{completeNodeValue}}</pre>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<ms-dialog-footer
|
||||
@cancel="modalVisible = false"
|
||||
@confirm="handleOk"/>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {isNull} from './util'
|
||||
import {TYPE_NAME, TYPE} from './type/type'
|
||||
import MsMock from './mock/MockComplete'
|
||||
import MsDialogFooter from '../../../components/MsDialogFooter'
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: 'JsonSchemaEditor',
|
||||
components: {MsMock, MsDialogFooter},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
disabled: { //name不可编辑,根节点name不可编辑,数组元素name不可编辑
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabledType: { //禁用类型选择
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isItem: { //是否数组元素
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
deep: { // 节点深度,根节点deep=0
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
root: { //是否root节点
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
parent: { //父节点
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
custom: { //enable custom properties
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
lang: { // i18n language
|
||||
type: String,
|
||||
default: 'zh_CN'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pickValue() {
|
||||
return Object.values(this.value)[0]
|
||||
},
|
||||
pickKey() {
|
||||
return Object.keys(this.value)[0]
|
||||
},
|
||||
isObject() {
|
||||
return this.pickValue.type === 'object'
|
||||
},
|
||||
isArray() {
|
||||
return this.pickValue.type === 'array'
|
||||
},
|
||||
checked() {
|
||||
return this.parent && this.parent.required && this.parent.required.indexOf(this.pickKey) >= 0
|
||||
},
|
||||
advanced() {
|
||||
return TYPE[this.pickValue.type]
|
||||
},
|
||||
advancedAttr() {
|
||||
return TYPE[this.pickValue.type].attr
|
||||
},
|
||||
advancedNotEmptyValue() {
|
||||
const jsonNode = Object.assign({}, this.advancedValue);
|
||||
for (let key in jsonNode) {
|
||||
isNull(jsonNode[key]) && delete jsonNode[key]
|
||||
}
|
||||
return jsonNode
|
||||
},
|
||||
completeNodeValue() {
|
||||
const t = {}
|
||||
for (const item of this.customProps) {
|
||||
t[item.key] = item.value
|
||||
}
|
||||
return Object.assign({}, this.pickValue, this.advancedNotEmptyValue, t)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
TYPE_NAME,
|
||||
hidden: false,
|
||||
countAdd: 1,
|
||||
modalVisible: false,
|
||||
advancedValue: {},
|
||||
addProp: {},// 自定义属性
|
||||
customProps: [],
|
||||
customing: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onInputName(e) {
|
||||
const val = e.target.value
|
||||
const p = {};
|
||||
for (let key in this.parent.properties) {
|
||||
if (key != this.pickKey) {
|
||||
p[key] = this.parent.properties[key]
|
||||
} else {
|
||||
p[val] = this.parent.properties[key]
|
||||
delete this.parent.properties[key]
|
||||
}
|
||||
}
|
||||
this.$set(this.parent, 'properties', p)
|
||||
},
|
||||
onChangeType() {
|
||||
this.$delete(this.pickValue, 'properties')
|
||||
this.$delete(this.pickValue, 'items')
|
||||
this.$delete(this.pickValue, 'required')
|
||||
this.$delete(this.pickValue, 'mock')
|
||||
if (this.isArray) {
|
||||
this.$set(this.pickValue, 'items', {type: 'string', mock: {mock: ""}})
|
||||
}
|
||||
},
|
||||
onCheck(e) {
|
||||
this._checked(e.target.checked, this.parent)
|
||||
},
|
||||
onRootCheck(e) {
|
||||
const checked = e.target.checked
|
||||
this._deepCheck(checked, this.pickValue)
|
||||
},
|
||||
_deepCheck(checked, node) {
|
||||
if (node.type === 'object' && node.properties) {
|
||||
checked ? this.$set(node, 'required', Object.keys(node.properties)) : this.$delete(node, 'required')
|
||||
Object.keys(node.properties).forEach(key => this._deepCheck(checked, node.properties[key]))
|
||||
} else if (node.type === 'array' && node.items.type === 'object') {
|
||||
checked ? this.$set(node.items, 'required', Object.keys(node.items.properties)) : this.$delete(node.items, 'required')
|
||||
Object.keys(node.items.properties).forEach(key => this._deepCheck(checked, node.items.properties[key]))
|
||||
}
|
||||
},
|
||||
_checked(checked, parent) {
|
||||
let required = parent.required
|
||||
if (checked) {
|
||||
required || this.$set(this.parent, 'required', [])
|
||||
|
||||
required = this.parent.required
|
||||
required.indexOf(this.pickKey) === -1 && required.push(this.pickKey)
|
||||
} else {
|
||||
const pos = required.indexOf(this.pickKey)
|
||||
pos >= 0 && required.splice(pos, 1)
|
||||
}
|
||||
required.length === 0 && this.$delete(parent, 'required')
|
||||
},
|
||||
addChild() {
|
||||
const name = this._joinName()
|
||||
const type = 'string'
|
||||
const node = this.pickValue
|
||||
node.properties || this.$set(node, 'properties', {})
|
||||
const props = node.properties
|
||||
this.$set(props, name, {type: type, mock: {mock: ""}})
|
||||
},
|
||||
addCustomNode() {
|
||||
this.$set(this.addProp, 'key', this._joinName())
|
||||
this.$set(this.addProp, 'value', '')
|
||||
this.customing = true
|
||||
},
|
||||
confirmAddCustomNode() {
|
||||
this.customProps.push(this.addProp)
|
||||
this.addProp = {}
|
||||
this.customing = false
|
||||
},
|
||||
removeNode() {
|
||||
const {properties, required} = this.parent
|
||||
this.$delete(properties, this.pickKey)
|
||||
if (required) {
|
||||
const pos = required.indexOf(this.pickKey)
|
||||
pos >= 0 && required.splice(pos, 1)
|
||||
required.length === 0 && this.$delete(this.parent, 'required')
|
||||
}
|
||||
},
|
||||
_joinName() {
|
||||
return `feild_${this.deep}_${this.countAdd++}_${getUUID().substring(0, 5)}`
|
||||
},
|
||||
onSetting() {
|
||||
this.modalVisible = true;
|
||||
this.advancedValue = this.advanced.value
|
||||
for (const k in this.advancedValue) {
|
||||
if (this.pickValue[k]) this.advancedValue[k] = this.pickValue[k]
|
||||
}
|
||||
},
|
||||
handleClose() {
|
||||
this.modalVisible = false;
|
||||
},
|
||||
handleOk() {
|
||||
this.modalVisible = false
|
||||
for (const key in this.advancedValue) {
|
||||
if (isNull(this.advancedValue[key])) {
|
||||
this.$delete(this.pickValue, key)
|
||||
} else {
|
||||
this.$set(this.pickValue, key, this.advancedValue[key])
|
||||
}
|
||||
}
|
||||
for (const item of this.customProps) {
|
||||
this.$set(this.pickValue, item.key, item.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.json-schema-editor .row {
|
||||
display: flex;
|
||||
margin: 12px;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ms-col-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ms-col-name .ms-col-name-c {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ms-col-name .ms-col-name-required {
|
||||
flex: 0 0 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ms-col-type {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ms-col-setting {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .setting-icon {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .plus-icon {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .close-icon {
|
||||
color: #888;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal pre {
|
||||
font-family: monospace;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal h3 {
|
||||
display: block;
|
||||
border-left: 3px solid #1890ff;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal .ms-advanced-search-form {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal .ms-advanced-search-form .ms-form-item .ms-form-item-control-wrapper {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.col-item-setting {
|
||||
padding-top: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tip {
|
||||
padding: 3px 5px;
|
||||
font-size: 16px;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid #783887;
|
||||
margin: 0px 0px 10px;
|
||||
}
|
||||
.ms-transform {
|
||||
transform: rotate(-180deg);
|
||||
transition: 0ms;
|
||||
}
|
||||
</style>
|
@ -1,236 +0,0 @@
|
||||
<template>
|
||||
<el-dialog :title="$t('api_test.request.parameters_advance')"
|
||||
:visible.sync="itemValueVisible"
|
||||
class="advanced-item-value"
|
||||
width="70%">
|
||||
<el-tabs tab-position="top" style="height: 50vh;" @tab-click="selectTab">
|
||||
<el-tab-pane :label="$t('api_test.request.parameters_advance_mock')">
|
||||
<el-row type="flex" :gutter="20">
|
||||
<el-col :span="6" class="col-height">
|
||||
<div>
|
||||
<el-input size="small" v-model="filterText"
|
||||
:placeholder="$t('api_test.request.parameters_mock_filter_tips')"/>
|
||||
<el-tree class="filter-tree" ref="tree" :data="mockFuncs" :props="treeProps"
|
||||
default-expand-all @node-click="selectVariable"
|
||||
:filter-node-method="filterNode"></el-tree>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6" v-for="(itemFunc, itemIndex) in mockVariableFuncs" :key="itemIndex">
|
||||
<div v-for="(func, funcIndex) in funcs"
|
||||
:key="`${itemIndex}-${funcIndex}`">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-radio size="mini" v-model="itemFunc.name" :label="func.name"
|
||||
@change="methodChange(itemFunc, func)"/>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="itemFunc.name === func.name">
|
||||
<div v-for="(p, pIndex) in itemFunc.params" :key="`${itemIndex}-${funcIndex}-${pIndex}`">
|
||||
<el-input :placeholder="p.name" size="mini" v-model="p.value" @change="showPreview"/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('api_test.variable')">
|
||||
<el-row>
|
||||
<el-col :span="6" class="col-height">
|
||||
<div v-if="preRequestParams">
|
||||
<p>{{ $t('api_test.request.parameters_pre_request') }}</p>
|
||||
<el-tree :data="preRequestParams" :props="treeProps" @node-click="selectVariable"></el-tree>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="18" class="col-height">
|
||||
<div>
|
||||
<h1>{{ $t('api_test.request.jmeter_func') }}</h1>
|
||||
<el-table border :data="jmeterFuncs" class="adjust-table table-content" height="400">
|
||||
<el-table-column prop="type" label="Type" width="150"/>
|
||||
<el-table-column prop="name" label="Functions" width="250"/>
|
||||
<el-table-column prop="description" label="Description"/>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form>
|
||||
<el-form-item>
|
||||
<el-input :placeholder="valueText" size="small"
|
||||
v-model="itemValue"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="padding-top: 10px;">
|
||||
<el-row type="flex" align="middle">
|
||||
<el-col :span="12">
|
||||
<el-button size="small" type="primary" plain @click="saveAdvanced()">
|
||||
{{ $t('commons.save') }}
|
||||
</el-button>
|
||||
<el-button size="small" type="info" plain @click="addFunc()" v-if="currentTab === 0">
|
||||
{{ $t('api_test.request.parameters_advance_add_func') }}
|
||||
</el-button>
|
||||
<el-button size="small" type="success" plain @click="showPreview()" v-if="currentTab === 0">
|
||||
{{ $t('api_test.request.parameters_preview') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<div> {{ itemValuePreview }}</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {calculate} from "./calculate";
|
||||
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
||||
|
||||
export default {
|
||||
name: "MsApiVariableAdvance",
|
||||
props: {
|
||||
parameters: Array,
|
||||
currentItem: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
itemValueVisible: false,
|
||||
filterText: '',
|
||||
environmentParams: [],
|
||||
scenarioParams: [],
|
||||
Scenario: {},
|
||||
preRequests: [],
|
||||
preRequestParams: [],
|
||||
treeProps: {children: 'children', label: 'name'},
|
||||
currentTab: 0,
|
||||
itemValue: null,
|
||||
itemValuePreview: null,
|
||||
funcs: [
|
||||
{name: "md5"},
|
||||
{name: "base64"},
|
||||
{name: "unbase64"},
|
||||
{
|
||||
name: "substr",
|
||||
params: [{name: "start"}, {name: "length"}]
|
||||
},
|
||||
{
|
||||
name: "concat",
|
||||
params: [{name: "suffix"}]
|
||||
},
|
||||
{name: "lconcat", params: [{name: "prefix"}]},
|
||||
{name: "sha1"},
|
||||
{name: "sha224"},
|
||||
{name: "sha256"},
|
||||
{name: "sha384"},
|
||||
{name: "sha512"},
|
||||
{name: "lower"},
|
||||
{name: "upper"},
|
||||
{name: "length"},
|
||||
{name: "number"}
|
||||
],
|
||||
mockFuncs: MOCKJS_FUNC.map(f => {
|
||||
return {name: f.name, value: f.name}
|
||||
}),
|
||||
jmeterFuncs: JMETER_FUNC,
|
||||
mockVariableFuncs: [],
|
||||
jmeterVariableFuncs: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
valueText() {
|
||||
return this.valuePlaceholder || this.$t("api_test.value");
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.prepareData();
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.itemValueVisible = true;
|
||||
},
|
||||
prepareData() {
|
||||
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data.name.indexOf(value) !== -1;
|
||||
},
|
||||
selectVariable(node) {
|
||||
this.itemValue = node.value;
|
||||
},
|
||||
selectTab(tab) {
|
||||
this.currentTab = +tab.index;
|
||||
this.itemValue = null;
|
||||
this.itemValuePreview = null;
|
||||
},
|
||||
showPreview() {
|
||||
// 找到变量本身
|
||||
if (!this.itemValue) {
|
||||
return;
|
||||
}
|
||||
let index = this.itemValue.indexOf("|");
|
||||
if (index > -1) {
|
||||
this.itemValue = this.itemValue.substring(0, index).trim();
|
||||
}
|
||||
|
||||
this.mockVariableFuncs.forEach(f => {
|
||||
if (!f.name) {
|
||||
return;
|
||||
}
|
||||
this.itemValue += "|" + f.name;
|
||||
if (f.params) {
|
||||
this.itemValue += ":" + f.params.map(p => p.value).join(",");
|
||||
}
|
||||
});
|
||||
|
||||
this.itemValuePreview = calculate(this.itemValue);
|
||||
},
|
||||
methodChange(itemFunc, func) {
|
||||
let index = this.mockVariableFuncs.indexOf(itemFunc);
|
||||
this.mockVariableFuncs = this.mockVariableFuncs.slice(0, index);
|
||||
// 这里要用 deep copy
|
||||
this.mockVariableFuncs.push(JSON.parse(JSON.stringify(func)));
|
||||
this.showPreview();
|
||||
},
|
||||
addFunc() {
|
||||
if (this.mockVariableFuncs.length > 4) {
|
||||
this.$info(this.$t('api_test.request.parameters_advance_add_func_limit'));
|
||||
return;
|
||||
}
|
||||
if (this.mockVariableFuncs.length > 0) {
|
||||
let func = this.mockVariableFuncs[this.mockVariableFuncs.length - 1];
|
||||
if (!func.name) {
|
||||
this.$warning(this.$t('api_test.request.parameters_advance_add_func_error'));
|
||||
return;
|
||||
}
|
||||
if (func.params) {
|
||||
for (let j = 0; j < func.params.length; j++) {
|
||||
if (!func.params[j].value) {
|
||||
this.$warning(this.$t('api_test.request.parameters_advance_add_param_error'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.mockVariableFuncs.push({name: '', params: []});
|
||||
},
|
||||
saveAdvanced() {
|
||||
this.currentItem.mock = this.itemValue;
|
||||
this.itemValueVisible = false;
|
||||
this.mockVariableFuncs = [];
|
||||
this.$emit('advancedRefresh', this.itemValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.col-height {
|
||||
height: 40vh;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
@ -1,95 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-autocomplete
|
||||
size="small"
|
||||
class="input-with-autocomplete"
|
||||
v-model="mock.mock"
|
||||
:fetch-suggestions="funcSearch"
|
||||
:disabled="disabled"
|
||||
:placeholder="$t('api_test.value')"
|
||||
value-key="name"
|
||||
highlight-first-item
|
||||
@select="change">
|
||||
<i slot="suffix" class="el-input__icon el-icon-edit pointer" @click="advanced()"></i>
|
||||
</el-autocomplete>
|
||||
|
||||
<ms-advance ref="variableAdvance" :current-item="mock"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
||||
import MsAdvance from "./Advance";
|
||||
|
||||
export default {
|
||||
name: 'MsMock',
|
||||
components: {MsAdvance},
|
||||
props: {
|
||||
schema: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
}
|
||||
},
|
||||
disabled: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mock: {mock: ""}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.schema.mock && Object.prototype.toString.call(this.schema.mock).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') {
|
||||
this.mock = this.schema.mock;
|
||||
} else {
|
||||
this.schema.mock = this.mock;
|
||||
}
|
||||
if (this.schema.type === 'object') {
|
||||
this.$delete(this.schema, 'mock')
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
funcSearch(queryString, cb) {
|
||||
let funcs = MOCKJS_FUNC.concat(JMETER_FUNC);
|
||||
let results = queryString ? funcs.filter(this.funcFilter(queryString)) : funcs;
|
||||
// 调用 callback 返回建议列表的数据
|
||||
cb(results);
|
||||
},
|
||||
funcFilter(queryString) {
|
||||
return (func) => {
|
||||
return (func.name.toLowerCase().indexOf(queryString.toLowerCase()) > -1);
|
||||
};
|
||||
},
|
||||
change: function () {
|
||||
},
|
||||
advanced() {
|
||||
this.$refs.variableAdvance.open();
|
||||
},
|
||||
showEdit() {
|
||||
this.$emit('showEdit')
|
||||
},
|
||||
handleChange(e) {
|
||||
this.$emit('change', e)
|
||||
},
|
||||
querySearchAsync(queryString, cb) {
|
||||
const arr = this.mock || []
|
||||
const results = queryString
|
||||
? arr.filter(this.createStateFilter(queryString))
|
||||
: arr
|
||||
|
||||
cb(results)
|
||||
},
|
||||
createStateFilter(queryString) {
|
||||
return state => {
|
||||
return (
|
||||
state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
@ -1,31 +0,0 @@
|
||||
import Mock from "mockjs";
|
||||
import {funcFilters} from "@/common/js/func-filter";
|
||||
|
||||
export const calculate = function (itemValue) {
|
||||
if (!itemValue) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (itemValue.trim().startsWith("${")) {
|
||||
// jmeter 内置函数不做处理
|
||||
return itemValue;
|
||||
}
|
||||
let funcs = itemValue.split("|");
|
||||
let value = Mock.mock(funcs[0].trim());
|
||||
if (funcs.length === 1) {
|
||||
return value;
|
||||
}
|
||||
for (let i = 1; i < funcs.length; i++) {
|
||||
let func = funcs[i].trim();
|
||||
let args = func.split(":");
|
||||
let strings = [];
|
||||
if (args[1]) {
|
||||
strings = args[1].split(",");
|
||||
}
|
||||
value = funcFilters[args[0].trim()](value, ...strings);
|
||||
}
|
||||
return value;
|
||||
} catch (e) {
|
||||
return itemValue;
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
const value = {
|
||||
description: null,
|
||||
minItems:null,
|
||||
maxItems:null,
|
||||
uniqueItems:false
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string'
|
||||
},
|
||||
maxItems:{
|
||||
name: '最大元素个数',
|
||||
type: 'integer'
|
||||
},
|
||||
minItems:{
|
||||
name: '最小元素个数',
|
||||
type: 'integer'
|
||||
},
|
||||
uniqueItems:{
|
||||
name:'元素不可重复',
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
@ -1,11 +0,0 @@
|
||||
const value = {
|
||||
description: null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
@ -1,31 +0,0 @@
|
||||
const value = {
|
||||
description: null,
|
||||
maximum: null,
|
||||
minimum: null,
|
||||
exclusiveMaximum:null,
|
||||
exclusiveMinimum:null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string',
|
||||
},
|
||||
maximum:{
|
||||
name:'最大值',
|
||||
type:'integer'
|
||||
},
|
||||
minimum:{
|
||||
name:'最小值',
|
||||
type:'integer'
|
||||
},
|
||||
exclusiveMaximum:{
|
||||
name:'不包含最大值',
|
||||
type:'boolean'
|
||||
},
|
||||
exclusiveMinimum:{
|
||||
name:'不包含最小值',
|
||||
type:'boolean'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
@ -1,31 +0,0 @@
|
||||
const value = {
|
||||
description: null,
|
||||
maximum: null,
|
||||
minimum: null,
|
||||
exclusiveMaximum:null,
|
||||
exclusiveMinimum:null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string',
|
||||
},
|
||||
maximum:{
|
||||
name:'最大值',
|
||||
type:'number'
|
||||
},
|
||||
minimum:{
|
||||
name:'最小值',
|
||||
type:'number'
|
||||
},
|
||||
exclusiveMaximum:{
|
||||
name:'不包含最大值',
|
||||
type:'boolean'
|
||||
},
|
||||
exclusiveMinimum:{
|
||||
name:'不包含最小值',
|
||||
type:'boolean'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
@ -1,21 +0,0 @@
|
||||
const value = {
|
||||
description: null,
|
||||
maxProperties: null,
|
||||
minProperties: null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string',
|
||||
},
|
||||
maxProperties:{
|
||||
name:'最大元素个数',
|
||||
type:'integer'
|
||||
},
|
||||
minProperties:{
|
||||
name:'最小元素个数',
|
||||
type:'integer'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
@ -1,32 +0,0 @@
|
||||
const value = {
|
||||
description: null,
|
||||
maxLength: null,
|
||||
minLength: null,
|
||||
pattern: null,
|
||||
format:null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string',
|
||||
},
|
||||
maxLength:{
|
||||
name:'最大字符数',
|
||||
type:'integer'
|
||||
},
|
||||
minLength:{
|
||||
name:'最小字符数',
|
||||
type:'integer'
|
||||
},
|
||||
pattern: {
|
||||
name: '正则表达式',
|
||||
type:'string'
|
||||
},
|
||||
format: {
|
||||
name:'格式',
|
||||
type:'array',
|
||||
enums:['date','date-time','email','hostname','ipv4','ipv6','uri']
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
@ -1,17 +0,0 @@
|
||||
import _object from './object'
|
||||
import _string from './string'
|
||||
import _array from './array'
|
||||
import _boolean from './boolean'
|
||||
import _integer from './integer'
|
||||
import _number from './number'
|
||||
const TYPE_NAME = ['string', 'number', 'integer','object', 'array', 'boolean']
|
||||
|
||||
const TYPE = {
|
||||
'object': _object,
|
||||
'string': _string,
|
||||
'array': _array,
|
||||
'boolean': _boolean,
|
||||
'integer': _integer,
|
||||
'number': _number
|
||||
}
|
||||
export {TYPE ,TYPE_NAME}
|
@ -1,24 +0,0 @@
|
||||
export function clearAttr(obj) {
|
||||
for(let key in obj){
|
||||
delete obj[key]
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 快速拷贝两个对象的属性值
|
||||
* @param {*} source
|
||||
* @param {*} target
|
||||
*/
|
||||
export function copyAttr(source, target){
|
||||
Object.keys(target).forEach(key=>{target[key]=source[key]})
|
||||
}
|
||||
|
||||
export function isNull(ele){
|
||||
if(typeof ele==='undefined'){
|
||||
return true;
|
||||
}else if(ele==null){
|
||||
return true;
|
||||
}else if(ele==''){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import JsonSchemaEditor from './editor/index'
|
||||
const components = [
|
||||
JsonSchemaEditor
|
||||
]
|
||||
|
||||
// 定义 install 方法
|
||||
const install = function (Vue) {
|
||||
if (install.installed) return
|
||||
install.installed = true
|
||||
// 遍历并注册全局组件
|
||||
components.map(component => {
|
||||
Vue.component(component.name, component)
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && window.Vue) {
|
||||
install(window.Vue)
|
||||
}
|
||||
|
||||
export default {
|
||||
// 导出的对象必须具备一个 install 方法
|
||||
install,
|
||||
// 组件列表
|
||||
...components
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
<template>
|
||||
<el-row type="flex" justify="end">
|
||||
<div class="table-page">
|
||||
<el-pagination
|
||||
:current-page="currentPage"
|
||||
:page-sizes="pageSizes"
|
||||
:page-size="pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MsTablePagination',
|
||||
props: {
|
||||
page: Object,
|
||||
currentPage: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array,
|
||||
default: function() {
|
||||
return [5, 10, 20, 50, 100]
|
||||
}
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
change: Function
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange: function(size) {
|
||||
this.$emit('update:pageSize', size)
|
||||
this.change()
|
||||
},
|
||||
handleCurrentChange(current) {
|
||||
this.$emit('update:currentPage', current)
|
||||
this.change()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.table-page {
|
||||
padding-top: 20px;
|
||||
}
|
||||
</style>
|
@ -1,15 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
adfdsaf
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "RouterSidebar"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<div id="body">
|
||||
<router-view name="sidebar" class="sidebar"/>
|
||||
<router-view name="content" class="content"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsView"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#body {
|
||||
width: 100%;
|
||||
height: calc(100vh - 56px);
|
||||
/*background-color: #F5F5F5;*/
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: relative;
|
||||
width: 330px;
|
||||
height: 100%;
|
||||
max-width: 750px;
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
@ -1,57 +0,0 @@
|
||||
import Vue from "vue";
|
||||
import VueRouter from 'vue-router'
|
||||
import RouterSidebar from "./RouterSidebar";
|
||||
import Setting from "@/business/components/settings/router";
|
||||
import Chart from "@/business/components/chart/router";
|
||||
// import API from "@/business/components/api/router";
|
||||
// import Performance from "@/business/components/performance/router";
|
||||
import DataSet from "@/business/components/dataset/router";
|
||||
import Track from "@/business/components/track/router";
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const router = new VueRouter({
|
||||
routes: [
|
||||
{path: "/", redirect: '/setting/personsetting'},
|
||||
{
|
||||
path: "/sidebar",
|
||||
components: {
|
||||
sidebar: RouterSidebar
|
||||
}
|
||||
},
|
||||
Setting,
|
||||
Chart,
|
||||
// Performance,
|
||||
DataSet,
|
||||
Track,
|
||||
]
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
|
||||
//redirectLoginPath(to.fullPath);
|
||||
|
||||
next()
|
||||
});
|
||||
|
||||
//重复点击导航路由报错
|
||||
const routerPush = VueRouter.prototype.push;
|
||||
VueRouter.prototype.push = function push(location) {
|
||||
return routerPush.call(this, location).catch(error => error)
|
||||
}
|
||||
|
||||
|
||||
// 登入后跳转至原路径
|
||||
// function redirectLoginPath(originPath) {
|
||||
// let redirectUrl = sessionStorage.getItem('redirectUrl');
|
||||
// let loginSuccess = sessionStorage.getItem('loginSuccess');
|
||||
// sessionStorage.setItem('redirectUrl', originPath);
|
||||
// if (redirectUrl && loginSuccess) {
|
||||
// sessionStorage.removeItem('loginSuccess');
|
||||
// router.push(redirectUrl);
|
||||
// }
|
||||
// sessionStorage.removeItem('loginSuccess');
|
||||
// }
|
||||
|
||||
|
||||
export default router
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user