功能更新:新增Bug管理模块,完善用户角色分配,优化项目设置

This commit is contained in:
qiaoxinjiu
2026-05-07 19:43:05 +08:00
parent 916248483c
commit f8211673ee
44 changed files with 10410 additions and 437 deletions

View File

@@ -0,0 +1,815 @@
<template>
<div class="page-wrap">
<page-section :title="isCreate ? '新建 Bug' : '编辑 Bug'">
<template slot="extra">
<el-button size="small" @click="goBack">返回</el-button>
</template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" size="small" class="bug-form">
<el-form-item label="标题" prop="title">
<el-input v-model.trim="form.title" maxlength="200" show-word-limit placeholder="Bug 标题" />
</el-form-item>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="产品" prop="productId">
<el-select v-model="form.productId" filterable placeholder="请选择产品" style="width: 100%;" @change="onProductChange" @focus="loadProductOptions">
<el-option v-for="p in productOptions" :key="p.id" :label="p.name" :value="p.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目" prop="projectId">
<el-select v-model="form.projectId" filterable placeholder="请选择项目" style="width: 100%;" :disabled="!form.productId" @change="onProjectChange">
<el-option v-for="p in projectOptions" :key="p.id" :label="p.name" :value="p.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="模块" prop="moduleId">
<el-select v-model="form.moduleId" filterable placeholder="请选择模块" style="width: 100%;" :disabled="!form.projectId">
<el-option v-for="m in flatModules" :key="m.id" :label="m.name" :value="m.id" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="类型" prop="bugType">
<el-select v-model="form.bugType" placeholder="类型" style="width: 100%;">
<el-option v-for="(label, key) in bugTypeOptions" :key="key" :label="label" :value="Number(key)" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="严重程度" prop="severity">
<el-select v-model="form.severity" placeholder="严重程度" style="width: 100%;">
<el-option v-for="(label, key) in severityOptions" :key="key" :label="label" :value="Number(key)" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="优先级" prop="priority">
<el-select v-model="form.priority" placeholder="优先级" style="width: 100%;">
<el-option v-for="(label, key) in priorityOptions" :key="key" :label="label" :value="Number(key)" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="复现率" prop="reproduceRate">
<el-select v-model="form.reproduceRate" placeholder="请选择复现率" style="width: 100%;">
<el-option v-for="(label, key) in reproduceRateOptions" :key="key" :label="label" :value="Number(key)" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col v-if="!isCreate" :span="8">
<el-form-item label="状态">
<el-select v-model="form.status" clearable placeholder="状态" style="width: 100%;">
<el-option v-for="(label, key) in statusOptions" :key="key" :label="label" :value="Number(key)" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="isCreate ? 12 : 8">
<el-form-item label="创建人" prop="reporterId">
<el-input
v-if="isCreate"
class="bug-creator-readonly"
:value="defaultCreatorDisplayName"
readonly
placeholder="当前登录用户"
style="width: 100%;" />
<el-select
v-else
ref="reporterSelect"
v-model="form.reporterId"
filterable
placeholder="请先选择项目"
style="width: 100%;"
popper-class="bug-editor-reporter-members"
:disabled="!form.projectId"
@visible-change="onReporterDropdownVisible">
<el-option v-for="u in reporterMemberOptions" :key="'r-' + u.id" :label="u.name" :value="u.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="isCreate ? 12 : 8">
<el-form-item label="当前指派" prop="assigneeId">
<el-select
ref="assigneeSelect"
v-model="form.assigneeId"
filterable
placeholder="请选择当前指派"
style="width: 100%;"
popper-class="bug-editor-assignee-members"
:disabled="!form.projectId"
@visible-change="onAssigneeDropdownVisible">
<el-option v-for="u in assigneeMemberOptions" :key="'a-' + u.id" :label="u.name" :value="u.id" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="环境">
<el-input v-model.trim="form.environment" maxlength="64" placeholder="如 st / pre" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="关联用例">
<el-input v-model="form.caseId" placeholder="选填,用例 ID" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="关联计划">
<el-input v-model="form.planId" placeholder="选填,计划 ID" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="复现步骤">
<bug-steps-rich-editor :key="stepsEditorKey" v-model="form.steps" />
</el-form-item>
<el-form-item>
<el-button @click="goBack">取消</el-button>
<el-button type="primary" :loading="saving" @click="submit">{{ isCreate ? '创建' : '保存' }}</el-button>
</el-form-item>
</el-form>
</page-section>
</div>
</template>
<script>
import PageSection from '@/components/TestPlatform/common/PageSection'
import BugStepsRichEditor from '@/components/Bug/BugStepsRichEditor.vue'
import { getBugDetail, createBug, updateBug } from '@/api/bugApi'
import { recordBugHistory, recordBugEditDiff, buildBugEditBaseline } from '@/utils/bugHistory'
import { legacyStepsToEditorHtml, BUG_STEPS_DEFAULT_HTML } from '@/utils/bugStepsFormat'
import { getProductList } from '@/api/productApi'
import { getProjectList, getProjectMembers } from '@/api/projectApi'
import { getModuleTree } from '@/api/caseApi'
import { BUG_TYPE_MAP, SEVERITY_MAP, PRIORITY_MAP, STATUS_MAP, REPRODUCE_RATE_MAP } from '@/utils/bugMaps'
export default {
name: 'BugEditor',
components: { PageSection, BugStepsRichEditor },
data() {
return {
saving: false,
bugId: '',
/** 新建页复制带入后递增,用于富文本编辑器 key 强制刷新 */
editorNonce: 0,
productOptions: [],
projectOptions: [],
moduleTree: [],
memberPageSize: 10,
reporterMemberOptions: [],
reporterMemberPageNo: 0,
reporterMemberNoMore: false,
reporterMemberLoading: false,
assigneeMemberOptions: [],
assigneeMemberPageNo: 0,
assigneeMemberNoMore: false,
assigneeMemberLoading: false,
assigneeExtraLabel: '',
editBaseline: null,
form: {
title: '',
bugType: 1,
severity: 2,
priority: 2,
status: '',
productId: '',
projectId: '',
moduleId: '',
caseId: '',
planId: '',
environment: '',
steps: BUG_STEPS_DEFAULT_HTML,
reporterId: '',
assigneeId: '',
reproduceRate: 1
},
rules: {
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
reproduceRate: [{ required: true, message: '请选择复现率', trigger: 'change' }],
productId: [{ required: true, message: '请选择产品', trigger: 'change' }],
projectId: [{ required: true, message: '请选择项目', trigger: 'change' }],
moduleId: [{ required: true, message: '请选择模块', trigger: 'change' }],
assigneeId: [{ required: true, message: '请选择当前指派', trigger: 'change' }],
reporterId: [
{
required: true,
validator: (rule, value, callback) => {
if (this.isCreate) {
const uid = this.defaultReporterId()
if (uid === '' || uid === undefined || uid === null) {
callback(new Error('未获取到当前登录用户,请重新登录'))
} else {
callback()
}
return
}
if (value === '' || value === undefined || value === null) {
callback(new Error('请选择创建人'))
} else {
callback()
}
},
trigger: 'change'
}
]
}
}
},
computed: {
isCreate() {
return (this.$route.path || '').indexOf('/bug/create') !== -1
},
bugTypeOptions() {
return BUG_TYPE_MAP
},
severityOptions() {
return SEVERITY_MAP
},
priorityOptions() {
return PRIORITY_MAP
},
statusOptions() {
return STATUS_MAP
},
reproduceRateOptions() {
return REPRODUCE_RATE_MAP
},
flatModules() {
const out = []
const walk = (nodes, prefix) => {
;(nodes || []).forEach(n => {
const name = prefix ? `${prefix} / ${n.name}` : n.name
out.push({ id: n.id, name })
const ch = n.children || n.child_list || n.childList || []
if (ch.length) walk(ch, name)
})
}
walk(this.moduleTree, '')
return out
},
stepsEditorKey() {
if (this.isCreate) {
return 'create-' + String(this.editorNonce)
}
return 'edit-' + String(this.bugId || '0')
},
currentUser() {
return this.$store.state.currentUser
},
/** 新建页展示:优先 real_name接口字段与 store 中 realName 一致 */
defaultCreatorDisplayName() {
const u = this.currentUser
if (!u) return '-'
return u.real_name || u.realName || u.username || '-'
}
},
watch: {
'$route.query.bugId'(v) {
this.bugId = v || ''
if (!this.isCreate) this.loadDetail()
},
isCreate(val) {
if (val) {
if (this.$route.query.copyFrom) return
this.form.steps = BUG_STEPS_DEFAULT_HTML
this.form.reporterId = this.defaultReporterId()
this.form.reproduceRate = 1
this.form.assigneeId = ''
this.assigneeExtraLabel = ''
this.resetReporterMembers()
this.resetAssigneeMembers()
}
},
'$route.query.copyFrom': {
handler(v) {
if (!this.isCreate || !v) return
this.loadProductOptions().then(() => this.applyCopyFromDetail(v))
},
immediate: true
}
},
destroyed() {
this.unbindReporterMemberScroll()
this.unbindAssigneeMemberScroll()
},
methods: {
defaultReporterId() {
const u = this.currentUser
return u && u.id != null && u.id !== '' ? u.id : ''
},
mapMemberRows(list) {
const arr = Array.isArray(list) ? list : []
return arr
.map(item => ({
id: item.user_id || item.userId || item.id,
name:
item.real_name ||
item.realName ||
item.username ||
item.name ||
item.user_name ||
String(item.user_id || item.id)
}))
.filter(u => u.id !== undefined && u.id !== null)
},
ensureCurrentUserInMemberOptions(opts) {
const u = this.currentUser
if (!u || u.id == null || u.id === '') return opts || []
const list = opts || []
if (list.some(m => String(m.id) === String(u.id))) return list
const label = u.realName || u.username || '当前用户'
return [{ id: u.id, name: label }, ...list]
},
applyDefaultReporterIfNeeded() {
if (!this.isCreate) return
const uid = this.defaultReporterId()
const inList = id =>
id !== '' && id !== undefined && id !== null &&
this.reporterMemberOptions.some(m => String(m.id) === String(id))
if (!uid) return
if (!this.form.reporterId || !inList(this.form.reporterId)) {
if (inList(uid)) this.form.reporterId = uid
}
},
mergeMemberById(existing, incoming) {
const base = (existing || []).slice()
const seen = new Set(base.map(x => String(x.id)))
;(incoming || []).forEach(x => {
if (x.id === undefined || x.id === null) return
const k = String(x.id)
if (!seen.has(k)) {
seen.add(k)
base.push(x)
}
})
return base
},
resetReporterMembers() {
this.reporterMemberOptions = []
this.reporterMemberPageNo = 0
this.reporterMemberNoMore = false
},
resetAssigneeMembers() {
this.assigneeMemberOptions = []
this.assigneeMemberPageNo = 0
this.assigneeMemberNoMore = false
},
fetchReporterMemberPage(append) {
const pid = this.form.projectId
if (!pid || this.reporterMemberLoading) return Promise.resolve()
if (append && this.reporterMemberNoMore) return Promise.resolve()
const nextPage = append ? this.reporterMemberPageNo + 1 : 1
if (!append) {
this.resetReporterMembers()
}
this.reporterMemberLoading = true
return getProjectMembers(pid, { pageNo: nextPage, pageSize: this.memberPageSize })
.then(res => {
const data = (res && res.data) || res || {}
const raw = data.items || data.list || data.data || []
const rows = this.mapMemberRows(Array.isArray(raw) ? raw : [])
if (append) {
this.reporterMemberOptions = this.mergeMemberById(this.reporterMemberOptions, rows)
} else {
this.reporterMemberOptions = this.ensureCurrentUserInMemberOptions(rows)
}
this.reporterMemberPageNo = nextPage
this.reporterMemberNoMore = rows.length < this.memberPageSize
})
.catch(() => {
if (!append) {
this.reporterMemberOptions = this.ensureCurrentUserInMemberOptions([])
}
this.reporterMemberNoMore = true
})
.finally(() => {
this.reporterMemberLoading = false
})
.then(() => {
this.applyDefaultReporterIfNeeded()
})
},
fetchAssigneeMemberPage(append) {
const pid = this.form.projectId
if (!pid || this.assigneeMemberLoading) return Promise.resolve()
if (append && this.assigneeMemberNoMore) return Promise.resolve()
const nextPage = append ? this.assigneeMemberPageNo + 1 : 1
if (!append) {
this.resetAssigneeMembers()
}
this.assigneeMemberLoading = true
return getProjectMembers(pid, { pageNo: nextPage, pageSize: this.memberPageSize })
.then(res => {
const data = (res && res.data) || res || {}
const raw = data.items || data.list || data.data || []
const rows = this.mapMemberRows(Array.isArray(raw) ? raw : [])
if (append) {
this.assigneeMemberOptions = this.mergeMemberById(this.assigneeMemberOptions, rows)
} else {
this.assigneeMemberOptions = rows.slice()
}
this.assigneeMemberPageNo = nextPage
this.assigneeMemberNoMore = rows.length < this.memberPageSize
this.ensureAssigneeInOptions()
})
.catch(() => {
if (!append) this.assigneeMemberOptions = []
this.assigneeMemberNoMore = true
})
.finally(() => {
this.assigneeMemberLoading = false
})
},
ensureAssigneeInOptions() {
const id = this.form.assigneeId
if (id === '' || id === undefined || id === null) return
if (this.assigneeMemberOptions.some(m => String(m.id) === String(id))) return
const name = this.assigneeExtraLabel || `用户 ${id}`
this.assigneeMemberOptions = [{ id, name }, ...this.assigneeMemberOptions]
},
getMemberDropdownScrollWrap(popperClass) {
const pop = document.querySelector(`.${popperClass}`)
if (!pop) return null
return pop.querySelector('.el-select-dropdown__wrap') || pop.querySelector('.el-scrollbar__wrap')
},
unbindReporterMemberScroll() {
if (this._reporterScrollEl && this._reporterScrollHandler) {
this._reporterScrollEl.removeEventListener('scroll', this._reporterScrollHandler)
}
this._reporterScrollEl = null
this._reporterScrollHandler = null
},
unbindAssigneeMemberScroll() {
if (this._assigneeScrollEl && this._assigneeScrollHandler) {
this._assigneeScrollEl.removeEventListener('scroll', this._assigneeScrollHandler)
}
this._assigneeScrollEl = null
this._assigneeScrollHandler = null
},
bindReporterMemberScroll() {
this.unbindReporterMemberScroll()
this.$nextTick(() => {
const el = this.getMemberDropdownScrollWrap('bug-editor-reporter-members')
if (!el) return
this._reporterScrollEl = el
this._reporterScrollHandler = this.onReporterMemberDropdownScroll.bind(this)
el.addEventListener('scroll', this._reporterScrollHandler, { passive: true })
})
},
bindAssigneeMemberScroll() {
this.unbindAssigneeMemberScroll()
this.$nextTick(() => {
const el = this.getMemberDropdownScrollWrap('bug-editor-assignee-members')
if (!el) return
this._assigneeScrollEl = el
this._assigneeScrollHandler = this.onAssigneeMemberDropdownScroll.bind(this)
el.addEventListener('scroll', this._assigneeScrollHandler, { passive: true })
})
},
onReporterMemberDropdownScroll(e) {
const el = e.target
if (this.reporterMemberLoading || this.reporterMemberNoMore) return
if (el.scrollHeight - el.scrollTop - el.clientHeight < 40) {
this.fetchReporterMemberPage(true)
}
},
onAssigneeMemberDropdownScroll(e) {
const el = e.target
if (this.assigneeMemberLoading || this.assigneeMemberNoMore) return
if (el.scrollHeight - el.scrollTop - el.clientHeight < 40) {
this.fetchAssigneeMemberPage(true)
}
},
onReporterDropdownVisible(visible) {
if (!visible) {
this.unbindReporterMemberScroll()
return
}
if (!this.form.projectId) return
const load = !this.reporterMemberOptions.length
? this.fetchReporterMemberPage(false)
: Promise.resolve()
load.finally(() => {
this.$nextTick(() => this.bindReporterMemberScroll())
})
},
onAssigneeDropdownVisible(visible) {
if (!visible) {
this.unbindAssigneeMemberScroll()
return
}
if (!this.form.projectId) return
const load = !this.assigneeMemberOptions.length
? this.fetchAssigneeMemberPage(false)
: Promise.resolve()
load.finally(() => {
this.$nextTick(() => this.bindAssigneeMemberScroll())
})
},
loadProjectMembersForForm(projectId) {
if (!projectId) {
this.resetReporterMembers()
this.resetAssigneeMembers()
return Promise.resolve()
}
if (this.isCreate) {
this.resetReporterMembers()
return this.fetchAssigneeMemberPage(false)
}
return Promise.all([
this.fetchReporterMemberPage(false),
this.fetchAssigneeMemberPage(false)
])
},
loadProductOptions() {
if (this.productOptions.length) return Promise.resolve()
return getProductList({ pageNo: 1, pageSize: 1000, status: 1 }).then(res => {
const data = (res && res.data) || res || {}
this.productOptions = data.items || data.list || data.data || []
}).catch(() => { this.productOptions = [] })
},
loadProjects(productId) {
if (!productId) {
this.projectOptions = []
return Promise.resolve()
}
return getProjectList({ pageNo: 1, pageSize: 1000, status: 1, productId }).then(res => {
const data = (res && res.data) || res || {}
this.projectOptions = data.items || data.list || data.data || []
}).catch(() => { this.projectOptions = [] })
},
loadModules(projectId) {
if (!projectId) {
this.moduleTree = []
return Promise.resolve()
}
return getModuleTree({ projectId, pageNo: 1, pageSize: 1000 }).then(res => {
const data = (res && res.data) || res || {}
this.moduleTree = data.list || data.items || []
}).catch(() => { this.moduleTree = [] })
},
onProductChange(val) {
this.form.projectId = ''
this.form.moduleId = ''
this.form.assigneeId = ''
this.form.reporterId = this.defaultReporterId()
this.moduleTree = []
this.assigneeExtraLabel = ''
this.resetReporterMembers()
this.resetAssigneeMembers()
this.loadProjects(val)
},
onProjectChange(val) {
this.form.moduleId = ''
this.form.assigneeId = ''
this.assigneeExtraLabel = ''
this.loadModules(val)
this.loadProjectMembersForForm(val)
},
applyCopyTitle(raw) {
const t = String(raw || '').trim()
const suffix = '(复制)'
if (!t) return suffix
if (t.indexOf(suffix) !== -1) {
return t.length > 200 ? t.slice(0, 200) : t
}
const combined = t + suffix
if (combined.length <= 200) return combined
return t.slice(0, Math.max(0, 200 - suffix.length)) + suffix
},
applyCopyFromDetail(sourceBugId) {
const sid = String(sourceBugId || '').trim()
if (!sid) return Promise.resolve()
return getBugDetail(sid)
.then(res => {
const d = (res && res.data) || res || {}
this.assigneeExtraLabel =
d.assignee_real_name ||
d.assigneeRealName ||
d.assignee_name ||
d.assigneeName ||
d.assignee_username ||
d.assigneeUsername ||
''
const rawSteps =
d.steps || d.reproduce_steps || d.reproduceSteps || d.reproduction_steps || d.reproductionSteps || ''
this.form = {
title: this.applyCopyTitle(d.title || ''),
bugType: d.bug_type != null ? d.bug_type : d.bugType != null ? d.bugType : 1,
severity: d.severity != null ? d.severity : 2,
priority: d.priority != null ? d.priority : 2,
status: '',
productId: d.product_id || d.productId || '',
projectId: d.project_id || d.projectId || '',
moduleId: d.module_id || d.moduleId || '',
caseId: d.case_id != null && d.case_id !== '' ? d.case_id : d.caseId != null && d.caseId !== '' ? d.caseId : '',
planId: d.plan_id != null && d.plan_id !== '' ? d.plan_id : d.planId != null && d.planId !== '' ? d.planId : '',
environment: d.environment || '',
steps: legacyStepsToEditorHtml(rawSteps),
reporterId: this.defaultReporterId(),
assigneeId: d.assignee_id || d.assigneeId || '',
reproduceRate:
d.reproduce_rate != null && d.reproduce_rate !== ''
? Number(d.reproduce_rate)
: d.reproduceRate != null && d.reproduceRate !== ''
? Number(d.reproduceRate)
: 1
}
if (this.form.productId) this.loadProjects(this.form.productId)
if (this.form.projectId) {
this.loadModules(this.form.projectId)
this.loadProjectMembersForForm(this.form.projectId)
}
this.editorNonce = (this.editorNonce || 0) + 1
this.bugId = ''
this.editBaseline = null
this.$nextTick(() => {
if (this.$refs.formRef) this.$refs.formRef.clearValidate()
})
this.$message.success('已带入原 Bug 内容,请确认后创建')
})
.then(() => this.$router.replace({ path: '/bug/create', query: {} }).catch(() => {}))
.catch(() => {
this.$message.error('复制失败:无法加载原 Bug 详情')
})
},
loadDetail() {
if (!this.bugId) return
getBugDetail(this.bugId).then(res => {
const d = (res && res.data) || res || {}
this.assigneeExtraLabel =
d.assignee_real_name ||
d.assigneeRealName ||
d.assignee_name ||
d.assigneeName ||
d.assignee_username ||
d.assigneeUsername ||
''
const rawSteps =
d.steps || d.reproduce_steps || d.reproduceSteps || d.reproduction_steps || d.reproductionSteps || ''
this.form = {
title: d.title || '',
bugType: d.bug_type != null ? d.bug_type : (d.bugType != null ? d.bugType : 1),
severity: d.severity != null ? d.severity : 2,
priority: d.priority != null ? d.priority : 2,
status: d.status != null ? d.status : '',
productId: d.product_id || d.productId || '',
projectId: d.project_id || d.projectId || '',
moduleId: d.module_id || d.moduleId || '',
caseId: d.case_id || d.caseId || '',
planId: d.plan_id || d.planId || '',
environment: d.environment || '',
steps: legacyStepsToEditorHtml(rawSteps),
reporterId:
d.reporter_id ||
d.reporterId ||
d.creator_id ||
d.creatorId ||
d.created_by ||
d.createdBy ||
'',
assigneeId: d.assignee_id || d.assigneeId || '',
reproduceRate:
d.reproduce_rate != null && d.reproduce_rate !== ''
? Number(d.reproduce_rate)
: d.reproduceRate != null && d.reproduceRate !== ''
? Number(d.reproduceRate)
: 1
}
if (this.form.productId) this.loadProjects(this.form.productId)
if (this.form.projectId) {
this.loadModules(this.form.projectId)
this.loadProjectMembersForForm(this.form.projectId)
}
this.$nextTick(() => {
this.editBaseline = buildBugEditBaseline(this.form)
})
}).catch(() => {})
},
clean(obj) {
const o = {}
Object.keys(obj).forEach(k => {
const v = obj[k]
if (v !== '' && v !== undefined && v !== null) o[k] = v
})
return o
},
submit() {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.saving = true
if (this.isCreate) {
const payload = this.clean({
title: this.form.title,
bugType: this.form.bugType,
severity: this.form.severity,
priority: this.form.priority,
productId: this.form.productId,
projectId: this.form.projectId,
moduleId: this.form.moduleId,
caseId: this.form.caseId,
planId: this.form.planId,
environment: this.form.environment,
steps: this.form.steps,
reporterId: this.form.reporterId,
assigneeId: this.form.assigneeId,
reproduceRate: this.form.reproduceRate
})
payload.description = ''
createBug(payload).then(res => {
const data = (res && res.data) || {}
this.$message.success('创建成功')
const id = data.id
if (id) {
recordBugHistory(this.$store, {
bugId: id,
fieldName: 'create',
oldValue: '',
newValue: '1'
})
this.$router.replace({ path: '/bug/detail', query: { bugId: id } })
} else {
this.$router.push({ path: '/bug/list' })
}
}).finally(() => { this.saving = false })
} else {
const payload = this.clean({
bugId: Number(this.bugId),
id: Number(this.bugId),
title: this.form.title,
bugType: this.form.bugType,
severity: this.form.severity,
priority: this.form.priority,
status: this.form.status,
reporterId: this.form.reporterId,
assigneeId: this.form.assigneeId,
moduleId: this.form.moduleId,
caseId: this.form.caseId,
planId: this.form.planId,
environment: this.form.environment,
steps: this.form.steps,
reproduceRate: this.form.reproduceRate
})
payload.description = ''
updateBug(payload)
.then(() =>
recordBugEditDiff(
this.$store,
Number(this.bugId),
this.editBaseline,
buildBugEditBaseline(this.form)
)
)
.then(() => {
this.$message.success('保存成功')
this.$router.push({ path: '/bug/detail', query: { bugId: this.bugId } })
})
.finally(() => {
this.saving = false
})
}
})
},
goBack() {
if (this.isCreate) {
this.$router.push({ path: '/bug/list' })
} else {
this.$router.push({ path: '/bug/detail', query: { bugId: this.bugId } })
}
}
},
created() {
this.bugId = this.$route.query.bugId || ''
if (this.isCreate) {
this.form.reporterId = this.defaultReporterId()
}
if (!this.isCreate) {
this.loadProductOptions().then(() => this.loadDetail())
} else if (!this.$route.query.copyFrom) {
this.loadProductOptions()
}
}
}
</script>
<style scoped>
.page-wrap {
padding: 20px;
}
.bug-form {
max-width: 960px;
}
.bug-creator-readonly >>> .el-input__inner {
cursor: default;
color: #606266;
background-color: #f5f7fa;
}
</style>