Commit cadf901e authored by 智勇's avatar 智勇

质效管理

parent 05fb3dba
......@@ -119,13 +119,6 @@ export function fetchTaglist(data) {
})
}
export function getType() {
return request({
url: '/proconfig/get_type',
method: 'get'
})
}
export function CreateCluService(data) {
return request({
url: '/k8s/service/create',
......
import request from '@/utils/request'
export function fetchSonarJob(data) {
return request({
url: '/sonar/getSonarJobs',
method: 'post',
data
})
}
export function fetchQuality(data) {
return request({
url: '/sonar/fetchQuality',
method: 'post',
data
})
}
......@@ -30,3 +30,10 @@ export function getHostName(query) {
params: query
})
}
export function getType() {
return request({
url: '/proconfig/get_type',
method: 'get'
})
}
......@@ -231,23 +231,35 @@ export const asyncRouterMap = [
name: 'quali',
meta: { title: '质效管理', icon: '' }
},
// {
// path: 'quali-old',
// component: () => import('@/views/pipeline/quali-old'),
// name: 'quali-old',
// meta: { title: '质效管理-old', icon: '' }
// },
// {
// path: 'manager',
// component: () => import('@/views/pipeline/manager'),
// name: 'manager',
// meta: { title: '流水线管理', icon: '' }
// },
// {
// path: 'adapter',
// component: () => import('@/views/pipeline/adapter'),
// name: 'adapter',
// meta: { title: '流水线适配', icon: '' }
// },
// {
// path: 'job-old',
// component: () => import('@/views/pipeline/job-old'),
// name: 'job-old',
// meta: { title: 'Job实例-old', icon: '' }
// },
{
path: 'manager',
component: () => import('@/views/pipeline/manager'),
name: 'manager',
meta: { title: '流水线管理', icon: '' }
},
{
path: 'adapter',
component: () => import('@/views/pipeline/adapter'),
name: 'adapter',
meta: { title: '流水线适配', icon: '' }
},
{
path: 'job',
component: () => import('@/views/pipeline/job'),
path: 'sonarJob',
component: () => import('@/views/pipeline/sonarJob'),
name: 'job',
meta: { title: 'Job实例', icon: '' }
meta: { title: 'Sonar Job', icon: '' }
},
{
path: 'jobDetail',
......
......@@ -8,6 +8,7 @@ const getters = {
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
username: state => state.user.username,
introduction: state => state.user.introduction,
status: state => state.user.status,
roles: state => state.user.roles,
......
......@@ -35,6 +35,9 @@ const user = {
SET_NAME: (state, name) => {
state.name = name
},
SET_USERNAME: (state, user) => {
state.username = user
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
......@@ -76,6 +79,7 @@ const user = {
reject('getInfo: roles must be a non-null array!')
}
commit('SET_NAME', data.name)
commit('SET_USERNAME', data.user)
// commit('SET_AVATAR', data.avatar)
// commit('SET_INTRODUCTION', data.introduction)
resolve(response)
......
......@@ -52,9 +52,15 @@
<template slot-scope="scope">
<i v-if="scope.row.status == 'Normal'" class="el-icon-success" style="color: #67c23a"/>
<i v-else class="el-icon-error" style="color: #f56c6c"/>
<span v-if="scope.row.serviceName !== 'rabbitmq'">{{ scope.row.serviceName }}</span>
<span v-if="scope.row.serviceName === 'consul'">
<span class="link-type" style="margin-right:5px" @click="openConsole(scope.row)">
{{ scope.row.serviceName }}
</span>
</span>
<span v-if="scope.row.serviceName === 'rabbitmq'" >
<span class="link-type" style="margin-right:5px" @click="openRabbitmq(scope.row)">
<span class="link-type" style="margin-right:5px" @click="openConsole(scope.row)">
{{ scope.row.serviceName }}
</span>
......@@ -75,6 +81,7 @@
</el-popover>
</span>
<span v-if="scope.row.serviceName !== 'rabbitmq'&& scope.row.serviceName !== 'consul'">{{ scope.row.serviceName }}</span>
</template>
</el-table-column>
<el-table-column
......@@ -141,7 +148,7 @@
<div v-for="(item,index) in typeList" :key="index" class="shadow-content">
<div class="warn-content">
<svg-icon icon-class="service"/>
{{ item._id }}服务
{{ item._id.toUpperCase() }} 服务
<div style="float: right">
<el-button type="warning" size="mini" round @click="getRepository(item._id)">新增服务</el-button>
<el-button type="success" size="mini" round @click="refresh">刷新状态</el-button>
......@@ -326,8 +333,8 @@
</el-col>
</el-row>
<p v-if="label==='node'||label==='java'" class="title-sub">是否调试模式<span style="font-size: 12px">(执行测试时选择默认选项否即可)</span> </p>
<el-row v-if="label==='node'||label==='java'" :gutter="20">
<p v-if="label==='node'||label==='java'||label==='go'" class="title-sub">是否调试模式<span style="font-size: 12px">(执行测试时选择默认选项否即可)</span> </p>
<el-row v-if="label==='node'||label==='java'||label==='go'" :gutter="20">
<el-col :span="14">
<el-select v-model="debug.key" filterable clearable class="elSelect" placeholder="请选择是否调试模式,执行测试时请选择否">
<el-option v-for="item in debugOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
......@@ -421,7 +428,6 @@ import {
fetchK8sdetail,
fetchUserrepository,
fetchTaglist,
getType,
CreateCluService,
fetchServiceDetails,
modifyCluService,
......@@ -434,6 +440,7 @@ import {
ingressHost,
mqDiff
} from '@/api/docker'
import { getType } from '@/api/proconfig'
import JsonEditor from '@/components/JsonEditor'
import permission from '@/directive/permission/index.js' // 权限判断指令
import { getHostName } from '@/api/proconfig'
......@@ -622,8 +629,15 @@ export default {
// window.open(`http://${url}/`, '_blank')
// })
},
openRabbitmq(data) {
const port = data.portMappings.filter(item => item.port === 15672)[0].nodePort
openConsole(data) {
console.log(1, data)
let port
if (data.serviceName === 'rabbitmq') {
port = data.portMappings.filter(item => item.port === 15672)[0].nodePort
}
if (data.serviceName === 'consul') {
port = data.portMappings.filter(item => item.port === 8500)[0].nodePort
}
window.open(`http://${data.lanIp}:${port}/`, '_blank')
},
getServiceDetails(value) {
......
......@@ -14,7 +14,6 @@
</div>
<el-table
v-loading="listLoading"
:data="applications"
border
fit
......@@ -153,7 +152,6 @@ export default {
repository: '',
total: 0,
cacheData: {},
listLoading: true,
listQuery: {
},
temp: {
......@@ -231,10 +229,6 @@ export default {
}
})
}
// this.applications = res.data.map((item)=>{
//
// })
this.listLoading = false
})
},
newRepoAndRef() {
......@@ -264,12 +258,11 @@ export default {
handleCreate() {
this.resetTemp()
this.dialogStatus = '新建'
getProjects({ is_active: true }).then(res => {
getProjects({ is_active: true, deploy_to_testenv: true }).then(res => {
this.repos = res.data
this.repos.sort((s1, s2) => {
return s1.project_name.localeCompare(s2.project_name)
})
this.listLoading = false
})
this.dialogFormVisible = true
},
......@@ -386,7 +379,6 @@ export default {
this.repos.sort((s1, s2) => {
return s1.project_name.localeCompare(s2.project_name)
})
this.listLoading = false
row.repos.forEach(item => {
this.getRefs(item.repository)
})
......
<template>
<div class="app-container">
<div style="margin-bottom:20px">
<el-input v-model="listQuery.repository" placeholder="项目名称" clearable style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-date-picker
v-model="dateRange"
:picker-options="pickerOptions2"
style="width:280px"
type="daterange"
align="right"
unlink-panels
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"/>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button>
</div>
<el-table
v-loading="listLoading"
:data="qualis"
:header-cell-style="{background:'#F3F4F7',color:'#555'}"
border
fit
highlight-current-row
style="width: 100%;">
<el-table-column label="ID" type="index" align="center" width="65"/>
<el-table-column label="项目" prop="repository" align="center">
<template slot-scope="scope">
<span>{{ scope.row.repository }}</span>
</template>
</el-table-column>
<el-table-column label="Task sum" prop="run" align="center"/>
<el-table-column label="Task success" prop="success" align="center"/>
<el-table-column label="Task fail" align="center">
<template slot-scope="scope">
<span>{{ scope.row.fail + scope.row.exception }}</span>
</template>
</el-table-column>
<el-table-column label="成功率" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.success/scope.row.run | statusFilter">{{ scope.row.success/scope.row.run*100 | decimalsFilter }}%</el-tag>
</template>
</el-table-column>
<el-table-column label="Sonar" align="center" width="180" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" @click="handleInfo(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
<!-- <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" /> -->
</div>
</template>
<script>
import { getQuali } from '@/api/pipeline'
import waves from '@/directive/waves' // Waves directive
export default {
directives: { waves },
filters: {
decimalsFilter(num) {
return num.toFixed(2)
},
statusFilter(num) {
let status = 'success'
if (num >= 0.7 && num <= 0.9) {
status = 'info'
}
if (num >= 0.4 && num <= 0.7) {
status = 'warning'
}
if (num >= 0 && num <= 0.4) {
status = 'danger'
}
return status
}
},
data() {
return {
pickerOptions2: {
shortcuts: [{
text: '最近一周',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
picker.$emit('pick', [start, end])
}
}, {
text: '最近一个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
picker.$emit('pick', [start, end])
}
}, {
text: '最近三个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
picker.$emit('pick', [start, end])
}
}]
},
qualis: [],
dateRange: [],
listLoading: true,
listQuery: {}
}
},
computed: {
// dateRange: {
// get: function() {
// const end = new Date(new Date().getTime() + 24 * 60 * 60 * 1000)
// const start = new Date(end.getTime() - 5 * 24 * 60 * 60 * 1000)
// return [start, end]
// },
// set: function(dates) {
// this.dateRange = this.dates
// }
// }
},
created() {
this.getQuali()
},
methods: {
getQuali() {
for (const prop in this.listQuery) {
if (this.listQuery[prop] === '') {
delete this.listQuery[prop]
}
}
this.listLoading = true
if (!this.dateRange || this.dateRange[1] === undefined) {
this.dateRange = []
this.dateRange[1] = new Date(new Date().getTime() + 24 * 60 * 60 * 1000)
}
if (!this.dateRange || this.dateRange[0] === undefined) {
this.dateRange[0] = new Date(this.dateRange[1].getTime() - 5 * 24 * 60 * 60 * 1000)
}
this.listQuery.startDate = this.formartTime(this.dateRange[0])
this.listQuery.endDate = this.formartTime(this.dateRange[1])
getQuali(this.listQuery).then(res => {
this.qualis = res.data.data.sort((s1, s2) => {
return s1.repository.localeCompare(s2.repository)
})
this.listLoading = false
})
},
handleInfo(row) {
const startDate = this.formartTime(this.dateRange[0])
const endDate = this.formartTime(this.dateRange[1])
this.$router.push({ name: 'qualiSonar', query: { repository: row.repository, startDate: startDate, endDate: endDate }})
},
formartTime(date) {
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
},
handleFilter() {
this.getQuali()
}
}
}
</script>
<style scoped>
</style>
<template>
<div class="app-container">
<div style="margin-bottom:20px">
<el-input v-model="listQuery.repository" placeholder="项目名称" clearable style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-input v-model="listQuery.projectName" placeholder="项目名称" clearable style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-date-picker
v-model="dateRange"
:picker-options="pickerOptions2"
:default-time="['00:00:00', '23:59:59']"
style="width:280px"
type="daterange"
align="right"
......@@ -18,39 +19,39 @@
</div>
<el-table
v-loading="listLoading"
:data="qualis"
:header-cell-style="{background:'#F3F4F7',color:'#555'}"
border
max-height="700"
fit
highlight-current-row
style="width: 100%;">
<el-table-column label="ID" type="index" align="center" width="65"/>
<el-table-column label="项目" prop="repository" align="center">
<el-table-column sortable label="项目" prop="projectName" align="center">
<template slot-scope="scope">
<span>{{ scope.row.repository }}</span>
<span>{{ scope.row.projectName }}</span>
</template>
</el-table-column>
<el-table-column label="Task sum" prop="run" align="center"/>
<el-table-column sortable label="Task sum" prop="run" align="center"/>
<el-table-column label="Task success" prop="success" align="center"/>
<el-table-column sortable label="Task success" prop="success" align="center"/>
<el-table-column label="Task fail" align="center">
<el-table-column :sort-method="sortFail" sortable label="Task fail" align="center">
<template slot-scope="scope">
<span>{{ scope.row.fail + scope.row.exception }}</span>
</template>
</el-table-column>
<el-table-column label="成功率" align="center">
<el-table-column :sort-method="sortRate" sortable label="成功率" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.success/scope.row.run | statusFilter">{{ scope.row.success/scope.row.run*100 | decimalsFilter }}%</el-tag>
</template>
</el-table-column>
<el-table-column label="Sonar" align="center" width="180" class-name="small-padding fixed-width">
<el-table-column label="详情" align="center" width="180" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" @click="handleInfo(scope.row)">详情</el-button>
</template>
......@@ -64,7 +65,7 @@
</template>
<script>
import { getQuali } from '@/api/pipeline'
import { fetchQuality } from '@/api/pipeline1'
import waves from '@/directive/waves' // Waves directive
export default {
......@@ -118,7 +119,6 @@ export default {
},
qualis: [],
dateRange: [],
listLoading: true,
listQuery: {}
}
},
......@@ -141,6 +141,12 @@ export default {
},
methods: {
sortFail(a, b) {
return (a.exception + a.fail) - (b.exception + b.fail)
},
sortRate(a, b) {
return a.success / a.run - b.success / b.run
},
getQuali() {
for (const prop in this.listQuery) {
if (this.listQuery[prop] === '') {
......@@ -148,31 +154,29 @@ export default {
}
}
this.listLoading = true
if (!this.dateRange || this.dateRange[1] === undefined) {
this.dateRange = []
this.dateRange[1] = new Date(new Date().getTime() + 24 * 60 * 60 * 1000)
if (this.dateRange.length === 0) {
this.dateRange[1] = new Date(new Date().getTime())
this.dateRange[0] = new Date(this.dateRange[1].getTime() - 3 * 24 * 60 * 60 * 1000)
}
if (!this.dateRange || this.dateRange[0] === undefined) {
this.dateRange[0] = new Date(this.dateRange[1].getTime() - 5 * 24 * 60 * 60 * 1000)
}
this.listQuery.startDate = this.dateRange[0]
this.listQuery.endDate = this.dateRange[1]
this.listQuery.startDate = this.formartTime(this.dateRange[0])
this.listQuery.endDate = this.formartTime(this.dateRange[1])
getQuali(this.listQuery).then(res => {
this.qualis = res.data.data.sort((s1, s2) => {
return s1.repository.localeCompare(s2.repository)
fetchQuality(this.listQuery).then(res => {
this.qualis = res.data.sort((s1, s2) => {
return s1.projectName.localeCompare(s2.projectName)
})
this.listLoading = false
})
},
handleInfo(row) {
const startDate = this.formartTime(this.dateRange[0])
const endDate = this.formartTime(this.dateRange[1])
this.$router.push({ name: 'qualiSonar', query: { repository: row.repository, startDate: startDate, endDate: endDate }})
this.$router.push({
name: 'job',
query: {
projectName: row.projectName,
startDate: JSON.stringify(this.listQuery.startDate),
endDate: JSON.stringify(this.listQuery.endDate)
}
})
},
formartTime(date) {
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
......
<template>
<div class="app-container">
<div style="margin-bottom:20px">
<div style="margin-bottom:10px">
<el-input v-model="listQuery.query.projectName" placeholder="服务名称" clearable style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-input v-model="listQuery.query.branchName" placeholder="分支名称" clearable style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-input v-model="listQuery.query.gitUser" placeholder="触发者" clearable style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-date-picker
v-model="dateRange"
:default-time="['00:00:00', '23:59:59']"
type="daterange"
style="width:280px"
align="right"
unlink-panels
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"/>
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button>
</div>
<el-table
:data="jobs"
fit
highlight-current-row
style="width: 100%;">
<el-table-column type="index" align="center" width="65"/>
<el-table-column label="项目" prop="projectName" align="center"/>
<el-table-column label="分支" prop="branchName" align="center"/>
<el-table-column prop="gitUser" label="触发者" align="center"/>
<el-table-column prop="commitMes" label="触发信息" align="center"/>
<el-table-column prop="status" label="状态" width="120" >
<template slot-scope="scope">
<i :class="scope.row.statusIcon"/>
<span> {{ scope.row.desc }}</span>
</template>
</el-table-column>
<el-table-column :formatter="formatDate" label="触发时间" align="center"/>
<el-table-column label="操作" align="center" width="250">
<template slot-scope="scope">
<el-button :disabled="!scope.row.buildResult" size="mini" @click="handleJenkins(scope.row)">Job信息</el-button>
<el-button :disabled="!scope.row.buildResult" type="primary" size="mini" @click="handleSonar(scope.row)">Sonar结果</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination :total="jobCount" :current-page.sync="page" background style="margin-top:20px" @current-change="handleCurrentChange"/>
</div>
</div></template>
<script>
import { fetchSonarJob } from '@/api/pipeline1'
import moment from 'moment'
export default {
filters: {
},
data() {
return {
listQuery: {
query: {},
page: {
num: 0,
count: 10
}
},
jobs: [],
jobCount: 10,
page: 1,
dateRange: []
}
},
created() {
this.listQuery.query.projectName = this.$route.query.projectName
this.listQuery.query.gitUser = this.$route.query.gitUser
if (this.$route.query.startDate) {
this.dateRange[0] = JSON.parse(this.$route.query.startDate)
}
if (this.$route.query.endDate) {
this.dateRange[1] = this.$route.query.endDate
this.dateRange[1] = JSON.parse(this.$route.query.endDate)
}
this.fetchSonarJob()
},
methods: {
handleCurrentChange() {
this.fetchSonarJob()
},
handleFilter() {
this.page = 1
this.fetchSonarJob()
},
fetchSonarJob() {
this.listQuery.page.num = this.page - 1
if (!this.dateRange) {
this.dateRange = []
}
// if (this.dateRange.length === 0) {
// this.dateRange[1] = new Date(new Date().getTime())
// this.dateRange[0] = new Date(this.dateRange[1].getTime() - 3 * 24 * 60 * 60 * 1000)
// }
this.listQuery.query.startDate = this.dateRange[0]
this.listQuery.query.endDate = this.dateRange[1]
fetchSonarJob(this.listQuery).then(res => {
this.jobs = res.data.data
this.jobCount = res.data.count
this.jobs.forEach(item => {
if (item.buildResult === 'success') {
item.desc = item.sonarResult
switch (item.sonarResult) {
case 'OK':
item.statusIcon = 'el-icon-success'
break
case 'ERROR':
item.statusIcon = 'el-icon-error'
break
case 'WARN':
item.statusIcon = 'el-icon-warning'
break
default:
item.statusIcon = 'el-icon-loading'
break
}
} else if (item.buildResult === 'error') {
item.statusIcon = 'el-icon-remove'
item.desc = 'EXCEPTION'
} else {
item.statusIcon = 'el-icon-loading'
}
})
}).catch(() => {
})
},
formatDate(row, val) {
const pattern = 'YYYY-MM-DD HH:mm:ss'
return moment(row.createdAt).format(pattern)
},
handleInfo(row) {
this.$router.push({ name: 'jobDetail', query: { pipelineId: row.id }})
},
handleHook(row) {
this.$router.push({ name: 'hookInfo', query: { gitHookReceiveId: row.gitHookReceiveId }})
},
handleJenkins(row) {
window.open(`http://192.168.4.96:8080/job/${row.buildJob}/${row.buildId}/console`, '_blank')
},
handleSonar(row) {
window.open(`http://sonar.quantgroups.com/project/activity?id=${row.projectName}&selected_date=${row.analysisDate}`, '_blank')
}
}
}
</script>
......@@ -18,12 +18,13 @@
<el-table
:data="proconfigs"
fit
max-height="700"
size="medium"
style="width: 100%;">
<el-table-column label="ID" type="index" align="center" width="55"/>
<el-table-column label="服务名称" align="center" >
<el-table-column label="服务名称" align="center">
<template slot-scope="scope">
<span class="link-type" @click="handleUpdate(scope.row)">{{ scope.row.project_name }}</span>
</template>
......@@ -213,17 +214,10 @@
</template>
<script>
import { getProjects, saveProject, deleteProject } from '@/api/proconfig'
import { getProjects, saveProject, deleteProject, getType } from '@/api/proconfig'
import waves from '@/directive/waves' // Waves directive
import permission from '@/directive/permission/index.js' // 权限判断指令
const typeOptions = [
{ key: 'java', display_name: 'Java' },
{ key: 'ui', display_name: 'UI' },
{ key: 'node', display_name: 'Nodejs' },
{ key: 'python', display_name: 'Python' }
]
const avtiveOptions = [
{ key: true, display_name: '服役中' },
{ key: false, display_name: '退役了' }
......@@ -269,7 +263,7 @@ export default {
is_active: true,
sort: '+project_name'
},
typeOptions,
typeOptions: [],
sortOptions: [{ label: '项目名升序', key: '+project_name' }, { label: '项目名降序', key: '-project_name' }],
temp: {
},
......@@ -302,6 +296,7 @@ export default {
}
},
created() {
this.getType()
this.disabled = !this.$store.getters.roles.includes('admin')
},
methods: {
......@@ -335,6 +330,14 @@ export default {
this.getProjects()
},
getType() {
getType().then((res) => {
this.typeOptions = res.data.map(i => {
return { key: i._id, display_name: i._id.toUpperCase() }
})
})
},
handleCreate() {
this.temp = {}
this.dialogStatus = 'create'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment