双击详情完成

This commit is contained in:
2024-12-30 09:50:38 +08:00
parent 2bd0de8c17
commit 0ad404d3e8
29 changed files with 1469 additions and 1076 deletions

View File

@@ -0,0 +1,70 @@
import { defineComponent } from "vue"
import { TreeNodeData } from "@arco-design/web-vue"
import { useTreeDataStore } from "@/store"
import testDemandAPI from "@/api/project/testDemand"
import useOptions from "./useOptions"
import subFormHooks from "@/views/project/projPublicHooks/subFormHooks"
const DemandSubForm = defineComponent({
name: "DemandSubFormForm",
setup(_, { expose }) {
// hook variable
const treeDataStore = useTreeDataStore()
const { title, formData, formRef, modalOptions, project_id, visible } = subFormHooks(
testDemandAPI.update,
treeDataStore.updateTestDemandTreeData,
"80%"
)
// hooks
const { options, columnOptions } = useOptions(formRef) // **option里面变化**
// 双击打开回调
const open = async (nodeData: TreeNodeData) => {
// 请求数据
try {
const key = nodeData.key as string
// 设置表单名称
title.value = nodeData.title!
const res = await testDemandAPI.getTestDemandOne({ project_id, key }) // **API变化**
// 更新表单
formData.value = res.data // **属性变化**
formData.value.round = key.split("-")[0]
formData.value.dut = key.split("-")[1]
formData.value.designDemand = key.split("-")[2]
visible.value = true
} catch (e) {
visible.value = false
}
}
// out use
expose({ open })
// Dom
return () => (
// 注意v-model:visible是不能放在对象解构的
<a-modal {...modalOptions} v-model:visible={visible.value}>
{{
title: () => <span>[]-{title.value}</span>,
default: () => (
<ma-form
ref={formRef}
v-model={formData.value}
options={options.value}
columns={columnOptions.value}
>
{{
"inputPrepend-ident": () => <span>XQ_XX_</span>
}}
</ma-form>
)
}}
</a-modal>
)
}
})
export default DemandSubForm
// 组件类型导出
type DemandSubFormOrigin = InstanceType<typeof DemandSubForm>
export interface DemandSubFormInstance extends DemandSubFormOrigin {
open(nodeData: TreeNodeData): void
}

View File

@@ -0,0 +1,16 @@
import { ref, computed } from "vue"
import tool from "@/utils/tool"
import useColumn from "../hooks/useColumns"
// demand在这里设置不同ma-form选项
export default function useOptions(formRef: any) {
const options = ref({
showButtons: false,
labelAlign: "center"
})
const crudColumns = useColumn(formRef)
const columnOptions = computed(() => {
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
})
return { options, columnOptions }
}

View File

@@ -0,0 +1,145 @@
import { ref } from "vue"
import PinYinMatch from "pinyin-match"
export default function (crudOrFormRef: any) {
const crudColumns = ref([
{
title: "ID",
align: "center",
hide: true,
dataIndex: "id",
display: false
},
{
title: "测项标识",
width: 150,
dataIndex: "ident",
sortable: { sortDirections: ["ascend"] },
align: "center",
search: true,
validateTrigger: "blur",
placeholder: "请填写测试项的标识,注意标识不能重复",
commonRules: [{ required: true, message: "测试项标识必填" }],
openPrepend: true
},
{
title: "名称",
dataIndex: "name",
width: 120,
align: "center",
search: true,
commonRules: [{ required: true, message: "名称是必填" }],
validateTrigger: "blur"
},
{
title: "优先级",
dataIndex: "priority",
search: true,
formType: "radio",
align: "center",
addDefaultValue: "1",
dict: {
name: "priority",
props: { label: "title", value: "key" },
translation: true,
tagColors: { 1: "red", 2: "blue", 3: "green" }
}
},
{
title: "测试类型",
dataIndex: "testType",
search: true,
align: "center",
formType: "select",
sortable: { sortDirections: ["ascend", "descend"] },
addDefaultValue: "4",
maxLength: 200,
commonRules: [{ required: true, message: "测试类型必选" }],
dict: { name: "testType", translation: true, props: { label: "title", value: "key" } },
extra: "支持拼音搜索例如gn可以搜索出功能测试",
// 这是arco的属性所以在ma-crud和ma-form可以直接使用arco属性和事件事件+onXXX
filterOption: function (inputValue, selectedOption) {
if (inputValue) {
let matchRes = PinYinMatch.match(selectedOption.label, inputValue)
if (matchRes) {
return true
}
}
}
},
{
title: "测试手段",
align: "center",
dataIndex: "testMethod",
formType: "select",
multiple: true,
dict: { name: "testMethod", props: { label: "title", value: "key" }, translation: true }
},
{
title: "充分性要求",
hide: true,
dataIndex: "adequacy",
formType: "textarea",
maxLength: 256,
commonRules: [{ required: true, message: "充分性描述必填" }],
addDefaultValue:
"测试用例覆盖XX子项名称1、XX子项名称2、XX子项名称3子项要求的全部内容。\n所有用例执行完毕对于未执行的用例说明未执行原因。"
},
{
title: "测试子项",
hide: true,
dataIndex: "testContent",
commonRules: [{ required: true, message: "测试方法是必填的" }],
formType: "children-form",
formList: [
{
title: "子项名称",
dataIndex: "subName",
placeholder: "对应测试项描述标题,和测试方法的标题",
rules: [{ required: true, message: "测试子项名称必填" }],
onChange: (ev) => {
// 取出子项的对象数组
const subItemFormData = crudOrFormRef.value.getFormData().testContent
// 取出充分性条件字段字符串
const mapRes = subItemFormData.map((subItem) => subItem.subName)
crudOrFormRef.value.getFormData().adequacy = `测试用例覆盖${mapRes.join(
"、"
)}子项要求的全部内容。\n所有用例执行完毕对于未执行的用例说明未执行原因。`
}
},
{
title: "子项描述",
dataIndex: "subDesc",
formType: "textarea",
placeholder: "对应大纲测试项表格的测试项描述",
rules: [{ required: true, message: "测试子项描述必填" }]
},
{
title: "条件",
dataIndex: "condition",
formType: "textarea",
placeholder: "在什么环境和前置条件下"
},
{
title: "操作",
dataIndex: "operation",
formType: "textarea",
placeholder: "通过xxx操作"
},
{
title: "观察",
dataIndex: "observe",
formType: "textarea",
placeholder: "查看xxx内容"
},
{
title: "期望",
dataIndex: "expect",
formType: "textarea",
placeholder: "xxx结果正确"
}
]
}
])
return crudColumns
}

View File

