新增汇总页-问题单详情

This commit is contained in:
2025-12-23 10:36:04 +08:00
parent 92783045ef
commit ec972fac8e
20 changed files with 849 additions and 69 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "testplant",
"version": "0.0.6",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "testplant",
"version": "0.0.6",
"version": "0.1.0",
"dependencies": {
"@arco-design/color": "^0.4.0",
"@arco-design/web-vue": "^2.57.0",
@@ -32,7 +32,7 @@
"vue": "^3.5.26",
"vue-clipboard3": "^2.0.0",
"vue-color-kit": "^1.0.6",
"vue-data-ui": "^3.9.6",
"vue-data-ui": "^3.9.12",
"vue-router": "^4.6.4",
"vuedraggable": "^2.24.3"
},
@@ -5469,9 +5469,9 @@
}
},
"node_modules/vue-data-ui": {
"version": "3.9.6",
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-3.9.6.tgz",
"integrity": "sha512-XpIqONAc6xYAWvjiR8snVTIjETbZUdxw2gV2vrHnwA71yXMS3Mso2MO+aE9mNhsUI7LThzOPtjylA+vniKANzQ==",
"version": "3.9.12",
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-3.9.12.tgz",
"integrity": "sha512-0gNNA9DJw9q9/o4KrK+tesZHHtUxMB6x1JhiGhILU6VS3J/kb+pXC/BQaOqmjK512xzDyE05SGCR5UkHTSNPpQ==",
"license": "MIT",
"peerDependencies": {
"jspdf": "^3.0.1",

View File

@@ -35,7 +35,7 @@
"vue": "^3.5.26",
"vue-clipboard3": "^2.0.0",
"vue-color-kit": "^1.0.6",
"vue-data-ui": "^3.9.6",
"vue-data-ui": "^3.9.12",
"vue-router": "^4.6.4",
"vuedraggable": "^2.24.3"
},

View File

@@ -136,7 +136,7 @@ export default {
* 批量替换事件
* @returns
*/
exetimeReplace(data = { selectRows: [], exetime: "" }) {
exetimeReplace(data = { selectRows: [], exetime: [] }) {
return request({
url: "/project/case/timeReplace/",
method: "post",

View File

@@ -120,5 +120,16 @@ export default {
method: "get",
params
})
},
/**
* 复制到当前dut下面CRUD中操作列
* @returns
*/
copy_current(params = {}) {
return request({
url: "/project/copy_current",
method: "get",
params
})
}
}

View File

@@ -36,15 +36,15 @@ export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${(td[round_key] as any).title} > ${(td[round_key] as any).children[dut_key].title} >设计需求[${record.name}]-`
return true
},
afterAdd: (res) => {
afterAdd: (res: any) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterEdit: (res) => {
afterEdit: (res: any) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterDelete: (res, record) => {
afterDelete: (_: any, record: any) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
@@ -62,12 +62,12 @@ export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
rowSelection: { showCheckedAll: true },
searchColNumber: 4,
tablePagination: false,
operationColumnWidth: 250,
operationColumnWidth: 300,
operationColumn: true,
operationColumnAlign: "center",
formOption: {
width: 1200
},
}
})
return crudOptions
}

View File

@@ -31,6 +31,10 @@
<!-- 字段的前缀后缀的插槽 -->
<!-- 版本字段的插槽 -->
<template #inputPrepend-ident> SJ-XX- </template>
<!-- 操作列前置插槽 -->
<template #operationBeforeExtend="{ record }">
<a-link @click="handleCopyCurrentNode($event, record)" :loading="copyLoading"><icon-copy />复制当前</a-link>
</template>
</ma-crud>
</div>
<file-input-modal ref="fileInputRef" @enterFinish="crudRef.refresh()"></file-input-modal>
@@ -59,6 +63,7 @@
<script setup>
import { ref } from "vue"
import { useTreeDataStore } from "@/store"
import useCrudOptions from "@/views/project/dut/hooks/useCrudOptions"
import useColumns from "./hooks/useColumns"
import { Message } from "@arco-design/web-vue"
@@ -75,6 +80,7 @@ import BatchCaseCreate from "@/views/project/components/BatchCaseCreate/index.vu
const route = useRoute()
const crudRef = ref()
const projectId = ref(route.query.id)
const treeDataStore = useTreeDataStore()
// 5月28日新增功能替换
const replaceModal = ref()
@@ -143,6 +149,23 @@ const handleBatchCaseCreate = () => {
batchCreateCaseRef.value.open({})
}
// 复制设计需求到当前dut
const copyLoading = ref(false)
const handleCopyCurrentNode = async (_, record) => {
copyLoading.value = true
try {
await designApi.copy_current({ dut_id: record.dut.id, design_id: record.id })
// 复制成功给提示
Message.success("复制成功!")
refreshCrudTable()
treeDataStore.updateDesignDemandTreeData({ key: record.key }, projectId.value)
} catch (e) {
console.log("复制失败,后台打印错误:", e)
} finally {
copyLoading.value = false
}
}
const refreshCrudTable = () => {
crudRef.value.refresh()
}

View File

@@ -8,13 +8,15 @@
import DesignTable from "../components/DesignTable/index.vue"
import DemandTable from "../components/DemandTable/index.vue"
import CaseTable from "../components/CaseTable/index.vue"
import ProblemTable from "../components/ProblemTable/index.vue"
/* 导入columns看能不能行 */
// useColumns使用对应关系
const mapColumn = {
design: DesignTable,
demand: DemandTable,
case: CaseTable
case: CaseTable,
problem: ProblemTable
}
// props
const { type } = defineProps<{
@@ -25,7 +27,7 @@ const { type } = defineProps<{
</script>
<style lang="less" scoped>
.pro-table-container{
.pro-table-container {
padding: 5px;
}
</style>

View File

@@ -1,20 +1,12 @@
<template>
<!-- 注意该组件强制绑定caseTable页面不要使用在其他地方了 -->
<div class="replace-person-container">
<a-modal
v-model:visible="visible"
width="40%"
unmount-on-close
ok-text="替换执行时间"
cancel-text="关闭"
draggable
:on-before-ok="submitReplace"
>
<a-modal v-model:visible="visible" width="40%" unmount-on-close ok-text="替换执行时间" cancel-text="关闭" draggable :on-before-ok="submitReplace">
<template #title>替换执行时间</template>
<div class="content-container">
<a-form ref="exeTime" :model="formData" scroll-to-first-error>
<a-form-item field="exetime" label="执行时间">
<a-date-picker v-model="exetime" style="width: 200px" />
<a-range-picker v-model="exetime" style="width: 400px" :shortcuts="shortcuts" />
</a-form-item>
</a-form>
</div>
@@ -26,10 +18,12 @@
import { ref } from "vue"
import { Message } from "@arco-design/web-vue"
import caseApi from "@/api/project/case"
import { isEmpty } from "lodash-es"
import dayjs from "dayjs"
const visible = ref(false)
const formData = ref({})
const exetime = ref("")
const exetime = ref<string[]>([])
const getSelectedsFunc = ref<any>(() => [])
// props
@@ -41,7 +35,7 @@ const emit = defineEmits(["modifySuccess"])
// 2.异步执行替换操作返回boolean-true则关闭弹窗
const submitReplace = async () => {
// 不再非受控验证,手动验证
if (exetime.value === "") {
if (isEmpty(exetime.value)) {
Message.error("请选择时间后,进行替换操作")
return false
}
@@ -49,22 +43,42 @@ const submitReplace = async () => {
if (selecteds.length && selecteds.length > 0) {
// 判断是否选择了行
// 请求后台执行
await caseApi.exetimeReplace({
selectRows: selecteds,
exetime: exetime.value
})
emit("modifySuccess")
Message.success("批量替换成功...")
return true
try {
await caseApi.exetimeReplace({
selectRows: selecteds,
exetime: exetime.value as any
})
emit("modifySuccess")
Message.success("批量替换成功...")
return true
} catch (e) {
return false
}
}
Message.error("请在表格中选择行...")
return false
}
// 给时间范围选择器的快捷选择数组
const shortcuts = [
{
label: "后六天",
value: () => [dayjs(), dayjs().add(6, "day")]
},
{
label: "前六天",
value: () => [dayjs(), dayjs().subtract(6, "day")]
},
{
label: "前后各一周",
value: () => [dayjs().subtract(7, "day"), dayjs().add(7, "day")]
}
]
// 其他打开modal
const open = (getFunc: (() => number[]) | undefined) => {
if (getFunc) getSelectedsFunc.value = getFunc
exetime.value = ""
exetime.value = []
visible.value = true
}
defineExpose({ open })

View File

@@ -3,11 +3,7 @@
<search v-show="searchVisible" @submit="searchSubmit" />
<div class="lg:flex justify-between mb-2">
<a-space>
<a-popconfirm
content="确定要删除数据吗? 这会删除全部下级数据!"
position="bottom"
@ok="deletesMultipleAction"
>
<a-popconfirm content="确定要删除数据吗? 这会删除全部下级数据!" position="bottom" @ok="deletesMultipleAction">
<a-button type="primary" status="danger">
批量删除
<template #icon><icon-delete /></template>
@@ -164,7 +160,8 @@ const columns = ref([
hide: false,
ellipsis: true,
search: true,
formType: "input"
formType: "input",
fixed: ""
},
{
title: "名称",
@@ -174,7 +171,8 @@ const columns = ref([
hide: false,
ellipsis: true,
search: true,
formType: "input"
formType: "input",
fixed: ""
},
{
title: "用例综述",
@@ -186,7 +184,8 @@ const columns = ref([
search: false, // 不搜索
formType: "input", // 搜索输入框形式
isHyperText: false,
bodyCellClass: "hyperTextCell-table-chen"
bodyCellClass: "hyperTextCell-table-chen",
fixed: ""
},
{
// 这是单独处理的字段只声明Search组件相关属性
@@ -198,16 +197,14 @@ const columns = ref([
ellipsis: false,
search: false, // 要搜索
formType: "input", // 搜索输入框形式
bodyCellClass: "hyperTextCell-table-chen"
bodyCellClass: "hyperTextCell-table-chen",
fixed: ""
}
])
provide("columns", columns)
// 3.query查询和分页相关
const { tableData, isFetching, fetchData, total, pageChange, pageSizeChange, searchParams } = useFetchData(
caseApi.getCaseList,
columns
)
const { tableData, isFetching, fetchData, total, pageChange, pageSizeChange, searchParams } = useFetchData(caseApi.getCaseList, columns)
// 4.表单相关
const formRef = ref<InstanceType<typeof Form> | null>(null)

View File

@@ -163,7 +163,8 @@ const columns = ref([
hide: false,
ellipsis: true,
search: true,
formType: "input"
formType: "input",
fixed: ""
},
{
title: "名称",
@@ -173,7 +174,8 @@ const columns = ref([
hide: false,
ellipsis: true,
search: true,
formType: "input"
formType: "input",
fixed: ""
},
{
title: "优先级",
@@ -188,7 +190,8 @@ const columns = ref([
// 只是指明a-table-column渲染v-if
showType: (text: string) => {
return text
}
},
fixed: ""
},
{
title: "测试类型",
@@ -202,7 +205,8 @@ const columns = ref([
dict: true,
showType: (text: string) => {
return text
}
},
fixed: ""
},
{
title: "测项描述",
@@ -214,7 +218,8 @@ const columns = ref([
search: false, // 不搜索
formType: "input", // 搜索输入框形式
isHyperText: false,
bodyCellClass: "hyperTextCell-table-chen"
bodyCellClass: "hyperTextCell-table-chen",
fixed: ""
},
{
// 这是单独处理的字段只声明Search组件相关属性
@@ -226,7 +231,8 @@ const columns = ref([
ellipsis: false,
search: false, // 要搜索
formType: "input", // 搜索输入框形式
bodyCellClass: "hyperTextCell-table-chen"
bodyCellClass: "hyperTextCell-table-chen",
fixed: ""
}
])
provide("columns", columns)

View File

@@ -3,11 +3,7 @@
<search v-show="searchVisible" @submit="searchSubmit" />
<div class="lg:flex justify-between mb-2">
<a-space>
<a-popconfirm
content="确定要删除数据吗? 这会删除全部下级数据!"
position="bottom"
@ok="deletesMultipleAction"
>
<a-popconfirm content="确定要删除数据吗? 这会删除全部下级数据!" position="bottom" @ok="deletesMultipleAction">
<a-button type="primary" status="danger">
批量删除
<template #icon><icon-delete /></template>
@@ -140,7 +136,8 @@ const columns = ref([
hide: false,
ellipsis: true,
search: true,
formType: "input"
formType: "input",
fixed: ""
},
{
title: "标识",
@@ -150,7 +147,8 @@ const columns = ref([
hide: false,
ellipsis: true,
search: true,
formType: "input"
formType: "input",
fixed: ""
},
{
title: "章节号",
@@ -160,7 +158,8 @@ const columns = ref([
hide: false,
ellipsis: true,
search: true,
formType: "input"
formType: "input",
fixed: ""
},
{
title: "类型",
@@ -174,7 +173,8 @@ const columns = ref([
showType: (text: string) => {
return text
},
dict: true
dict: true,
fixed: ""
},
{
title: "需求描述",
@@ -185,7 +185,8 @@ const columns = ref([
formType: "input",
// 设置内容单元格样式-注意作用与<td>
bodyCellClass: "hyperTextCell-table-chen",
isHyperText: true
isHyperText: true,
fixed: ""
}
])
provide("columns", columns)
@@ -194,10 +195,7 @@ provide("columns", columns)
const showType = useShowType("demandType")
// 3.query查询和分页相关
const { tableData, isFetching, fetchData, total, pageChange, pageSizeChange, searchParams } = useFetchData(
designApi.getDesignDemandList,
columns
)
const { tableData, isFetching, fetchData, total, pageChange, pageSizeChange, searchParams } = useFetchData(designApi.getDesignDemandList, columns)
// 4.表单相关
const formRef = ref<InstanceType<typeof Form> | null>(null)

View File

@@ -20,3 +20,8 @@ export interface ISearchFormDemand {
export interface ISearchFormCase {
}
// 问题单搜索字段
export interface ISearchFormProblem {
}

View File

@@ -0,0 +1,71 @@
<template>
<div class="problem-form-container">
<a-modal
width="60%"
draggable
unmount-on-close
ok-text="确认修改"
cancel-text="关闭"
v-model:visible="visible"
title="修改问题单"
:on-before-ok="handleSubmit"
>
<ma-form v-model="formData" :columns="columns" :options="options" ref="formRef">
<template #form-ident> PT_{{ route.query.ident }}_{{ formData["ident"] }} </template>
</ma-form>
</a-modal>
</div>
</template>
<script setup lang="ts">
import useFormColumns from "./formHooks/useFormColumns"
import { ref } from "vue"
import MaForm from "@/components/ma-form/index.vue"
import problemApi from "@/api/project/problem"
import { useRoute } from "vue-router"
import { Message } from "@arco-design/web-vue"
const visible = ref(false)
const formRef = ref<InstanceType<typeof MaForm> | null>(null)
const route = useRoute()
// form数据
const project_id = route.query.id
const formData = ref<any>({})
const emit = defineEmits(["updateProblem"])
// modal提交按钮
const handleSubmit = async () => {
const isValidated = await formRef.value!.validateForm()
if (isValidated) {
return false
}
try {
await problemApi.update(formData.value.id, { project_id, ...formData.value })
emit("updateProblem")
Message.success("修改成功")
formData.value = {} // 清除已有数据,防止卡顿
} catch {
return false
}
}
// options
const options = ref({
showButtons: false,
labelAlign: "center"
})
// columns
const { columns } = useFormColumns()
const open = (record: any) => {
visible.value = true
formData.value = record
}
defineExpose({ open })
</script>
<style scoped></style>

View File

@@ -0,0 +1,347 @@
import { useRoute } from "vue-router"
import { useUserStore } from "@/store"
export default function () {
const route = useRoute()
const userStore = useUserStore()
const columns = [
{
title: "id",
dataIndex: "id",
display: false
},
{
formType: "grid",
customClass: ["mt-0"],
cols: [
{
span: 12,
formList: [
{
title: "名称",
align: "left",
search: true,
dataIndex: "name",
rules: [{ required: true, message: "名称是必填" }],
validateTrigger: "blur-sm"
}
]
},
{
span: 12,
formList: [
{
title: "问题标识",
align: "center",
width: 140,
search: true,
disabled: true,
dataIndex: "ident",
validateTrigger: "blur-sm"
}
]
}
]
},
{
formType: "grid",
customClass: ["ml-4"],
cols: [
{
span: 12,
formList: [
{
title: "缺陷状态",
align: "center",
width: 80,
search: true,
dataIndex: "status",
formType: "radio",
rules: [{ required: true, message: "缺陷状态是必填" }],
dict: {
name: "problemStatu",
translation: true,
props: { label: "title", value: "key" },
tagColors: { 1: "green", 2: "blue", 3: "#FF7D00", 4: "red" }
}
}
]
},
{
span: 12,
formList: [
{
title: "闭环方式",
align: "center",
width: 200,
dataIndex: "closeMethod",
search: true,
formType: "checkbox",
dict: {
name: "closeMethod",
translation: true,
props: { label: "title", value: "key" }
}
}
]
}
]
},
{
formType: "grid",
customClass: ["ml-4"],
cols: [
{
span: 12,
formList: [
{
title: "缺陷等级",
align: "center",
width: 80,
dataIndex: "grade",
search: true,
formType: "radio",
rules: [{ required: true, message: "缺陷等级必填" }],
dict: {
name: "problemGrade",
translation: true,
props: { label: "title", value: "key" }
}
}
]
},
{
span: 12,
formList: [
{
title: "缺陷类型",
align: "center",
width: 80,
dataIndex: "type",
search: true,
formType: "radio",
rules: [{ required: true, message: "缺陷类型必选" }],
dict: {
name: "problemType",
translation: true,
props: { label: "title", value: "key" }
}
}
]
}
]
},
{
formType: "divider"
},
{
formType: "grid",
cols: [
{
span: 24,
formList: [
{
title: "问题描述",
hide: true,
search: true,
align: "center",
dataIndex: "operation",
formType: "editor"
}
]
}
]
},
{
formType: "grid",
cols: [
{
span: 24,
formList: [
{
title: "问题影响",
hide: true,
align: "center",
dataIndex: "result",
formType: "textarea"
}
]
}
]
},
{
formType: "divider"
},
{
formType: "grid",
cols: [
{
span: 24,
formList: [
{
title: "原因分析",
hide: true,
align: "center",
dataIndex: "analysis",
formType: "textarea"
}
]
}
]
},
{
formType: "grid",
cols: [
{
span: 24,
formList: [
{
title: "影响域分析",
hide: true,
align: "center",
dataIndex: "effect_scope",
formType: "textarea"
}
]
}
]
},
{
formType: "grid",
cols: [
{
span: 24,
formList: [
{
title: "改正措施",
hide: true,
align: "center",
dataIndex: "solve",
formType: "textarea"
}
]
}
]
},
{
formType: "divider"
},
{
formType: "grid",
cols: [
{
span: 24,
formList: [
{
title: "回归结果",
hide: true,
align: "center",
dataIndex: "verify_result",
formType: "editor"
}
]
}
]
},
{
formType: "divider",
title: "人员信息"
},
{
formType: "grid",
cols: [
{
span: 12,
formList: [
{
title: "测试人员",
dataIndex: "postPerson",
search: true,
align: "center",
formType: "select",
rules: [{ required: true, message: "测试人员必填" }],
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
}
]
},
{
span: 12,
formList: [
{
title: "测试日期",
hide: true,
dataIndex: "postDate",
formType: "date"
}
]
}
]
},
{
formType: "grid",
cols: [
{
span: 12,
formList: [
{
title: "开发人员",
hide: true,
dataIndex: "designerPerson",
formType: "input"
}
]
},
{
span: 12,
formList: [
{
title: "开发方日期",
hide: true,
dataIndex: "designDate",
formType: "date"
}
]
}
]
},
{
formType: "grid",
cols: [
{
span: 12,
formList: [
{
title: "回归人员",
hide: true,
dataIndex: "verifyPerson",
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
}
]
},
{
span: 12,
formList: [
{
title: "回归日期",
hide: true,
dataIndex: "verifyDate",
formType: "date"
}
]
}
]
}
]
return { columns }
}

View File

@@ -0,0 +1,57 @@
import { ref } from "vue"
export default function () {
const columns = ref([
{
title: "名称",
dataIndex: "name",
slotName: "name",
align: "left",
hide: false,
width: 250,
fixed: ""
},
{
title: "问题标识",
dataIndex: "ident",
slotName: "ident",
align: "center",
hide: false,
width: 150,
fixed: ""
},
{
title: "缺陷状态",
dataIndex: "problemStatu",
slotName: "problemStatu",
align: "center",
hide: false,
width: 100,
fixed: "",
formType: "select",
dict: true
},
{
title: "缺陷等级",
dataIndex: "problemGrade",
slotName: "problemGrade",
align: "center",
hide: false,
width: 100,
fixed: "",
formType: "select",
dict: true
},
{
title: "问题描述",
dataIndex: "operation",
slotName: "operation",
align: "left",
hide: false,
isHyperText: true,
fixed: ""
}
])
return { columns }
}

View File

@@ -0,0 +1,35 @@
import { computed, ref } from "vue"
import dictApi from "@/api/system/dict"
import { Message } from "@arco-design/web-vue"
export default function () {
const loading = ref(false)
const originOption = ref([])
const gradeOptions = computed(() => {
return Object.fromEntries(originOption.value.map(({ title, key }) => [key, title]))
})
// 请求字典中测试手段数据
const fetchDictData = async () => {
try {
const res = await dictApi.getDictByCode({ code: "problemGrade" })
originOption.value = res.data
loading.value = true
} catch (e) {
Message.error("获取测试手段选项失败,请关闭后重新打开!")
} finally {
loading.value = false
}
}
// 一个工具函数
const changeGradeColor = (status: "1" | "2" | "3" | "4") => {
const colorDict = {
"1": "blue",
"2": "orange",
"3": "green",
"4": "red"
}
return colorDict[status]
}
fetchDictData()
return { fetchDictData, loading, gradeOptions, changeGradeColor }
}

View File

@@ -0,0 +1,39 @@
import { computed, ref } from "vue"
import dictApi from "@/api/system/dict"
import { Message } from "@arco-design/web-vue"
export default function () {
const loading = ref(false)
const originOption = ref([])
const problemStatus = computed(() => {
return Object.fromEntries(originOption.value.map(({ title, key }) => [key, title]))
})
// 请求字典中测试手段数据
const fetchDictData = async () => {
try {
const res = await dictApi.getDictByCode({ code: "problemStatu" })
originOption.value = res.data
loading.value = true
} catch (e) {
Message.error("获取测试手段选项失败,请关闭后重新打开!")
} finally {
loading.value = false
}
}
// 一个工具函数
const changeColor = (status: "1" | "2" | "3" | "4") => {
const colorDict = {
"1": "green",
"2": "red",
"3": "magenta",
"4": "arcoblue"
}
return colorDict[status]
}
// 在组件挂载请求dict
fetchDictData()
return { fetchDictData, loading, problemStatus, changeColor }
}

View File

@@ -0,0 +1,166 @@
<template>
<div class="problem-table-container">
<search v-show="searchVisible" @submit="searchSubmit" />
<div class="lg:flex justify-between mb-2">
<a-space> </a-space>
<a-space>
<a-space class="lg:mt-0 mt-2">
<slot name="tools"></slot>
<a-tooltip content="刷新表格">
<a-button shape="circle" @click="fetchData()"><icon-refresh /></a-button>
</a-tooltip>
<a-tooltip content="显隐搜索" @click="searchVisible = !searchVisible">
<a-button shape="circle"><icon-search /></a-button>
</a-tooltip>
<a-tooltip content="设置">
<a-button shape="circle" @click="clickSetting"><icon-settings /></a-button>
</a-tooltip>
</a-space>
</a-space>
</div>
<a-table
id="basic-table-problem"
v-bind="options"
hoverable
column-resizable
ref="tableRef"
row-key="id"
:columns="columns"
:loading="isFetching || problemStatusLoading || problemGradeLoading"
:data="tableData"
:scroll="{ x: '100%' }"
:pagination="{
showTotal: true,
showPageSize: true,
total: total,
pageSizeOptions: [10, 20, 50, 1000],
hideOnSinglePage: false
}"
@page-change="pageChange"
@page-size-change="pageSizeChange"
>
<template #columns>
<template v-for="column in columns" :key="column.dataIndex">
<template v-if="!column.hide">
<a-table-column v-bind="column" v-if="column.dataIndex === 'operation'">
<template #cell="{ record }" v-if="column.isHyperText">
<div v-html="record[column.dataIndex]"></div>
</template>
</a-table-column>
<a-table-column v-bind="column" v-else tooltip>
<template #cell="{ record }">
<template v-if="column.dataIndex === 'ident'"> PT_{{ route.query.ident }}_{{ record.ident }} </template>
<template v-else-if="column.dataIndex === 'problemStatu'">
<a-tag :color="changeColor(record.status)">
{{ problemStatus[record.status] }}
</a-tag>
</template>
<template v-else-if="column.dataIndex === 'problemGrade'">
<a-tag :color="changeGradeColor(record.grade)">
{{ gradeOptions[record.grade] }}
</a-tag>
</template>
<template v-else>
{{ record[column.dataIndex] }}
</template>
</template>
</a-table-column>
</template>
</template>
<!-- 所属用例列 -->
<a-table-column title="所属用例" align="center" :width="110" fixed="right">
<template #cell="{ record }">
<a-tag v-if="record.hang" color="red">无关联用例</a-tag>
<a-button v-else color="green" type="primary" @click="seeRelatedCases(record)">
<icon-eye />
</a-button>
</template>
</a-table-column>
<!-- 操作列 -->
<a-table-column title="操作" align="center" :width="120" fixed="right">
<template #cell="{ record }">
<a-link @click="handleOpenProblemModify(record)">
修改
<template #icon>
<icon-edit />
</template>
</a-link>
</template>
</a-table-column>
</template>
</a-table>
<!-- 问题单表单页面 -->
<ProblemForm ref="problemRef" @updateProblem="refresh()" />
<!-- 表格设置 -->
<my-setting ref="settingRef" @onChangeColumnHide="changeColumn"></my-setting>
<case-modal ref="caseModalRef" />
</div>
</template>
<script setup lang="ts">
import { provide, ref } from "vue"
import useColumns from "./hooks/useColumns"
import useFetchData from "@/views/project/opeSets/hooks/useFetchData"
import useSettings from "@/views/project/opeSets/components/DesignTable/useSettings"
import problemApi from "@/api/project/problem"
import { useRoute } from "vue-router"
import useProblemStatu from "./hooks/useProblemStatu"
import useProblemGrade from "./hooks/useProblemGrade"
import problemSingleApi from "@/api/project/singleProblem"
import CaseModal from "@/views/project/case/components/CaseModal.vue"
import MySetting from "@/views/project/opeSets/components/TableCommonComponent/Setting.vue"
import Search from "@/views/project/opeSets/components/DesignTable/Search.vue"
import ProblemForm from "./form.vue"
import type { ISearchFormProblem } from "../DesignTable/types"
const route = useRoute()
const caseModalRef = ref<InstanceType<typeof CaseModal> | null>(null)
const problemRef = ref<InstanceType<typeof ProblemForm> | null>(null)
// 加载初始字典数据
const { loading: problemStatusLoading, problemStatus, changeColor } = useProblemStatu()
const { loading: problemGradeLoading, gradeOptions, changeGradeColor } = useProblemGrade()
// 定义表格列
const { columns } = useColumns()
provide("columns", columns)
// 请求初始数据钩子
const { tableData, isFetching, fetchData, total, pageChange, pageSizeChange, searchParams } = useFetchData(problemApi.searchAllProblem, columns)
// 查看关联用例
const seeRelatedCases = async (record: any) => {
const problemId = record.id
const res = await problemSingleApi.getRelativeCases({ id: problemId })
caseModalRef.value && caseModalRef.value.open(res.data)
}
// 表格设置相关
const { options, clickSetting, changeColumn, settingRef } = useSettings()
// 搜索相关内容
const searchVisible = ref(true)
const searchSubmit = (data: ISearchFormProblem) => {
searchParams.value = { ...data }
fetchData(true)
}
// 点击修改
const handleOpenProblemModify = (record: any) => {
problemRef.value?.open(record)
}
// 刷新表格显示
const refresh = () => {
fetchData()
}
</script>
<style scoped>
.max-height-class {
max-height: 300px;
overflow-y: auto;
white-space: normal;
word-break: break-all;
}
</style>

View File

@@ -14,6 +14,9 @@
<a-tab-pane key="case" title="测试用例">
<ProTable type="case"></ProTable>
</a-tab-pane>
<a-tab-pane key="problem" title="本轮问题单">
<ProTable type="problem"></ProTable>
</a-tab-pane>
</a-tabs>
</div>
</div>

View File

@@ -1,9 +1,12 @@
import { ref } from "vue"
import { useRoute } from "vue-router"
import tool from "@/utils/tool"
export default function (crudOrFormRef: any, problemFormRef?: any) {
const title = ref("问题单表单")
const route = useRoute()
// 固定是否为FPGA
const isFPGA = !tool.checkForCpuOrFPGA(route.query.plant_type)
const crudColumns = ref([
{
title: "ID",
@@ -154,7 +157,10 @@ export default function (crudOrFormRef: any, problemFormRef?: any) {
hide: true,
dataIndex: "timing_diagram",
addDefaultValue: "",
formType: "editor"
formType: "editor",
display: !isFPGA,
editDisplay: !isFPGA,
addDisplay: !isFPGA
},
{
title: "测试步骤",