refactor: update case API to use camelCase for parameters and add import/export functionality for case templates
This commit is contained in:
@@ -33,10 +33,14 @@ export function deleteModule(data) {
|
||||
}
|
||||
|
||||
export function getCaseList(projectId, params) {
|
||||
const query = Object.assign({}, params || {})
|
||||
if (projectId !== undefined && projectId !== null && projectId !== '') {
|
||||
query.projectId = projectId
|
||||
}
|
||||
return request({
|
||||
url: '/case/list',
|
||||
method: 'get',
|
||||
params: Object.assign({ project_id: projectId }, params || {})
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
@@ -45,8 +49,8 @@ export function getCaseDetail(projectId, caseId) {
|
||||
url: '/case/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
project_id: projectId,
|
||||
id: caseId
|
||||
projectId,
|
||||
caseId
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -55,7 +59,7 @@ export function createCase(projectId, data) {
|
||||
return request({
|
||||
url: '/case/create',
|
||||
method: 'post',
|
||||
data: Object.assign({ project_id: projectId }, data)
|
||||
data: Object.assign({ projectId }, data)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -63,7 +67,7 @@ export function updateCase(projectId, caseId, data) {
|
||||
return request({
|
||||
url: '/case/update',
|
||||
method: 'post',
|
||||
data: Object.assign({ project_id: projectId, id: caseId }, data)
|
||||
data: Object.assign({ projectId, caseId }, data)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -72,8 +76,8 @@ export function deleteCase(projectId, caseId) {
|
||||
url: '/case/delete',
|
||||
method: 'post',
|
||||
data: {
|
||||
project_id: projectId,
|
||||
id: caseId
|
||||
projectId,
|
||||
caseId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,8 +2,44 @@
|
||||
<div class="page-wrap">
|
||||
<page-section :title="form.id ? '编辑用例' : '新建用例'">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px" size="small">
|
||||
<el-form-item label="项目ID">
|
||||
<el-input v-model="projectId" style="width: 200px;"></el-input>
|
||||
<el-form-item label="产品" prop="productId">
|
||||
<el-select
|
||||
v-model="form.productId"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择产品"
|
||||
style="width: 360px;"
|
||||
@change="handleProductChange"
|
||||
@focus="loadProductOptions">
|
||||
<el-option v-for="item in productOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目" prop="projectId">
|
||||
<el-select
|
||||
v-model="form.projectId"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择项目"
|
||||
style="width: 360px;"
|
||||
:disabled="!form.productId"
|
||||
@change="handleProjectChange">
|
||||
<el-option v-for="item in projectOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="模块" prop="moduleId">
|
||||
<el-select
|
||||
v-model="form.moduleId"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择模块"
|
||||
style="width: 360px;"
|
||||
:disabled="!form.projectId"
|
||||
@focus="loadModuleOptions">
|
||||
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="用例编号">
|
||||
<el-input v-model="form.caseKey" placeholder="不填则由后端自动生成"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="标题" prop="title">
|
||||
<el-input v-model="form.title"></el-input>
|
||||
@@ -23,19 +59,32 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<el-select v-model="form.case_type">
|
||||
<el-select v-model="form.caseType">
|
||||
<el-option label="功能" :value="1"></el-option>
|
||||
<el-option label="性能" :value="2"></el-option>
|
||||
<el-option label="安全" :value="3"></el-option>
|
||||
<el-option label="接口" :value="4"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="form.status">
|
||||
<el-option label="正常" :value="1"></el-option>
|
||||
<el-option label="已废弃" :value="2"></el-option>
|
||||
<el-option label="评审中" :value="3"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否自动化">
|
||||
<el-select v-model="form.isAuto">
|
||||
<el-option label="未实现" :value="0"></el-option>
|
||||
<el-option label="已实现" :value="1"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签">
|
||||
<el-input v-model="tagsText" placeholder="多个标签用逗号分隔"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="saving" @click="submitForm">保存</el-button>
|
||||
<el-button @click="$router.push('/test-platform/cases')">返回</el-button>
|
||||
<el-button @click="backList">返回</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</page-section>
|
||||
@@ -44,7 +93,9 @@
|
||||
|
||||
<script>
|
||||
import PageSection from '@/components/TestPlatform/common/PageSection'
|
||||
import { createCase, getCaseDetail, updateCase } from '@/api/caseApi'
|
||||
import { createCase, getCaseDetail, getModuleTree, updateCase } from '@/api/caseApi'
|
||||
import { getProductList } from '@/api/productApi'
|
||||
import { getProjectDetail, getProjectList } from '@/api/projectApi'
|
||||
|
||||
export default {
|
||||
name: 'CaseEditor',
|
||||
@@ -52,59 +103,175 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
saving: false,
|
||||
projectId: this.$route.query.projectId || 1,
|
||||
productOptions: [],
|
||||
projectOptions: [],
|
||||
moduleOptions: [],
|
||||
form: {
|
||||
productId: this.$route.query.productId ? Number(this.$route.query.productId) : '',
|
||||
projectId: this.$route.query.projectId ? Number(this.$route.query.projectId) : '',
|
||||
id: '',
|
||||
moduleId: '',
|
||||
caseKey: '',
|
||||
title: '',
|
||||
preconditions: '',
|
||||
steps: [],
|
||||
priority: 2,
|
||||
case_type: 1,
|
||||
tags: []
|
||||
caseType: 1,
|
||||
tags: [],
|
||||
status: 1,
|
||||
isAuto: 0
|
||||
},
|
||||
stepsText: '[]',
|
||||
tagsText: '',
|
||||
rules: {
|
||||
productId: [{ required: true, message: '请选择产品', trigger: 'change' }],
|
||||
projectId: [{ required: true, message: '请选择项目', trigger: 'change' }],
|
||||
moduleId: [{ required: true, message: '请选择模块', trigger: 'change' }],
|
||||
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
|
||||
steps: [{ required: true, message: '请输入步骤', trigger: 'change' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadProductOptions() {
|
||||
if (this.productOptions && this.productOptions.length > 0) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
return getProductList({ pageNo: 1, pageSize: 1000, status: 1 }).then(res => {
|
||||
const data = res && res.data ? res.data : res || {}
|
||||
this.productOptions = data.items || data.list || data.data || []
|
||||
}).catch(() => {
|
||||
this.productOptions = []
|
||||
})
|
||||
},
|
||||
loadProjectOptions() {
|
||||
if (!this.form.productId) {
|
||||
this.projectOptions = []
|
||||
return Promise.resolve()
|
||||
}
|
||||
return getProjectList({ pageNo: 1, pageSize: 1000, status: 1, productId: this.form.productId }).then(res => {
|
||||
const data = res && res.data ? res.data : res || {}
|
||||
this.projectOptions = data.items || data.list || data.data || []
|
||||
}).catch(() => {
|
||||
this.projectOptions = []
|
||||
})
|
||||
},
|
||||
loadModuleOptions() {
|
||||
if (!this.form.projectId) {
|
||||
this.moduleOptions = []
|
||||
return Promise.resolve()
|
||||
}
|
||||
return getModuleTree({ projectId: this.form.projectId }).then(res => {
|
||||
const data = (res && res.data) || res || {}
|
||||
const list = data.list || data.items || []
|
||||
this.moduleOptions = Array.isArray(list) ? list : []
|
||||
}).catch(() => {
|
||||
this.moduleOptions = []
|
||||
})
|
||||
},
|
||||
handleProductChange() {
|
||||
this.form.projectId = ''
|
||||
this.form.moduleId = ''
|
||||
this.projectOptions = []
|
||||
this.moduleOptions = []
|
||||
this.loadProjectOptions()
|
||||
},
|
||||
handleProjectChange() {
|
||||
this.form.moduleId = ''
|
||||
this.moduleOptions = []
|
||||
this.loadModuleOptions()
|
||||
},
|
||||
fetchDetail() {
|
||||
const caseId = this.$route.query.caseId
|
||||
if (!caseId) {
|
||||
return
|
||||
}
|
||||
getCaseDetail(this.projectId, caseId).then(res => {
|
||||
getCaseDetail(this.form.projectId, caseId).then(res => {
|
||||
const data = (res && res.data) || res || {}
|
||||
this.form = Object.assign({}, this.form, data)
|
||||
this.stepsText = JSON.stringify(data.steps || [], null, 2)
|
||||
this.tagsText = (data.tags || []).join(',')
|
||||
this.form = Object.assign({}, this.form, {
|
||||
id: data.id || caseId,
|
||||
moduleId: data.moduleId || data.module_id || '',
|
||||
caseKey: data.caseKey || data.case_key || '',
|
||||
title: data.title || '',
|
||||
preconditions: data.preconditions || '',
|
||||
steps: data.steps || [],
|
||||
priority: data.priority !== undefined ? data.priority : 2,
|
||||
caseType: data.caseType || data.case_type || 1,
|
||||
tags: data.tags || [],
|
||||
status: data.status || 1,
|
||||
isAuto: data.isAuto !== undefined ? data.isAuto : (data.is_auto !== undefined ? data.is_auto : 0)
|
||||
})
|
||||
this.stepsText = JSON.stringify(this.form.steps || [], null, 2)
|
||||
this.tagsText = Array.isArray(this.form.tags) ? this.form.tags.join(',') : (this.form.tags || '')
|
||||
if (this.form.projectId) {
|
||||
this.loadModuleOptions()
|
||||
}
|
||||
})
|
||||
},
|
||||
submitForm() {
|
||||
let steps = []
|
||||
try {
|
||||
this.form.steps = JSON.parse(this.stepsText || '[]')
|
||||
steps = JSON.parse(this.stepsText || '[]')
|
||||
} catch (e) {
|
||||
this.$message({ type: 'error', message: '步骤 JSON 格式错误' })
|
||||
return
|
||||
}
|
||||
this.form.tags = this.tagsText ? this.tagsText.split(',').map(item => item.trim()).filter(Boolean) : []
|
||||
const tags = this.tagsText ? this.tagsText.split(',').map(item => item.trim()).filter(Boolean) : []
|
||||
const payload = this.cleanParams({
|
||||
projectId: this.form.projectId,
|
||||
moduleId: this.form.moduleId,
|
||||
caseKey: this.form.caseKey,
|
||||
title: this.form.title,
|
||||
preconditions: this.form.preconditions,
|
||||
steps,
|
||||
priority: this.form.priority,
|
||||
caseType: this.form.caseType,
|
||||
tags,
|
||||
status: this.form.status,
|
||||
isAuto: this.form.isAuto
|
||||
})
|
||||
this.saving = true
|
||||
const request = this.form.id || this.$route.query.caseId
|
||||
? updateCase(this.projectId, this.form.id || this.$route.query.caseId, this.form)
|
||||
: createCase(this.projectId, this.form)
|
||||
const caseId = this.form.id || this.$route.query.caseId
|
||||
const request = caseId ? updateCase(this.form.projectId, caseId, payload) : createCase(this.form.projectId, payload)
|
||||
request.then(() => {
|
||||
this.$message({ type: 'success', message: '保存成功' })
|
||||
this.$router.push({ path: '/test-platform/cases', query: { projectId: this.projectId } })
|
||||
this.backList()
|
||||
}).finally(() => {
|
||||
this.saving = false
|
||||
})
|
||||
},
|
||||
cleanParams(params) {
|
||||
return Object.keys(params).reduce((result, key) => {
|
||||
if (params[key] !== '' && params[key] !== undefined && params[key] !== null) {
|
||||
result[key] = params[key]
|
||||
}
|
||||
return result
|
||||
}, {})
|
||||
},
|
||||
backList() {
|
||||
this.$router.push({ path: '/test-platform/case', query: { productId: this.form.productId || undefined, projectId: this.form.projectId || undefined } })
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchDetail()
|
||||
this.loadProductOptions().then(() => {
|
||||
if (this.form.projectId && !this.form.productId) {
|
||||
return getProjectDetail(this.form.projectId).then(res => {
|
||||
const data = res && res.data ? res.data : res || {}
|
||||
const pid = data.productId || data.product_id || ''
|
||||
if (pid) {
|
||||
this.form.productId = pid
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
}).then(() => {
|
||||
return this.loadProjectOptions()
|
||||
}).then(() => {
|
||||
if (this.form.projectId) {
|
||||
return this.loadModuleOptions()
|
||||
}
|
||||
}).finally(() => {
|
||||
this.fetchDetail()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -26,17 +26,30 @@ service.interceptors.request.use(
|
||||
// 响应拦截 401 token过期处理
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
if(response.data.code===500){
|
||||
Message.error("服务异常")
|
||||
}else if(response.data.code===451){
|
||||
router.push({name:'login'})
|
||||
}
|
||||
else {
|
||||
const data = response && response.data ? response.data : {}
|
||||
// 兼容后端返回结构:{ success, code, message, data }
|
||||
if (data && data.code === 500) {
|
||||
Message.error('服务异常')
|
||||
} else if (data && data.code === 451) {
|
||||
router.push({ name: 'login' })
|
||||
} else if (data && data.success === false) {
|
||||
Message.error(data.message || '请求失败')
|
||||
} else {
|
||||
return response.data
|
||||
}
|
||||
},
|
||||
error => {
|
||||
// 错误提醒
|
||||
// 非 2xx 时会进入这里(如 40009/40012),后端通常会带 JSON body
|
||||
const data = error && error.response && error.response.data ? error.response.data : null
|
||||
if (data && typeof data === 'object') {
|
||||
if (data.success === false) {
|
||||
Message.error(data.message || '请求失败')
|
||||
} else if (data.code && data.code !== 20000 && data.message) {
|
||||
Message.error(data.message || '请求失败')
|
||||
}
|
||||
} else if (error && error.message) {
|
||||
Message.error(error.message)
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user