@@ -0,0 +1,131 @@
import MaCrud from "@/components/ma-crud/index.vue"
import { type Ref, ref, getCurrentInstance } from "vue"
import testDemandApi from "@/api/project/testDemand"
import { useRoute } from "vue-router"
import { useTreeDataStore } from "@/store"
import { cloneDeep, isEqual } from "lodash-es"
// types
interface ITestContent {
subName: string
subDesc: string
}
/**
* 测试项表格的Crud-options
*/
export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
// global
const treeDataStore = useTreeDataStore()
const route = useRoute() as any
// variable
const roundNumber = (route.query.key as string)!.split("-")[0]
const dutNumber = (route.query.key as string)!.split("-")[1]
const designDemandNumber = (route.query.key as string)!.split("-")[2]
// refs
const projectId = ref(route.query.id)
// 处理弹窗关闭事件:处理用户数据是否保留
const app = getCurrentInstance()!.appContext.config.globalProperties
let beforeFormContent: ITestContent[] | undefined = undefined
const handleBeforeCancel = () => {
if (!beforeFormContent) {
return
}
const iuEqualValue = isEqual(crudRef.value.getFormData().testContent, beforeFormContent)
!iuEqualValue &&
app.$modal.confirm({
title: "测试项步骤内容你已改动,是否保留您编写的测试项/测试用例步骤数据?",
content: "",
okText: "保留",
cancelText: "恢复原数据",
simple: true,
onOk: () => null,
onCancel: () => {
crudRef.value.refresh()
}
})
}
const crudOptions = ref({
api: testDemandApi.getTestDemandList,
add: { show: true, api: testDemandApi.save, text: "新增测试项" },
edit: { show: true, api: testDemandApi.update, text: "修改测试项" },
delete: { show: true, api: testDemandApi.delete },
showTools: false,
beforeOpenAdd: function () {
// 1.新增则将form的content数据变为undifined以便判断
beforeFormContent = undefined
// 2.设置标识
let key_split = (route.query.key as string)!.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > ${td[round_key].children[dut_key].children[design_key].title} > 测试项-`
return true
},
beforeOpenEdit: function (record) {
// 1.储存打开前form的content数据到ref中以便后续比较
beforeFormContent = cloneDeep(record.testContent)
// 2.处理标识
let key_split = (route.query.key as string)!.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > ${td[round_key].children[dut_key].children[design_key].title} >测试项[${record.name}]-`
return true
},
afterAdd: (res: any) => {
let id = projectId.value
treeDataStore.updateTestDemandTreeData(res.data, id)
},
afterEdit: (res: any) => {
let id = projectId.value
treeDataStore.updateTestDemandTreeData(res.data, id)
},
afterDelete: (_: any, record: any) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateTestDemandTreeData(record, id)
// 清空选择
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber,
designDemand: designDemandNumber
},
showIndex: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 200,
operationColumn: true,
operationColumnAlign: "center",
formOption: {
width: 1200,
layout: [
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "ident" }] },
{ span: 12, formList: [{ dataIndex: "name" }] }
]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "priority" }] }]
},
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "testType" }] },
{ span: 12, formList: [{ dataIndex: "testMethod" }] }
]
}
]
}
})
return { projectId, crudOptions, handleBeforeCancel }
}

View File

@@ -1,280 +0,0 @@
import { ref, getCurrentInstance } from "vue"
import PinYinMatch from "pinyin-match"
import { useTreeDataStore } from "@/store"
import { useRoute } from "vue-router"
import testDemandApi from "@/api/project/testDemand"
import { isEqual, cloneDeep } from "lodash-es"
interface ITestContent {
subName: string
subDesc: string
}
/**
* 1.配置crud以及全组件使用变量
* 2.另外包含一个测试项是否保留数据的功能含一个ref以及一个事件处理函数
*/
export default function useCrudRef() {
// global
const treeDataStore = useTreeDataStore()
const route = useRoute()
// variable
const roundNumber = (route.query.key as string)!.split("-")[0]
const dutNumber = (route.query.key as string)!.split("-")[1]
const designDemandNumber = (route.query.key as string)!.split("-")[2]
// refs
const projectId = ref(route.query.id)
const crudRef = ref()
// 处理弹窗关闭事件:处理用户数据是否保留
const app = getCurrentInstance()!.appContext.config.globalProperties
let beforeFormContent: ITestContent[] | undefined = undefined
const handleBeforeCancel = () => {
if (!beforeFormContent) {
return
}
const iuEqualValue = isEqual(crudRef.value.getFormData().testContent, beforeFormContent)
!iuEqualValue &&
app.$modal.confirm({
title: "测试项步骤内容你已改动,是否保留您编写的测试项/测试用例步骤数据?",
content: "",
okText: "保留",
cancelText: "恢复原数据",
simple: true,
onOk: () => null,
onCancel: () => {
crudRef.value.refresh()
}
})
}
// 配置
// crud组件
const crudOptions = ref({
api: testDemandApi.getTestDemandList,
add: { show: true, api: testDemandApi.save, text: "新增测试项" },
edit: { show: true, api: testDemandApi.update, text: "修改测试项" },
delete: { show: true, api: testDemandApi.delete },
showTools: false,
beforeOpenAdd: function () {
// 1.新增则将form的content数据变为undifined以便判断
beforeFormContent = undefined
// 2.设置标识
let key_split = (route.query.key as string)!.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > ${td[round_key].children[dut_key].children[design_key].title} > 测试项-`
return true
},
beforeOpenEdit: function (record) {
// 1.储存打开前form的content数据到ref中以便后续比较
beforeFormContent = cloneDeep(record.testContent)
// 2.处理标识
let key_split = (route.query.key as string)!.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > ${td[round_key].children[dut_key].children[design_key].title} >测试项[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateTestDemandTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateTestDemandTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateTestDemandTreeData(record, id)
// 清空选择
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber,
designDemand: designDemandNumber
},
showIndex: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 200,
operationColumn: true,
operationColumnAlign: "center",
formOption: {
width: 1200,
layout: [
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "ident" }] },
{ span: 12, formList: [{ dataIndex: "name" }] }
]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "priority" }] }]
},
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "testType" }] },
{ span: 12, formList: [{ dataIndex: "testMethod" }] }
]
}
]
}
})
const crudColumns = ref([
{
title: "ID",
align: "center",
hide: true,
dataIndex: "id"
},
{
title: "测项标识",
width: 150,
dataIndex: "ident",
sortable: { sortDirections: ["ascend"] },
align: "center",
search: true,
validateTrigger: "blur",
placeholder: "请填写测试项的标识,注意标识不能重复",
commonRules: [{ required: true, message: "测试项标识必填" }],
openPrepend: true
},
{
title: "名称",
dataIndex: "name",
width: 120,
align: "center",
search: true,
commonRules: [{ required: true, message: "名称是必填" }],
validateTrigger: "blur"
},
{
title: "优先级",
dataIndex: "priority",
search: true,
formType: "radio",
align: "center",
addDefaultValue: "1",
dict: {
name: "priority",
props: { label: "title", value: "key" },
translation: true,
tagColors: { 1: "red", 2: "blue", 3: "green" }
}
},
{
title: "测试类型",
dataIndex: "testType",
search: true,
align: "center",
formType: "select",
sortable: { sortDirections: ["ascend", "descend"] },
addDefaultValue: "4",
maxLength: 200,
commonRules: [{ required: true, message: "测试类型必选" }],
dict: { name: "testType", translation: true, props: { label: "title", value: "key" } },
extra: "支持拼音搜索例如gn可以搜索出功能测试",
// 这是arco的属性所以在ma-crud和ma-form可以直接使用arco属性和事件事件+onXXX
filterOption: function (inputValue, selectedOption) {
if (inputValue) {
let matchRes = PinYinMatch.match(selectedOption.label, inputValue)
if (matchRes) {
return true
}
}
}
},
{
title: "测试手段",
align: "center",
dataIndex: "testMethod",
formType: "select",
multiple: true,
dict: { name: "testMethod", props: { label: "title", value: "key" }, translation: true }
},
{
title: "充分性要求",
hide: true,
dataIndex: "adequacy",
formType: "textarea",
maxLength: 256,
commonRules: [{ required: true, message: "充分性描述必填" }],
addDefaultValue:
"测试用例覆盖XX子项名称1、XX子项名称2、XX子项名称3子项要求的全部内容。\n所有用例执行完毕对于未执行的用例说明未执行原因。"
},
{
title: "测试子项",
hide: true,
dataIndex: "testContent",
commonRules: [{ required: true, message: "测试方法是必填的" }],
formType: "children-form",
formList: [
{
title: "子项名称",
dataIndex: "subName",
placeholder: "对应测试项描述标题,和测试方法的标题",
rules: [{ required: true, message: "测试子项名称必填" }],
onChange: (ev) => {
// 取出子项的对象数组
const subItemFormData = crudRef.value.getFormData().testContent
// 取出充分性条件字段字符串
const mapRes = subItemFormData.map((subItem) => subItem.subName)
crudRef.value.getFormData().adequacy = `测试用例覆盖${mapRes.join(
"、"
)}子项要求的全部内容。\n所有用例执行完毕对于未执行的用例说明未执行原因。`
}
},
{
title: "子项描述",
dataIndex: "subDesc",
formType: "textarea",
placeholder: "对应大纲测试项表格的测试项描述",
rules: [{ required: true, message: "测试子项描述必填" }]
},
{
title: "条件",
dataIndex: "condition",
formType: "textarea",
placeholder: "在什么环境和前置条件下"
},
{
title: "操作",
dataIndex: "operation",
formType: "textarea",
placeholder: "通过xxx操作"
},
{
title: "观察",
dataIndex: "observe",
formType: "textarea",
placeholder: "查看xxx内容"
},
{
title: "期望",
dataIndex: "expect",
formType: "textarea",
placeholder: "xxx结果正确"
}
]
}
])
return {
projectId,
crudRef,
crudOptions,
crudColumns,
handleBeforeCancel
}
}

View File

@@ -45,11 +45,14 @@
import { ref } from "vue"
import commonApi from "@/api/common"
// hooks
import useCrudRef from "./hooks/useCrudRef"
import useCrudOpMore from "./hooks/useCrudOpMore"
import useColumn from "./hooks/useColumns"
import useRalateDemand from "./hooks/useRalateDemand"
// refs
const crudRef = ref(null)
// 根据传参获取key分别为轮次、设计需求的key
const { projectId, crudRef, crudOptions, crudColumns, handleBeforeCancel } = useCrudRef()
const { projectId, crudOptions, handleBeforeCancel } = useCrudOpMore(crudRef)
const crudColumns = useColumn(crudRef)
// 关联弹窗、关联的事件处理
const { visible, relatedData, options, cascaderLoading, computedRelatedData, handleOpenRelationCSX, handleRelatedOk } =
useRalateDemand(projectId)

View File

@@ -0,0 +1,69 @@
import { defineComponent } from "vue"
import { TreeNodeData } from "@arco-design/web-vue"
import { useTreeDataStore } from "@/store"
import designDemandAPI from "@/api/project/designDemand"
import useOptions from "./useOptions"
import subFormHooks from "@/views/project/projPublicHooks/subFormHooks"
const DesignSubForm = defineComponent({
name: "DesignSubForm",
setup(_, { expose }) {
// hook variable
const treeDataStore = useTreeDataStore()
const { title, formData, formRef, modalOptions, project_id, visible } = subFormHooks(
designDemandAPI.update,
treeDataStore.updateDesignDemandTreeData,
"80%"
)
// hooks
const { options, columnOptions } = useOptions(formRef) // **option里面变化**
// 双击打开回调
const open = async (nodeData: TreeNodeData) => {
// 请求数据
try {
const key = nodeData.key as string
// 设置表单名称
title.value = nodeData.title!
const res = await designDemandAPI.getDesignDemandOne({ project_id, key }) // **API变化**
// 更新表单
formData.value = res.data // **属性变化**
formData.value.round = key.split("-")[0]
formData.value.dut = key.split("-")[1]
visible.value = true
} catch (e) {
visible.value = false
}
}
// out use
expose({ open })
// Dom
return () => (
// 注意v-model:visible是不能放在对象解构的
<a-modal {...modalOptions} v-model:visible={visible.value}>
{{
title: () => <span>[]-{title.value}</span>,
default: () => (
<ma-form
ref={formRef}
v-model={formData.value}
options={options.value}
columns={columnOptions.value}
>
{{
"inputPrepend-ident": () => <span>SJ-XX-</span>
}}
</ma-form>
)
}}
</a-modal>
)
}
})
export default DesignSubForm
// 组件类型导出
type DesignSubFormOrigin = InstanceType<typeof DesignSubForm>
export interface DesignSubFormInstance extends DesignSubFormOrigin {
open(nodeData: TreeNodeData): void
}

View File

@@ -0,0 +1,16 @@
import { ref, computed } from "vue"
import tool from "@/utils/tool"
import useColumn from "../hooks/useColumns"
// 设置不同ma-form选项
export default function useOptions(formRef: any) {
const options = ref({
showButtons: false,
labelAlign: "center"
})
const crudColumns = useColumn(formRef)
const columnOptions = computed(() => {
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
})
return { options, columnOptions }
}

View File

@@ -0,0 +1,119 @@
import { ref } from "vue"
export default function (crudOrFormRef: any) {
const crudColumns = ref([
{
title: "ID",
align: "center",
width: 50,
hide: true,
dataIndex: "id",
commonRules: [{ required: true, message: "ID必填" }],
validateTrigger: "blur",
display: false
},
{
title: "设需标识",
align: "center",
sortable: { sortDirections: ["ascend"] },
width: 180,
dataIndex: "ident",
search: true,
validateTrigger: "blur",
placeholder: "请输入文档中设计需求的标识",
help: '若不知道则填"无"或不填',
openPrepend: true
},
{
title: "设需名称",
align: "center",
width: 200,
dataIndex: "name",
search: true,
commonRules: [{ required: true, message: "设计需求名称是必填" }],
validateTrigger: "blur"
},
{
title: "章节号",
align: "center",
width: 150,
dataIndex: "chapter",
search: true,
help: '若为隐含需求则填"/"'
},
{
title: "需求类型",
width: 150,
align: "center",
dataIndex: "demandType",
addDefaultValue: "1",
formType: "radio",
search: true,
dict: { name: "demandType", props: { label: "title", value: "key" }, translation: true },
commonRules: [{ required: true, message: "需求类型是必填" }],
validateTrigger: "blur",
// 主要为了添加“接口”的4个字段
onControl: (value) => {
if (value === "3") {
return {
source: { display: true },
to: { display: true },
type: { display: true },
protocal: { display: true }
}
} else {
return {
source: { display: false },
to: { display: false },
type: { display: false },
protocal: { display: false }
}
}
}
},
{
formType: "grid-tailwind",
customClass: [],
colNumber: 2,
cols: [
{
formList: [
{
title: "接口来源",
dataIndex: "source",
hide: true
},
{
title: "目的地",
dataIndex: "to",
hide: true
}
]
},
{
formList: [
{
title: "接口类型",
dataIndex: "type",
hide: true
},
{
title: "接口内容",
dataIndex: "protocal",
hide: true
}
]
}
]
},
{
title: "需求描述",
dataIndex: "description",
hide: true,
width: 300,
formType: "editor",
height: 300
}
])
return crudColumns
}

View File

@@ -0,0 +1,74 @@
import MaCrud from "@/components/ma-crud/index.vue"
import { type Ref, ref } from "vue"
import designDemandApi from "@/api/project/designDemand"
import { useRoute } from "vue-router"
import { useTreeDataStore } from "@/store"
/**
* Dut被测件的crud选项
*/
export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
// globals
const route = useRoute() as any
const projectId = ref(route.query.id)
const treeDataStore = useTreeDataStore()
const roundNumber = (route.query.key as any).split("-")[0]
const dutNumber = (route.query.key as any).split("-")[1]
// refs
const crudOptions = ref({
api: designDemandApi.getDesignDemandList,
add: { show: true, api: designDemandApi.save, text: "新增设计需求" },
edit: { show: true, api: designDemandApi.editDesignDemand, text: "编辑设计需求" },
delete: { show: true, api: designDemandApi.delete },
// 处理添加后函数
beforeOpenAdd: function () {
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${(td[round_key] as any).title} > ${(td[round_key] as any).children[dut_key].title} > 设计需求-`
return true
},
beforeOpenEdit: function (record) {
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let td = treeDataStore.treeData
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) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateDesignDemandTreeData(record, id)
// 删除后情况行选择器
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber
},
showIndex: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 4,
tablePagination: false,
operationColumnWidth: 250,
operationColumn: true,
operationColumnAlign: "center",
formOption: {
width: 1200
},
showTools: false
})
return crudOptions
}

View File

@@ -25,21 +25,18 @@
<script setup lang="jsx">
import { ref } from "vue"
import useCrudOptions from "@/views/project/dut/hooks/useCrudOptions"
import useColumns from "./hooks/useColumns"
import { useRoute } from "vue-router"
import designDemandApi from "@/api/project/designDemand"
import dutApi from "@/api/project/dut"
import commonApi from "@/api/common"
import { useTreeDataStore } from "@/store"
import FileInputModal from "./components/FileInputModal/index.vue"
const treeDataStore = useTreeDataStore()
const route = useRoute()
const crudRef = ref()
const roundNumber = route.query.key.split("-")[0]
const dutNumber = route.query.key.split("-")[1]
const projectId = ref(route.query.id)
// 5月8日修改设计需求标识就按SJ-FT-设计需求标识来
const demandTypeDict = ref([])
!(function () {
;(function () {
commonApi.getDict("demandType").then((res) => {
demandTypeDict.value = res
})
@@ -63,175 +60,8 @@ const showType = (record) => {
}
}
// crud组件
const crudOptions = ref({
api: designDemandApi.getDesignDemandList,
add: { show: true, api: designDemandApi.save, text: "新增设计需求" },
edit: { show: true, api: designDemandApi.editDesignDemand, text: "编辑设计需求" },
delete: { show: true, api: designDemandApi.delete },
// 处理添加后函数
beforeOpenAdd: function () {
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > 设计需求-`
return true
},
beforeOpenEdit: function (record) {
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} >设计需求[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateDesignDemandTreeData(record, id)
// 删除后情况行选择器
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber
},
showIndex: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 4,
tablePagination: false,
operationColumnWidth: 250,
operationColumn: true,
operationColumnAlign: "center",
formOption: {
width: 1200
},
showTools: false
})
const crudColumns = ref([
{
title: "ID",
align: "center",
width: 50,
hide: true,
dataIndex: "id",
commonRules: [{ required: true, message: "ID必填" }],
validateTrigger: "blur"
},
{
title: "设需标识",
align: "center",
sortable: { sortDirections: ["ascend"] },
width: 180,
dataIndex: "ident",
search: true,
validateTrigger: "blur",
placeholder: "请输入文档中设计需求的标识",
help: '若不知道则填"无"或不填',
openPrepend: true
},
{
title: "设需名称",
align: "center",
width: 200,
dataIndex: "name",
search: true,
commonRules: [{ required: true, message: "设计需求名称是必填" }],
validateTrigger: "blur"
},
{
title: "章节号",
align: "center",
width: 150,
dataIndex: "chapter",
search: true,
help: '若为隐含需求则填"/"'
},
{
title: "需求类型",
width: 150,
align: "center",
dataIndex: "demandType",
addDefaultValue: "1",
formType: "radio",
search: true,
dict: { name: "demandType", props: { label: "title", value: "key" }, translation: true },
commonRules: [{ required: true, message: "需求类型是必填" }],
validateTrigger: "blur",
// 主要为了添加“接口”的4个字段
onControl: (value) => {
if (value === "3") {
return {
source: { display: true },
to: { display: true },
type: { display: true },
protocal: { display: true }
}
} else {
return {
source: { display: false },
to: { display: false },
type: { display: false },
protocal: { display: false }
}
}
}
},
{
formType: "grid-tailwind",
customClass: [],
colNumber: 2,
cols: [
{
formList: [
{
title: "接口来源",
dataIndex: "source",
hide: true
},
{
title: "目的地",
dataIndex: "to",
hide: true
}
]
},
{
formList: [
{
title: "接口类型",
dataIndex: "type",
hide: true
},
{
title: "接口内容",
dataIndex: "protocal",
hide: true
}
]
}
]
},
{
title: "需求描述",
dataIndex: "description",
hide: true,
width: 300,
formType: "editor",
height: 300
}
])
const crudOptions = useCrudOptions(crudRef)
const crudColumns = useColumns(crudRef)
// ~~~大功能打开ma-form-modal~~~
const fileInputRef = ref(null)
const handleAddFileInputDemand = () => {

View File

@@ -0,0 +1,42 @@
/**
* 该hook为了各个页面双击弹窗SubForm进行公共代码提取
*/
import { ref, inject } from "vue"
import { useRoute } from "vue-router"
import MaForm from "@/components/ma-form/index.vue"
import { Message } from "@arco-design/web-vue"
export default function (updateApiFunc: Function, updateTreeFunc: Function, width = "40%") {
const route = useRoute()
const project_id = route.query.id // 只能拿ID其他是null
const rightViewRef = inject("rightViewRef")
// has returns
const visible = ref(false)
const formRef = ref<InstanceType<typeof MaForm> | null>(null)
const formData = ref<any>({})
// 标题
const title = ref("")
// 异步确认按钮点击
const handleBeforeOk = async () => {
const isValidated = await formRef.value!.validateForm()
if (isValidated) {
// 失败
return false
} else {
// 成功 **变化**
const res = await updateApiFunc(formData.value.id, { project_id, ...formData.value })
updateTreeFunc(res.data, project_id) // 刷新树节点信息
!(rightViewRef as any).value.refresh()
Message.success("修改成功")
}
}
const modalOptions = {
width,
draggable: true,
"unmount-on-close": true,
"ok-text": "保存",
"cancel-text": "关闭",
"on-before-ok": handleBeforeOk
}
return { title, formData, formRef, modalOptions, project_id, visible }
}

View File

@@ -1,28 +1,21 @@
import { defineComponent, inject, ref } from "vue"
import { defineComponent } from "vue"
import { TreeNodeData } from "@arco-design/web-vue"
import { useRoute } from "vue-router"
import { Message } from "@arco-design/web-vue"
import { useTreeDataStore } from "@/store"
import dutAPI from "@/api/project/dut"
import useOptions from "./useOptions"
import MaForm from "@/components/ma-form/index.vue"
import subFormHooks from "../../projPublicHooks/subFormHooks"
const DutSubForm = defineComponent({
name: "DutSubForm",
setup(props, { expose }) {
// globals
const route = useRoute()
const project_id = route.query.id
setup(_, { expose }) {
// hook variable
const treeDataStore = useTreeDataStore()
const rightViewRef = inject("rightViewRef")
// refs
const visible = ref(false)
const formRef = ref<InstanceType<typeof MaForm> | null>(null)
const formData = ref<any>({})
const { title, formData, formRef, modalOptions, project_id, visible } = subFormHooks(
dutAPI.update,
treeDataStore.updateDutTreeData
)
// hooks
const { options, columnOptions } = useOptions(formRef)
// 标题
const title = ref("被测件详情")
const { options, columnOptions } = useOptions(formRef) // **变化**
// 双击打开回调
const open = async (nodeData: TreeNodeData) => {
// 请求数据
@@ -30,43 +23,22 @@ const DutSubForm = defineComponent({
const key = nodeData.key
// 设置表单名称
title.value = nodeData.title!
const res = await dutAPI.getDutOne({ project_id, key })
const res = await dutAPI.getDutOne({ project_id, key }) // **API变化**
// 更新表单
formData.value = res.data
formData.value.round = key
formData.value.round = key // **属性变化**
visible.value = true
} catch (e) {
visible.value = false
}
}
// 异步确认按钮点击
const handleBeforeOk = async () => {
const isValidated = await formRef.value!.validateForm()
if (isValidated) {
// 失败
return false
} else {
// 成功
const res = await dutAPI.update(formData.value.id, { project_id, ...formData.value })
treeDataStore.updateDutTreeData(res.data, project_id) // 刷新树节点信息
!(rightViewRef as any).value.refresh()
Message.success("修改成功")
}
}
// out use
expose({ open })
// Dom
return () => (
<a-modal
v-model:visible={visible.value}
width={"40%"}
draggable
unmount-on-close
ok-text="保存"
cancel-text="关闭"
on-before-ok={handleBeforeOk}
>
// 注意v-model:visible是不能放在对象解构的
<a-modal {...modalOptions} v-model:visible={visible.value}>
{{
title: () => <span>[]-{title.value}</span>,
default: () => (

View File

@@ -1,13 +1,13 @@
import { ref, computed } from "vue"
import useCrudRef from "@/views/project/round/hooks/useCrudRef"
import tool from "@/utils/tool"
import useColumn from "../hooks/useColumn"
export default function useOptions(formRef: any) {
const options = ref({
showButtons: false,
labelAlign: "center"
})
const { crudColumns } = useCrudRef(undefined, formRef)
const crudColumns = useColumn(formRef)
const columnOptions = computed(() => {
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
})

View File

@@ -1,91 +1,18 @@
import { ref } from "vue"
import dutApi from "@/api/project/dut"
import { useRoute } from "vue-router"
import { useTreeDataStore } from "@/store"
import beiceType from "@/views/project/round/beiceType"
/**
* Ref返回其options和columnOptions
* @param crudRef crud组件的Refundefined
* @param formRef ma-form组件Ref
* @returns
*/
export default function useCrudRef(crudRef?, formRef?) {
// globals
export default function (crudOrFormRef: any) {
// global
const route = useRoute()
const projectId = ref(route.query.id)
const treeDataStore = useTreeDataStore()
const roundNumber = (route.query.key as any).split("-")[0]
// 计算注释率计算crud/form的数据判断
const calcPercent = () => {
if (crudRef) {
const formData = crudRef.value.getFormData()
const total_line = +formData.black_line + +formData.code_line + +formData.comment_line + +formData.mix_line
const comment_total = +formData.comment_line + +formData.mix_line
formData.comment_percent = `${(comment_total / total_line).toFixed(2).toString()}%`
} else if (formRef) {
const formData = formRef.value.getFormData()
const { code_line, comment_line, mix_line, black_line } = formData
const total_line = +black_line + +code_line + +comment_line + +mix_line
const comment_total = +comment_line + +mix_line
formData.comment_percent = `${(comment_total / total_line).toFixed(2).toString()}%`
}
const formData = crudOrFormRef.value.getFormData()
const { code_line, comment_line, mix_line, black_line } = formData
const total_line = +black_line + +code_line + +comment_line + +mix_line
const comment_total = +comment_line + +mix_line
formData.comment_percent = `${(comment_total / total_line).toFixed(2).toString()}%`
}
// refs
const crudOptions = ref({
api: dutApi.getDutList,
add: { show: true, api: dutApi.save, text: "新增被测件" },
edit: { show: true, api: dutApi.update, text: "编辑被测件" },
delete: { show: true, api: dutApi.delete },
// 处理添加后函数
beforeOpenAdd: function () {
let round_str = parseInt(route.query.key as any) + 1
crudRef.value.crudFormRef.actionTitle = `${route.query.ident}>第${round_str}轮>被测件-`
return true
},
beforeOpenEdit: function (record) {
let round_str = parseInt(route.query.key as any) + 1
crudRef.value.crudFormRef.actionTitle = `${route.query.ident}>第${round_str}轮>被测件[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateDutTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateDutTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateDutTreeData(record, id)
// 清空行选择器
crudRef.value.tableRef.selectAll(false)
},
// 新增、编辑、删除均携带下面
parameters: {
projectId: route.query.id,
round: roundNumber
},
operationWidth: 500,
showIndex: false,
showTools: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 200, // 操作列宽度
operationColumn: true,
operationColumnAlign: "center",
formOption: {
viewType: "drawer",
width: 600,
mask: false
}
})
const crudColumns = ref([
{
title: "ID",
@@ -251,11 +178,9 @@ export default function useCrudRef(crudRef?, formRef?) {
placeholder: "计算注释率",
hide: true,
addDisabled: true,
editDisabled: true
editDisabled: true,
disabled: true
}
])
return {
crudOptions,
crudColumns
}
return crudColumns
}

View File

@@ -0,0 +1,71 @@
import MaCrud from "@/components/ma-crud/index.vue"
import { type Ref, ref } from "vue"
import dutApi from "@/api/project/dut"
import { useRoute } from "vue-router"
import { useTreeDataStore } from "@/store"
/**
* Dut被测件的crud选项
*/
export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
// globals
const route = useRoute()
const projectId = ref(route.query.id)
const treeDataStore = useTreeDataStore()
const roundNumber = (route.query.key as any).split("-")[0]
// refs
const crudOptions = {
api: dutApi.getDutList,
add: { show: true, api: dutApi.save, text: "新增被测件" },
edit: { show: true, api: dutApi.update, text: "编辑被测件" },
delete: { show: true, api: dutApi.delete },
// 处理添加后函数
beforeOpenAdd: function () {
let round_str = parseInt(route.query.key as any) + 1
crudRef.value.crudFormRef.actionTitle = `${route.query.ident}>第${round_str}轮>被测件-`
return true
},
beforeOpenEdit: function (record) {
let round_str = parseInt(route.query.key as any) + 1
crudRef.value.crudFormRef.actionTitle = `${route.query.ident}>第${round_str}轮>被测件[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateDutTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateDutTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateDutTreeData(record, id)
// 清空行选择器
crudRef.value.tableRef.selectAll(false)
},
// 新增、编辑、删除均携带下面
parameters: {
projectId: route.query.id,
round: roundNumber
},
operationWidth: 500,
showIndex: false,
showTools: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 200, // 操作列宽度
operationColumn: true,
operationColumnAlign: "center",
formOption: {
viewType: "drawer",
width: 600,
mask: false
}
}
return crudOptions
}

View File

@@ -12,10 +12,12 @@
<script setup lang="jsx">
import { ref } from "vue"
import useCrudRef from "@/views/project/round/hooks/useCrudRef"
import useCrudOptions from "@/views/project/round/hooks/useCrudOptions"
import useColumn from "@/views/project/round/hooks/useColumn"
const crudRef = ref()
// crud组件
const { crudOptions, crudColumns } = useCrudRef(crudRef)
const crudOptions = useCrudOptions(crudRef)
const crudColumns = useColumn(crudRef)
const refreshCrudTable = () => {
crudRef.value.refresh()

View File

@@ -0,0 +1,69 @@
import { defineComponent } from "vue"
import { Message, TreeNodeData } from "@arco-design/web-vue"
import { useTreeDataStore } from "@/store"
import caseApi from "@/api/project/case"
import useOptions from "./useOptions"
import subFormHooks from "@/views/project/projPublicHooks/subFormHooks"
const CaseSubForm = defineComponent({
name: "DemandSubFormForm",
setup(_, { expose }) {
// hook variable
const treeDataStore = useTreeDataStore()
const { title, formData, formRef, modalOptions, project_id, visible } = subFormHooks(
caseApi.update,
treeDataStore.updateCaseTreeData,
"80%"
)
// hooks
const { options, columnOptions } = useOptions(formRef) // **option里面变化**
// 双击打开回调
const open = async (nodeData: TreeNodeData) => {
// 请求数据
try {
const key = nodeData.key as string
// 设置表单名称
title.value = nodeData.title!
// 注意这里因为case接口原因这里需要projectId!!!!!!!!!!!!!!!
const res = await caseApi.getCaseOne({ projectId: project_id, key }) // **API变化**
// 更新表单
formData.value = res.data // **属性变化**
formData.value.round = key.split("-")[0]
formData.value.dut = key.split("-")[1]
formData.value.designDemand = key.split("-")[2]
formData.value.testDemand = key.split("-")[3]
visible.value = true
} catch (e) {
Message.error("数据未获取到,请联系开发者")
visible.value = false
}
}
// out use
expose({ open })
// Dom
return () => (
// 注意v-model:visible是不能放在对象解构的
<a-modal {...modalOptions} v-model:visible={visible.value}>
{{
title: () => <span>[]-{title.value}</span>,
default: () => (
<ma-form
ref={formRef}
v-model={formData.value}
options={options.value}
columns={columnOptions.value}
></ma-form>
)
}}
</a-modal>
)
}
})
export default CaseSubForm
// 组件类型导出
type CaseSubFormOrigin = InstanceType<typeof CaseSubForm>
export interface CaseSubFormInstance extends CaseSubFormOrigin {
open(nodeData: TreeNodeData): void
}

View File

@@ -0,0 +1,16 @@
import { ref, computed } from "vue"
import tool from "@/utils/tool"
import useColumn from "../hooks/useColumn"
// Case用例在这里设置不同ma-form选项
export default function useOptions(formRef: any) {
const options = ref({
showButtons: false,
labelAlign: "center"
})
const crudColumns = useColumn(formRef)
const columnOptions = computed(() => {
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
})
return { options, columnOptions }
}

View File

@@ -0,0 +1,213 @@
import { ref } from "vue"
import { useRoute } from "vue-router"
export default function (crudOrFormRef: any, problemFormRef?: any) {
const title = ref("问题单表单")
const route = useRoute()
const crudColumns = ref([
{
title: "ID",
width: 60,
align: "center",
hide: true,
dataIndex: "id",
fixed: "left",
display: false
},
{
title: "用例标识",
dataIndex: "ident",
sortable: { sortDirections: ["ascend"] },
width: 180,
align: "center",
addDisabled: true,
addDefaultValue: "用例标识自动生成结构为YL_IO_XXXX_001",
editDefaultValue: "用例标识自动生成结构为YL_IO_XXXX_001",
editDisabled: true,
search: true,
validateTrigger: "blur"
},
{
title: "名称",
dataIndex: "name",
align: "center",
search: true,
commonRules: [{ required: true, message: "名称是必填" }],
validateTrigger: "blur"
},
{
title: "是否通过",
align: "center",
display: false,
addDisplay: false,
editDisplay: false,
customRender: ({ record }) => {
let passCount = 0
let failCount = 0
let stepCount = record.testStep.length
record.testStep.forEach((item) => {
if (item.passed === "1") {
passCount++
} else if (item.passed === "2") {
failCount++
}
})
if (failCount > 0) {
return (
<a-tag bordered color="red">
</a-tag>
)
} else {
if (passCount === stepCount) {
return (
<a-tag bordered color="green">
</a-tag>
)
} else {
return (
<a-tag bordered color="orange">
</a-tag>
)
}
}
}
},
{
title: "设计人员",
width: 80,
dataIndex: "designPerson",
align: "center",
hide: true,
search: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "执行人员",
dataIndex: "testPerson",
width: 120,
align: "center",
search: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "审核人员",
dataIndex: "monitorPerson",
width: 80,
align: "center",
hide: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "用例综述",
align: "center",
dataIndex: "summarize",
hide: true,
search: true,
addDefaultValue: ""
},
{
title: "用例初始化",
dataIndex: "initialization",
hide: true,
addDefaultValue: "软件正常启动,正常登录进软件"
},
{
title: "前提和约束",
dataIndex: "premise",
hide: true,
addDefaultValue: "软件正常启动,各界面显示工作正常"
},
{
title: "执行时间",
dataIndex: "exe_time",
hide: true,
formType: "date"
},
{
title: "测试步骤",
dataIndex: "testStep",
hide: true,
addDefaultValue: [
{
operation: "",
expect: "",
result: "",
passed: "3"
}
],
formType: "children-form",
type: "group",
formList: [
{
title: "操作",
dataIndex: "operation",
formType: "editor",
height: 180
},
{
title: "预期",
placeholder: "请输入预期结果",
dataIndex: "expect"
},
{
title: "结果",
dataIndex: "result",
formType: "editor",
height: 180
},
{
title: "是否通过",
dataIndex: "passed",
formType: "radio",
dict: { name: "passType", props: { label: "title", value: "key" } },
commonRules: [{ required: true, message: "是否通过必填" }]
}
]
},
{
title: "关联问题",
dataIndex: "problem",
width: 150,
addDisplay: false,
editDisplay: false,
align: "center",
display: false,
customRender: ({ record }) => {
if (record.problem) {
return (
<a-link
onClick={() => {
title.value = `PT_${route.query.ident}_${record.problem.ident.padStart(3, 0)}`
problemFormRef.value.open(record.problem)
}}
>{`PT_${route.query.ident}_${record.problem.ident.padStart(3, 0)}`}</a-link>
)
} else {
return "无问题单"
}
}
}
])
return crudColumns
}

View File

@@ -0,0 +1,159 @@
import { ref, getCurrentInstance, type Ref } from "vue"
import MaCrud from "@/components/ma-crud/index.vue"
import { useRoute } from "vue-router"
import caseApi from "@/api/project/case"
import { useTreeDataStore } from "@/store"
import { isEqual, cloneDeep } from "lodash-es"
/**
* Dut被测件的crud选项
*/
export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
// globals
const route = useRoute() as any
const projectId = ref(route.query.id)
const treeDataStore = useTreeDataStore()
const roundNumber = route.query.key.split("-")[0]
const dutNumber = route.query.key.split("-")[1]
const designDemandNumber = route.query.key.split("-")[2]
const testDemandNumber = route.query.key.split("-")[3]
// 辅助
const app = getCurrentInstance()!.appContext.config.globalProperties
let beforeFormStep = undefined
// 注意只保留测试步骤!!!
const handleBeforeCancel = () => {
if (!beforeFormStep) {
return
}
crudRef.value.getFormData().testStep
const iuEqualValue = isEqual(crudRef.value.getFormData().testStep, beforeFormStep)
!iuEqualValue &&
app.$modal.confirm({
title: "测试项步骤内容你已改动,是否保留您编写的测试项/测试用例步骤数据?",
content: "",
okText: "保留",
cancelText: "恢复原数据",
simple: true,
onOk: () => null,
onCancel: () => {
crudRef.value.refresh()
}
})
}
// refs
const crudOptions = ref({
api: caseApi.getCaseList,
add: { show: true, api: caseApi.save, text: "新增用例" },
edit: { show: true, api: caseApi.update, text: "修改用例" },
delete: { show: true, api: caseApi.delete },
operationColumnAlign: "center",
isDbClickEdit: true, // 关闭双击编辑
// 处理新增删除后树状图显示
beforeOpenAdd: function () {
// 1.新增则将form的content数据变为undifined以便判断
beforeFormStep = undefined
// 2.标识处理
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let test_key = key_split[3]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} >
${(td[round_key] as any).title} > ${(td[round_key] as any).children[dut_key].title} >
${(td[round_key] as any).children[dut_key].children[design_key].title} >
${(td[round_key] as any).children[dut_key].children[design_key].children[test_key].title} > 用例-`
return true
},
beforeOpenEdit: function (record) {
// 1.储存打开前form的content数据到ref中以便后续比较
beforeFormStep = cloneDeep(record.testStep)
// 2.标识处理
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let test_key = key_split[3]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} >
${(td[round_key] as any).title} > ${(td[round_key] as any).children[dut_key].title} >
${(td[round_key] as any).children[dut_key].children[design_key].title} >
${(td[round_key] as any).children[dut_key].children[design_key].children[test_key].title}
>用例[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateCaseTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateCaseTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateCaseTreeData(record, id)
// 被删除还是在选择里面
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber,
designDemand: designDemandNumber,
testDemand: testDemandNumber
},
showIndex: false,
showTools: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 180,
operationColumn: true,
formOption: {
width: 1200,
layout: [
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "ident" }] },
{ span: 12, formList: [{ dataIndex: "name" }] }
]
},
{
formType: "card",
customClass: ["ml-10", "mb-3", "py-0", "px-0"],
title: "人员信息",
formList: [
{
formType: "grid",
cols: [
{ span: 8, formList: [{ dataIndex: "designPerson" }] },
{ span: 8, formList: [{ dataIndex: "testPerson" }] },
{ span: 8, formList: [{ dataIndex: "monitorPerson" }] }
]
}
]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "summarize" }] }]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "initialization" }] }]
},
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "premise" }] },
{ span: 12, formList: [{ dataIndex: "exe_time" }] }
]
}
]
}
})
return { handleBeforeCancel, crudOptions }
}

View File

@@ -13,369 +13,22 @@
</template>
<script setup lang="jsx">
import { ref, getCurrentInstance } from "vue"
import { useRoute } from "vue-router"
import caseApi from "@/api/project/case"
import { useTreeDataStore } from "@/store"
import { ref } from "vue"
import ProblemForm from "@/views/project/case/components/ProblemForm.vue"
import { isEqual, cloneDeep } from "lodash-es"
import useCrudOpMore from "./hooks/useCrudOpMore"
import useColumn from "./hooks/useColumn"
const problemFormRef = ref(null)
const title = ref("问题单表单")
const treeDataStore = useTreeDataStore()
const route = useRoute()
const roundNumber = route.query.key.split("-")[0]
const dutNumber = route.query.key.split("-")[1]
const designDemandNumber = route.query.key.split("-")[2]
const testDemandNumber = route.query.key.split("-")[3]
const crudRef = ref()
const projectId = ref(route.query.id)
// 标识显示字段-用例比较特殊让后端返回了“FT”字样因为FT是在测试项里面标识的
// 标识重新定义
const showType = (record) => {
let key_string = parseInt(record.key.substring(record.key.lastIndexOf("-") + 1)) + 1
return "YL-" + record.testType + "-" + record.ident + "-" + key_string.toString().padStart(3, "0")
}
// crud设置以及是否保留step数据事件函数
const app = getCurrentInstance().appContext.config.globalProperties
let beforeFormStep = undefined
// 注意只保留测试步骤!!!
const handleBeforeCancel = () => {
if (!beforeFormStep) {
return
}
crudRef.value.getFormData().testStep
const iuEqualValue = isEqual(crudRef.value.getFormData().testStep, beforeFormStep)
!iuEqualValue &&
app.$modal.confirm({
title: "测试项步骤内容你已改动,是否保留您编写的测试项/测试用例步骤数据?",
content: "",
okText: "保留",
cancelText: "恢复原数据",
simple: true,
onOk: () => null,
onCancel: () => {
crudRef.value.refresh()
}
})
}
const crudOptions = ref({
api: caseApi.getCaseList,
add: { show: true, api: caseApi.save, text: "新增用例" },
edit: { show: true, api: caseApi.update, text: "修改用例" },
delete: { show: true, api: caseApi.delete },
operationColumnAlign: "center",
isDbClickEdit: true, // 关闭双击编辑
// 处理新增删除后树状图显示
beforeOpenAdd: function () {
// 1.新增则将form的content数据变为undifined以便判断
beforeFormStep = undefined
// 2.标识处理
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let test_key = key_split[3]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} >
${td[round_key].title} > ${td[round_key].children[dut_key].title} >
${td[round_key].children[dut_key].children[design_key].title} >
${td[round_key].children[dut_key].children[design_key].children[test_key].title} > 用例-`
return true
},
beforeOpenEdit: function (record) {
// 1.储存打开前form的content数据到ref中以便后续比较
beforeFormStep = cloneDeep(record.testStep)
// 2.标识处理
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let test_key = key_split[3]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} >
${td[round_key].title} > ${td[round_key].children[dut_key].title} >
${td[round_key].children[dut_key].children[design_key].title} >
${td[round_key].children[dut_key].children[design_key].children[test_key].title}
>用例[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateCaseTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateCaseTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateCaseTreeData(record, id)
// 被删除还是在选择里面
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber,
designDemand: designDemandNumber,
testDemand: testDemandNumber
},
showIndex: false,
showTools: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 180,
operationColumn: true,
formOption: {
width: 1200,
layout: [
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "ident" }] },
{ span: 12, formList: [{ dataIndex: "name" }] }
]
},
{
formType: "card",
customClass: ["ml-10", "mb-3", "py-0", "px-0"],
title: "人员信息",
formList: [
{
formType: "grid",
cols: [
{ span: 8, formList: [{ dataIndex: "designPerson" }] },
{ span: 8, formList: [{ dataIndex: "testPerson" }] },
{ span: 8, formList: [{ dataIndex: "monitorPerson" }] }
]
}
]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "summarize" }] }]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "initialization" }] }]
},
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "premise" }] },
{ span: 12, formList: [{ dataIndex: "exe_time" }] }
]
}
]
}
})
const crudColumns = ref([
{
title: "ID",
width: 60,
align: "center",
hide: true,
dataIndex: "id",
fixed: "left"
},
{
title: "用例标识",
dataIndex: "ident",
sortable: { sortDirections: ["ascend"] },
width: 180,
align: "center",
addDisabled: true,
addDefaultValue: "用例标识自动生成结构为YL_IO_XXXX_001",
editDefaultValue: "用例标识自动生成结构为YL_IO_XXXX_001",
editDisabled: true,
search: true,
validateTrigger: "blur"
},
{
title: "名称",
dataIndex: "name",
align: "center",
search: true,
commonRules: [{ required: true, message: "名称是必填" }],
validateTrigger: "blur"
},
{
title: "是否通过",
align: "center",
display: false,
addDisplay: false,
editDisplay: false,
customRender: ({ record }) => {
let passCount = 0
let failCount = 0
let stepCount = record.testStep.length
record.testStep.forEach((item) => {
if (item.passed === "1") {
passCount++
} else if (item.passed === "2") {
failCount++
}
})
if (failCount > 0) {
return (
<a-tag bordered color="red">
未通过
</a-tag>
)
} else {
if (passCount === stepCount) {
return (
<a-tag bordered color="green">
已通过
</a-tag>
)
} else {
return (
<a-tag bordered color="orange">
包含未执行
</a-tag>
)
}
}
}
},
{
title: "设计人员",
width: 80,
dataIndex: "designPerson",
align: "center",
hide: true,
search: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "执行人员",
dataIndex: "testPerson",
width: 120,
align: "center",
search: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "审核人员",
dataIndex: "monitorPerson",
width: 80,
align: "center",
hide: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "用例综述",
align: "center",
dataIndex: "summarize",
hide: true,
search: true,
addDefaultValue: ""
},
{
title: "用例初始化",
dataIndex: "initialization",
hide: true,
addDefaultValue: "软件正常启动,正常登录进软件"
},
{
title: "前提和约束",
dataIndex: "premise",
hide: true,
addDefaultValue: "软件正常启动,各界面显示工作正常"
},
{
title: "执行时间",
dataIndex: "exe_time",
hide: true,
formType: "date"
},
{
title: "测试步骤",
dataIndex: "testStep",
hide: true,
addDefaultValue: [
{
operation: "",
expect: "",
result: "",
passed: "3"
}
],
formType: "children-form",
type: "group",
formList: [
{
title: "操作",
dataIndex: "operation",
formType: "editor",
height: 180
},
{
title: "预期",
placeholder: "请输入预期结果",
dataIndex: "expect"
},
{
title: "结果",
dataIndex: "result",
formType: "editor",
height: 180
},
{
title: "是否通过",
dataIndex: "passed",
formType: "radio",
dict: { name: "passType", props: { label: "title", value: "key" } },
commonRules: [{ required: true, message: "是否通过必填" }]
}
]
},
{
title: "关联问题",
dataIndex: "problem",
width: 150,
addDisplay: false,
editDisplay: false,
align: "center",
customRender: ({ record }) => {
if (record.problem) {
return (
<a-link
onClick={() => {
title.value = `PT_${route.query.ident}_${record.problem.ident.padStart(3, 0)}`
problemFormRef.value.open(record.problem)
}}
>{`PT_${route.query.ident}_${record.problem.ident.padStart(3, 0)}`}</a-link>
)
} else {
return "无问题单"
}
}
}
])
const { handleBeforeCancel, crudOptions } = useCrudOpMore(crudRef)
const crudColumns = useColumn(crudRef, problemFormRef)
// 暴露刷新表格方法给外部
const refreshCrudTable = () => {
crudRef.value.refresh()