0.0.2
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "cdtmp",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -6,7 +6,7 @@ import qs, { stringify } from "qs"
|
||||
import { h } from "vue"
|
||||
import { IconFaceFrownFill } from "@arco-design/web-vue/dist/arco-vue-icon"
|
||||
|
||||
// createService
|
||||
// 创建axios实例,添加请求和响应拦截器,返回该axios实例
|
||||
function createService() {
|
||||
// 创建axios实例
|
||||
const service = axios.create()
|
||||
@@ -21,7 +21,6 @@ function createService() {
|
||||
// 实例的response响应拦截器
|
||||
service.interceptors.response.use(
|
||||
(res) => {
|
||||
// 如果发现响应头有文件传输扩展,或者响应头为application/json,或者直接status=200
|
||||
if (
|
||||
(res.headers["content-disposition"] || !/^application\/json/.test(res.headers["content-type"])) &&
|
||||
res.status === 200
|
||||
@@ -33,17 +32,15 @@ function createService() {
|
||||
res.data.message = "服务器内部错误"
|
||||
res.data.success = false
|
||||
} else if (res.data.code && res.data.code !== 200) {
|
||||
// 如果data里面code字段不为200
|
||||
Message.error({
|
||||
content: res.data.message,
|
||||
// 注意奇怪的用法
|
||||
icon: () => h(IconFaceFrownFill)
|
||||
})
|
||||
}
|
||||
return res.data
|
||||
},
|
||||
(error) => {
|
||||
// 其实基本逻辑是有message写message
|
||||
// 没用message再去找默认的response的status
|
||||
const err = (text) => {
|
||||
Message.error({
|
||||
content:
|
||||
@@ -79,6 +76,7 @@ function createService() {
|
||||
break
|
||||
default:
|
||||
err("未知错误!")
|
||||
break
|
||||
}
|
||||
} else {
|
||||
err("请求超时,服务器无响应!")
|
||||
@@ -96,7 +94,6 @@ function createService() {
|
||||
function createRequest(service) {
|
||||
return function (config) {
|
||||
const env = import.meta.env
|
||||
// localStorage获取token信息
|
||||
const token = tool.local.get(env.VITE_APP_TOKEN_PREFIX)
|
||||
const configDefault = {
|
||||
headers: {
|
||||
@@ -108,12 +105,7 @@ function createRequest(service) {
|
||||
baseURL: env.VITE_APP_OPEN_PROXY === "true" ? env.VITE_APP_PROXY_PREFIX : env.VITE_APP_BASE_URL,
|
||||
data: {}
|
||||
}
|
||||
// option是configDefault和传入的config合并
|
||||
const option = Object.assign(configDefault, config)
|
||||
// lodash的isEmpty函数可以判断对象属性是否为空/数组是否为空->为空则返回true
|
||||
// qs中stringfy作用是urlencode
|
||||
// { c: 'b', a: 'd' } -> 'c=b&a=d'
|
||||
// 如果有params就转为urlencode样子
|
||||
if (!isEmpty(option.params)) {
|
||||
option.url = option.url + "?" + stringify(option.params)
|
||||
option.params = {}
|
||||
@@ -122,7 +114,5 @@ function createRequest(service) {
|
||||
}
|
||||
}
|
||||
|
||||
// 上面两个函数一个为增加实例拦截器,一个是传入实例后请求
|
||||
export const service = createService()
|
||||
// 返回的是一个函数,这个函数传入config然后添加上默认config然后发出实例的请求
|
||||
export const request = createRequest(service)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<template>
|
||||
<!-- add:on-before-cancel -->
|
||||
<component
|
||||
:is="componentName"
|
||||
v-model:visible="dataVisible"
|
||||
:on-before-ok="submit"
|
||||
:on-before-cancel="beforeCancel"
|
||||
@cancel="close"
|
||||
ok-text="保存"
|
||||
cancel-text="关闭"
|
||||
@@ -46,7 +48,7 @@ const dataVisible = ref(false)
|
||||
const form = ref({})
|
||||
const actionTitle = ref("")
|
||||
const dataLoading = ref(true)
|
||||
const emit = defineEmits(["success", "error"])
|
||||
const emit = defineEmits(["success", "error", "beforeCancel"])
|
||||
|
||||
provide("form", toRaw(form))
|
||||
|
||||
@@ -134,6 +136,11 @@ const open = () => {
|
||||
dataVisible.value = true
|
||||
}
|
||||
}
|
||||
// ~~~~addMethod~~~~
|
||||
const beforeCancel = () => {
|
||||
emit("beforeCancel")
|
||||
return true
|
||||
}
|
||||
const close = () => {
|
||||
dataVisible.value = false
|
||||
formColumns.value = []
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
class="ma-crud-table-tr"
|
||||
:class="
|
||||
isFunction(options.rowCustomClass)
|
||||
? options.rowCustomClass(record, rowIndex) ?? []
|
||||
? (options.rowCustomClass(record, rowIndex) ?? [])
|
||||
: options.rowCustomClass
|
||||
"
|
||||
@contextmenu.prevent="openContextMenu($event, record)"
|
||||
@@ -215,7 +215,7 @@
|
||||
|
||||
<ma-setting ref="crudSettingRef" />
|
||||
|
||||
<ma-form ref="crudFormRef" @success="requestSuccess">
|
||||
<ma-form ref="crudFormRef" @success="requestSuccess" v-bind="$attrs">
|
||||
<template v-for="slot in Object.keys($slots)" #[slot]="component">
|
||||
<slot :name="slot" v-bind="component" />
|
||||
</template>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
>
|
||||
测试管理平台
|
||||
</a-typography-title>
|
||||
<a-typography-title :heading="6" class="version">V0.0.1</a-typography-title>
|
||||
<a-typography-title :heading="6" class="version">V0.0.2</a-typography-title>
|
||||
<icon-menu-fold
|
||||
v-if="!topMenu && appStore.device === 'mobile'"
|
||||
style="font-size: 22px; cursor: pointer"
|
||||
@@ -22,9 +22,7 @@
|
||||
<div class="center-side flex items-center justify-center font-bold text-lg">
|
||||
<template v-if="title">
|
||||
<a-typography-title :style="{ margin: 0, fontSize: '1.1rem', fontWeight: 'bold' }" :heading="4">
|
||||
项目名称:{{ $route.query.ident }}-{{ title }}- key的值为:{{
|
||||
route.query.key ? route.query.key : "无key值"
|
||||
}}
|
||||
项目名称:{{ $route.query.ident }}-{{ title }}
|
||||
</a-typography-title>
|
||||
</template>
|
||||
<Menu v-if="topMenu"></Menu>
|
||||
|
||||
@@ -40,6 +40,7 @@ const router = createRouter({
|
||||
component: () => import("@/views/project/round/index.vue"),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
ignoreCache: true,
|
||||
roles: ["*"],
|
||||
locale: "轮次信息",
|
||||
icon: "icon-arrow-right"
|
||||
@@ -51,6 +52,7 @@ const router = createRouter({
|
||||
component: () => import("@/views/project/dut/index.vue"),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
ignoreCache: true,
|
||||
roles: ["*"],
|
||||
locale: "被测件信息",
|
||||
icon: "icon-arrow-right"
|
||||
@@ -62,6 +64,7 @@ const router = createRouter({
|
||||
component: () => import("@/views/project/design-demand/index.vue"),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
ignoreCache: true,
|
||||
roles: ["*"],
|
||||
locale: "设计需求",
|
||||
icon: "icon-arrow-right"
|
||||
@@ -73,6 +76,7 @@ const router = createRouter({
|
||||
component: () => import("@/views/project/testDemand/index.vue"),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
ignoreCache: true,
|
||||
roles: ["*"],
|
||||
locale: "测试需求",
|
||||
icon: "icon-arrow-right"
|
||||
@@ -84,6 +88,7 @@ const router = createRouter({
|
||||
component: () => import("@/views/project/case/index.vue"),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
ignoreCache: true,
|
||||
roles: ["*"],
|
||||
locale: "测试用例",
|
||||
icon: "icon-arrow-right"
|
||||
@@ -95,6 +100,7 @@ const router = createRouter({
|
||||
component: () => import("@/views/project/problem/index.vue"),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
ignoreCache: true,
|
||||
roles: ["*"],
|
||||
locale: "问题单详情",
|
||||
icon: "icon-arrow-right"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</a>
|
||||
</a-card>
|
||||
<div class="mt-2">管理平台版本</div>
|
||||
<a-tag class="mt-2" color="#0fc6c2">TestManagePlant V0.0.1</a-tag>
|
||||
<a-tag class="mt-2" color="#0fc6c2">TestManagePlant V0.0.2</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
43
cdTMP/src/views/datamanage/dictmanage/DataList/index.vue
Normal file
43
cdTMP/src/views/datamanage/dictmanage/DataList/index.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" width="80%" draggable :footer="false">
|
||||
<template #title>维护数据字典 →【{{ currentRow.name }}】</template>
|
||||
<!-- crud组件 -->
|
||||
<div class="lg:w-full w-full lg:mt-0">
|
||||
<ma-crud :options="crudOptions" :columns="columns" ref="crudRef">
|
||||
<!-- 排序列 -->
|
||||
<template #sort="{ record }">
|
||||
<a-input-number
|
||||
:default-value="record.sort"
|
||||
mode="button"
|
||||
@change="changeSort($event, record.id)"
|
||||
:min="0"
|
||||
:max="1000"
|
||||
/>
|
||||
</template>
|
||||
<!-- 状态列 -->
|
||||
<template #status="{ record }">
|
||||
<a-switch
|
||||
:checked-value="1"
|
||||
unchecked-value="2"
|
||||
@change="changeStatus($event, record.id)"
|
||||
:default-checked="record.status == 1"
|
||||
/>
|
||||
</template>
|
||||
</ma-crud>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue"
|
||||
import useCrudRef from "./useCrudRef"
|
||||
import useOpenChangeModal from "./useOpenChangeModal"
|
||||
|
||||
const currentRow = ref({ id: undefined, name: undefined }) // 当前选择的行
|
||||
const { crudRef, crudOptions, columns } = useCrudRef(currentRow)
|
||||
const { visible, changeSort, changeStatus, open } = useOpenChangeModal(crudRef, currentRow)
|
||||
// 暴露自己的open方法
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
120
cdTMP/src/views/datamanage/dictmanage/DataList/useCrudRef.ts
Normal file
120
cdTMP/src/views/datamanage/dictmanage/DataList/useCrudRef.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { ref, type Ref } from "vue"
|
||||
import dictApi from "@/api/system/dict"
|
||||
/**
|
||||
* 定义crud的ref以及其
|
||||
*/
|
||||
export default function useCrudRef(currentRow: Ref<{ id: number | string; name: string }>) {
|
||||
const crudRef = ref()
|
||||
// crud选项
|
||||
const crudOptions = ref({
|
||||
autoRequest: false,
|
||||
api: dictApi.getDictItemAll,
|
||||
showIndex: false,
|
||||
rowSelection: { showCheckedAll: true },
|
||||
operationColumn: true,
|
||||
operationWidth: 160,
|
||||
operationColumnAlign: "center",
|
||||
showTools: false,
|
||||
beforeAdd: (form: any) => {
|
||||
form.id = currentRow.value?.id
|
||||
},
|
||||
add: { show: true, api: dictApi.saveDictItem },
|
||||
edit: { show: true, api: dictApi.updateDictItemData },
|
||||
delete: { show: true, api: dictApi.realDeleteItem },
|
||||
afterDelete(response) {
|
||||
crudRef.value.tableRef.selectAll(false)
|
||||
}
|
||||
})
|
||||
|
||||
// crudColumns
|
||||
const columns = ref([
|
||||
{ title: "ID", dataIndex: "id", addDisplay: false, editDisplay: false, width: 50, hide: true },
|
||||
{
|
||||
title: "字典标签",
|
||||
align: "center",
|
||||
dataIndex: "title",
|
||||
search: true,
|
||||
width: 150,
|
||||
commonRules: [{ required: true, message: "字典标签必填" }]
|
||||
},
|
||||
{
|
||||
title: "字段缩写",
|
||||
dataIndex: "show_title",
|
||||
align: "center",
|
||||
search: true
|
||||
},
|
||||
{
|
||||
title: "字典键值",
|
||||
align: "center",
|
||||
dataIndex: "key",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
search: true,
|
||||
commonRules: [{ required: true, message: "字典键值必填" }]
|
||||
},
|
||||
{
|
||||
title: "排序",
|
||||
align: "center",
|
||||
dataIndex: "sort",
|
||||
formType: "input-number",
|
||||
addDefaultValue: 1,
|
||||
width: 130,
|
||||
min: 0,
|
||||
max: 1000
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
align: "center",
|
||||
dataIndex: "status",
|
||||
search: true,
|
||||
addDefaultValue: "1",
|
||||
formType: "radio",
|
||||
dict: { name: "data_status", props: { label: "title", value: "key" } },
|
||||
width: 70
|
||||
},
|
||||
{
|
||||
title: "备注",
|
||||
align: "center",
|
||||
dataIndex: "remark",
|
||||
hide: true,
|
||||
formType: "textarea"
|
||||
},
|
||||
{
|
||||
title: "更新时间",
|
||||
align: "center",
|
||||
dataIndex: "update_datetime",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
search: true,
|
||||
formType: "range",
|
||||
width: 110
|
||||
},
|
||||
{
|
||||
title: "文档名称",
|
||||
dataIndex: "doc_name",
|
||||
align: "center",
|
||||
search: false,
|
||||
placeholder: "如果不是标准则不填"
|
||||
},
|
||||
{
|
||||
title: "发布日期",
|
||||
dataIndex: "publish_date",
|
||||
align: "center",
|
||||
search: false,
|
||||
placeholder: "如果不是标准则不填"
|
||||
},
|
||||
{
|
||||
title: "标准来源",
|
||||
dataIndex: "source",
|
||||
align: "center",
|
||||
search: false,
|
||||
placeholder: "如果不是标准则不填"
|
||||
}
|
||||
])
|
||||
|
||||
return {
|
||||
crudRef,
|
||||
crudOptions,
|
||||
columns
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { ref, type Ref } from "vue"
|
||||
import dictApi from "@/api/system/dict"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import MaCrud from "@/components/ma-crud/index.vue"
|
||||
/**
|
||||
* 1.打开该modal方法/改变状态/改变排序
|
||||
*/
|
||||
export default function useOpenChangeModal(crudRef: Ref<InstanceType<typeof MaCrud>>, currentRow: Ref<any>) {
|
||||
// refs
|
||||
const visible = ref(false)
|
||||
// 事件处理
|
||||
const changeSort = async (value: number, id: number): Promise<void> => {
|
||||
const response = await dictApi.numberOperation({ id, numberName: "sort", numberValue: value })
|
||||
response.success && Message.success(response.message)
|
||||
crudRef.value.refresh()
|
||||
}
|
||||
const changeStatus = async (status: number | string, id: number): Promise<void> => {
|
||||
const response = await dictApi.changeItemStatus({ id, status })
|
||||
if (response.success) {
|
||||
Message.success(response.message)
|
||||
}
|
||||
}
|
||||
// 定义该open方法并暴露给组件外部
|
||||
// 打开a-modal事件
|
||||
const open = (row: Ref<any>) => {
|
||||
currentRow.value = row
|
||||
// 调用固定方法请求数据
|
||||
crudRef.value.requestParams = { id: currentRow.value.id }
|
||||
crudRef.value.requestData()
|
||||
visible.value = true
|
||||
// 判断如果是行数据的code值为standard则不显示‘文档名称’‘发布来源’‘发布日期’,且表单也不显示
|
||||
// columnService可以动态设置表格列的属性!!!
|
||||
const columnService = crudRef.value.getColumnService()
|
||||
if (currentRow.value.code === "standard") {
|
||||
columnService.get("doc_name").setAttr("hide", false)
|
||||
columnService.get("publish_date").setAttr("hide", false)
|
||||
columnService.get("source").setAttr("hide", false)
|
||||
columnService.get("doc_name").setAttr("addDisplay", true)
|
||||
columnService.get("publish_date").setAttr("addDisplay", true)
|
||||
columnService.get("source").setAttr("addDisplay", true)
|
||||
columnService.get("doc_name").setAttr("editDisplay", true)
|
||||
columnService.get("publish_date").setAttr("editDisplay", true)
|
||||
columnService.get("source").setAttr("editDisplay", true)
|
||||
} else {
|
||||
columnService.get("doc_name").setAttr("hide", true)
|
||||
columnService.get("publish_date").setAttr("hide", true)
|
||||
columnService.get("source").setAttr("hide", true)
|
||||
columnService.get("doc_name").setAttr("addDisplay", false)
|
||||
columnService.get("publish_date").setAttr("addDisplay", false)
|
||||
columnService.get("source").setAttr("addDisplay", false)
|
||||
columnService.get("doc_name").setAttr("editDisplay", false)
|
||||
columnService.get("publish_date").setAttr("editDisplay", false)
|
||||
columnService.get("source").setAttr("editDisplay", false)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
visible,
|
||||
changeSort,
|
||||
changeStatus,
|
||||
open
|
||||
}
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" width="auto" draggable :footer="false">
|
||||
<template #title>维护数据字典 →【{{ currentRow.name }}】</template>
|
||||
<!-- crud组件 -->
|
||||
<div class="lg:w-full w-full lg:mt-0">
|
||||
<ma-crud :options="crudOptions" :columns="columns" ref="crudRef">
|
||||
<!-- 排序列 -->
|
||||
<template #sort="{ record }">
|
||||
<a-input-number
|
||||
:default-value="record.sort"
|
||||
mode="button"
|
||||
@change="changeSort($event, record.id)"
|
||||
:min="0"
|
||||
:max="1000"
|
||||
/>
|
||||
</template>
|
||||
<!-- 状态列 -->
|
||||
<template #status="{ record }">
|
||||
<a-switch
|
||||
:checked-value="1"
|
||||
unchecked-value="2"
|
||||
@change="changeStatus($event, record.id)"
|
||||
:default-checked="record.status == 1"
|
||||
/>
|
||||
</template>
|
||||
</ma-crud>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue"
|
||||
import dictApi from "@/api/system/dict"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
|
||||
const crudRef = ref()
|
||||
const visible = ref(false)
|
||||
const currentRow = ref({ id: undefined, name: undefined })
|
||||
|
||||
// 改变dictItem的sort字段
|
||||
const changeSort = async (value, id) => {
|
||||
const response = await dictApi.numberOperation({ id, numberName: "sort", numberValue: value })
|
||||
response.success && Message.success(response.message)
|
||||
crudRef.value.refresh()
|
||||
}
|
||||
// 改变dictItem状态
|
||||
const changeStatus = async (status, id) => {
|
||||
const response = await dictApi.changeItemStatus({ id, status })
|
||||
if (response.success) {
|
||||
Message.success(response.message)
|
||||
}
|
||||
}
|
||||
|
||||
// 打开a-modal事件
|
||||
const open = (row) => {
|
||||
currentRow.value = row
|
||||
// 调用固定方法请求数据
|
||||
crudRef.value.requestParams = { id: currentRow.value.id }
|
||||
crudRef.value.requestData()
|
||||
visible.value = true
|
||||
// 判断如果是行数据的code值为standard则不显示‘文档名称’‘发布来源’‘发布日期’,且表单也不显示
|
||||
// columnService可以动态设置表格列的属性!!!
|
||||
const columnService = crudRef.value.getColumnService()
|
||||
if (currentRow.value.code === "standard") {
|
||||
columnService.get("doc_name").setAttr("hide", false)
|
||||
columnService.get("publish_date").setAttr("hide", false)
|
||||
columnService.get("source").setAttr("hide", false)
|
||||
columnService.get("doc_name").setAttr("addDisplay", true)
|
||||
columnService.get("publish_date").setAttr("addDisplay", true)
|
||||
columnService.get("source").setAttr("addDisplay", true)
|
||||
columnService.get("doc_name").setAttr("editDisplay", true)
|
||||
columnService.get("publish_date").setAttr("editDisplay", true)
|
||||
columnService.get("source").setAttr("editDisplay", true)
|
||||
} else {
|
||||
columnService.get("doc_name").setAttr("hide", true)
|
||||
columnService.get("publish_date").setAttr("hide", true)
|
||||
columnService.get("source").setAttr("hide", true)
|
||||
columnService.get("doc_name").setAttr("addDisplay", false)
|
||||
columnService.get("publish_date").setAttr("addDisplay", false)
|
||||
columnService.get("source").setAttr("addDisplay", false)
|
||||
columnService.get("doc_name").setAttr("editDisplay", false)
|
||||
columnService.get("publish_date").setAttr("editDisplay", false)
|
||||
columnService.get("source").setAttr("editDisplay", false)
|
||||
}
|
||||
}
|
||||
// crud选项
|
||||
const crudOptions = ref({
|
||||
autoRequest: false,
|
||||
api: dictApi.getDictItemAll,
|
||||
showIndex: false,
|
||||
rowSelection: { showCheckedAll: true },
|
||||
operationColumn: true,
|
||||
operationWidth: 160,
|
||||
operationColumnAlign: "center",
|
||||
showTools: false,
|
||||
beforeAdd: (form) => {
|
||||
form.id = currentRow.value?.id
|
||||
},
|
||||
add: { show: true, api: dictApi.saveDictItem },
|
||||
edit: { show: true, api: dictApi.updateDictItemData },
|
||||
delete: { show: true, api: dictApi.realDeleteItem },
|
||||
afterDelete(response) {
|
||||
crudRef.value.tableRef.selectAll(false)
|
||||
}
|
||||
})
|
||||
|
||||
// crudColumns
|
||||
const columns = ref([
|
||||
{ title: "ID", dataIndex: "id", addDisplay: false, editDisplay: false, width: 50, hide: true },
|
||||
{
|
||||
title: "字典标签",
|
||||
align: "center",
|
||||
dataIndex: "title",
|
||||
search: true,
|
||||
width: 150,
|
||||
commonRules: [{ required: true, message: "字典标签必填" }]
|
||||
},
|
||||
{
|
||||
title: "字段缩写",
|
||||
dataIndex: "show_title",
|
||||
align: "center",
|
||||
search: true
|
||||
},
|
||||
{
|
||||
title: "字典键值",
|
||||
align: "center",
|
||||
dataIndex: "key",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
search: true,
|
||||
commonRules: [{ required: true, message: "字典键值必填" }]
|
||||
},
|
||||
{
|
||||
title: "排序",
|
||||
align: "center",
|
||||
dataIndex: "sort",
|
||||
formType: "input-number",
|
||||
addDefaultValue: 1,
|
||||
width: 130,
|
||||
min: 0,
|
||||
max: 1000
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
align: "center",
|
||||
dataIndex: "status",
|
||||
search: true,
|
||||
addDefaultValue: "1",
|
||||
formType: "radio",
|
||||
dict: { name: "data_status", props: { label: "title", value: "key" } },
|
||||
width: 70
|
||||
},
|
||||
{
|
||||
title: "备注",
|
||||
align: "center",
|
||||
dataIndex: "remark",
|
||||
hide: true,
|
||||
formType: "textarea"
|
||||
},
|
||||
{
|
||||
title: "更新时间",
|
||||
align: "center",
|
||||
dataIndex: "update_datetime",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
search: true,
|
||||
formType: "range",
|
||||
width: 110
|
||||
},
|
||||
{
|
||||
title: "文档名称",
|
||||
dataIndex: "doc_name",
|
||||
align: "center",
|
||||
search: false,
|
||||
placeholder: "如果不是标准则不填"
|
||||
},
|
||||
{
|
||||
title: "发布日期",
|
||||
dataIndex: "publish_date",
|
||||
align: "center",
|
||||
search: false,
|
||||
placeholder: "如果不是标准则不填"
|
||||
},
|
||||
{
|
||||
title: "标准来源",
|
||||
dataIndex: "source",
|
||||
align: "center",
|
||||
search: false,
|
||||
placeholder: "如果不是标准则不填"
|
||||
}
|
||||
])
|
||||
|
||||
// 暴露自己的open方法
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
@@ -32,88 +32,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import { ref } from "vue"
|
||||
import dictApi from "@/api/system/dict"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import DataList from "./dataList.vue"
|
||||
|
||||
const crudRef = ref()
|
||||
const datalistRef = ref()
|
||||
|
||||
// 打开datalist页面
|
||||
const openDictList = async (row) => {
|
||||
datalistRef.value.open(row)
|
||||
}
|
||||
|
||||
// 点击切换status
|
||||
const changeStatus = async (status, id) => {
|
||||
const response = await dictApi.changeStatus({ id, status })
|
||||
if (response.success) {
|
||||
Message.success(response.message)
|
||||
}
|
||||
}
|
||||
|
||||
const crudOptions = ref({
|
||||
api: dictApi.getDictIndex,
|
||||
showIndex: false,
|
||||
operationColumnAlign: "center",
|
||||
rowSelection: { showCheckedAll: true },
|
||||
searchColNumber: 4,
|
||||
tablePagination: false,
|
||||
operationColumn: true,
|
||||
showTools: false,
|
||||
afterDelete(response) {
|
||||
crudRef.value.tableRef.selectAll(false)
|
||||
}
|
||||
})
|
||||
|
||||
const crudColumns = ref([
|
||||
{ title: "ID", dataIndex: "id", addDisplay: false, editDisplay: false, width: 50, hide: true },
|
||||
{
|
||||
title: "字典备注",
|
||||
dataIndex: "remark",
|
||||
search: true,
|
||||
width: 220,
|
||||
align: "center",
|
||||
commonRules: [{ required: true, message: "字典备注必填" }]
|
||||
},
|
||||
{
|
||||
title: "字典标识",
|
||||
dataIndex: "code",
|
||||
search: true,
|
||||
width: 260,
|
||||
align: "center",
|
||||
commonRules: [{ required: true, message: "字典标识必填" }]
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
search: true,
|
||||
formType: "radio",
|
||||
align: "center",
|
||||
dict: { name: "data_status", props: { label: "title", value: "key" } },
|
||||
addDefaultValue: "1",
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: "字典名称",
|
||||
dataIndex: "name",
|
||||
hide: true,
|
||||
formType: "textarea",
|
||||
align: "center"
|
||||
},
|
||||
{
|
||||
title: "更新时间",
|
||||
dataIndex: "update_datetime",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
align: "center",
|
||||
search: true,
|
||||
formType: "range",
|
||||
width: 180
|
||||
}
|
||||
])
|
||||
|
||||
import DataList from "./DataList/index.vue"
|
||||
import useDictCrud from "./useDictCrud"
|
||||
import useDataListRef from "./useDataListRef"
|
||||
// 1.useDictCrud
|
||||
const { crudRef, changeStatus, crudOptions, crudColumns } = useDictCrud()
|
||||
// 2.dataList.vue界面打开和ref定义
|
||||
const { datalistRef, openDictList } = useDataListRef()
|
||||
defineOptions({
|
||||
name: "dictmanage"
|
||||
})
|
||||
|
||||
15
cdTMP/src/views/datamanage/dictmanage/useDataListRef.ts
Normal file
15
cdTMP/src/views/datamanage/dictmanage/useDataListRef.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ref } from "vue"
|
||||
/**
|
||||
* 该hook仅定义dataList的ref以及调用open函数
|
||||
*/
|
||||
export default function useDataListRef() {
|
||||
const datalistRef = ref()
|
||||
// 打开datalist页面
|
||||
const openDictList = async (row: object) => {
|
||||
datalistRef.value.open(row)
|
||||
}
|
||||
return {
|
||||
datalistRef,
|
||||
openDictList
|
||||
}
|
||||
}
|
||||
89
cdTMP/src/views/datamanage/dictmanage/useDictCrud.ts
Normal file
89
cdTMP/src/views/datamanage/dictmanage/useDictCrud.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { ref } from "vue"
|
||||
import dictApi from "@/api/system/dict"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
/**
|
||||
* dict主页面展示配置以及ref定义
|
||||
*/
|
||||
export default function useDictCrud() {
|
||||
// refs
|
||||
const crudRef = ref()
|
||||
// 事件函数
|
||||
const changeStatus = async (status: string, id: number) => {
|
||||
// 点击切换status
|
||||
try {
|
||||
const response = await dictApi.changeStatus({ id, status })
|
||||
if (response.success) {
|
||||
Message.success(response.message)
|
||||
}
|
||||
} catch (err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// crud定义
|
||||
const crudOptions = ref({
|
||||
api: dictApi.getDictIndex,
|
||||
showIndex: false,
|
||||
operationColumnAlign: "center",
|
||||
rowSelection: { showCheckedAll: true },
|
||||
searchColNumber: 4,
|
||||
tablePagination: false,
|
||||
operationColumn: true,
|
||||
showTools: false,
|
||||
afterDelete() {
|
||||
crudRef.value.tableRef.selectAll(false)
|
||||
}
|
||||
})
|
||||
const crudColumns = ref([
|
||||
{ title: "ID", dataIndex: "id", addDisplay: false, editDisplay: false, width: 50, hide: true },
|
||||
{
|
||||
title: "字典备注",
|
||||
dataIndex: "remark",
|
||||
search: true,
|
||||
width: 220,
|
||||
align: "center",
|
||||
commonRules: [{ required: true, message: "字典备注必填" }]
|
||||
},
|
||||
{
|
||||
title: "字典标识",
|
||||
dataIndex: "code",
|
||||
search: true,
|
||||
width: 260,
|
||||
align: "center",
|
||||
commonRules: [{ required: true, message: "字典标识必填" }]
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
search: true,
|
||||
hide: true,
|
||||
formType: "radio",
|
||||
align: "center",
|
||||
dict: { name: "data_status", props: { label: "title", value: "key" } },
|
||||
addDefaultValue: "1",
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: "字典名称",
|
||||
dataIndex: "name",
|
||||
hide: true,
|
||||
formType: "textarea",
|
||||
align: "center"
|
||||
},
|
||||
{
|
||||
title: "更新时间",
|
||||
dataIndex: "update_datetime",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
align: "center",
|
||||
search: true,
|
||||
formType: "range",
|
||||
width: 180
|
||||
}
|
||||
])
|
||||
return {
|
||||
crudRef,
|
||||
changeStatus,
|
||||
crudOptions,
|
||||
crudColumns
|
||||
}
|
||||
}
|
||||
274
cdTMP/src/views/project/design-demand/hooks/useCrudRef.ts
Normal file
274
cdTMP/src/views/project/design-demand/hooks/useCrudRef.ts
Normal file
@@ -0,0 +1,274 @@
|
||||
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"
|
||||
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,
|
||||
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: "请保证测试类型选择正确",
|
||||
// 这是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",
|
||||
placeholder: "对应大纲测试项表格的测试项描述",
|
||||
rules: [{ required: true, message: "测试子项描述必填" }]
|
||||
},
|
||||
{
|
||||
title: "条件",
|
||||
dataIndex: "condition",
|
||||
placeholder: "在什么环境和前置条件下"
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "operation",
|
||||
placeholder: "通过xxx操作"
|
||||
},
|
||||
{
|
||||
title: "观察",
|
||||
dataIndex: "observe",
|
||||
placeholder: "查看xxx内容"
|
||||
},
|
||||
{
|
||||
title: "期望",
|
||||
dataIndex: "expect",
|
||||
placeholder: "xxx结果正确"
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
return {
|
||||
projectId,
|
||||
crudRef,
|
||||
crudOptions,
|
||||
crudColumns,
|
||||
handleBeforeCancel
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { ref, computed, type Ref } from "vue"
|
||||
import testDemandApi from "@/api/project/testDemand"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import { useRoute } from "vue-router"
|
||||
/**
|
||||
* 关联测试项弹窗,并提供事件处理函数
|
||||
*/
|
||||
export default function useRalateDemand(projectId: Ref<string>) {
|
||||
// global
|
||||
const route = useRoute()
|
||||
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 visible = ref(false) // 弹窗显示隐藏
|
||||
const relatedData: Ref<any[]> = ref([]) // 已关联数据
|
||||
const options = ref<any>([]) // 级联cascade组件options
|
||||
const cascaderLoading = ref(false) // 级联的加载圈
|
||||
const computedRelatedData = computed(() => {
|
||||
const labelResultList: any[] = []
|
||||
options.value.forEach((item: any) => {
|
||||
if (item.children) {
|
||||
item.children.forEach((child: any) => {
|
||||
if (relatedData.value.includes(child.value)) {
|
||||
labelResultList.push(child.label)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return labelResultList
|
||||
})
|
||||
// 点击关联测试项-button
|
||||
const handleOpenRelationCSX = async () => {
|
||||
// 请求接口获取数据
|
||||
cascaderLoading.value = true
|
||||
visible.value = true
|
||||
// 点击进入时清除关联
|
||||
relatedData.value = []
|
||||
const res = await testDemandApi.getRelatedTestDemand({ id: projectId.value, round: roundNumber })
|
||||
options.value = res.data
|
||||
// 找出本设计需求design对应已关联的测试项
|
||||
const res_exist = await testDemandApi.getExistRelatedTestDemand({
|
||||
project_id: projectId.value,
|
||||
roundNumber,
|
||||
dutNumber,
|
||||
designDemandNumber
|
||||
})
|
||||
relatedData.value = res_exist.data
|
||||
cascaderLoading.value = false
|
||||
}
|
||||
// 点击关联确定按钮
|
||||
const handleRelatedOk = async () => {
|
||||
// 获取级联数据
|
||||
const relationDestItemIds = relatedData.value
|
||||
if (relationDestItemIds.length > 0) {
|
||||
const res = await testDemandApi.solveRelatedTestDemand({
|
||||
data: relationDestItemIds,
|
||||
project_id: projectId.value,
|
||||
roundNumber,
|
||||
dutNumber,
|
||||
designDemandNumber
|
||||
})
|
||||
if (res.code == 200) {
|
||||
Message.success(res.message)
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
const res = await testDemandApi.solveRelatedTestDemand({
|
||||
data: [],
|
||||
project_id: projectId.value,
|
||||
roundNumber,
|
||||
dutNumber,
|
||||
designDemandNumber
|
||||
})
|
||||
if (res.code == 200) {
|
||||
Message.success(res.message)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return {
|
||||
visible,
|
||||
relatedData,
|
||||
options,
|
||||
cascaderLoading,
|
||||
computedRelatedData,
|
||||
handleOpenRelationCSX,
|
||||
handleRelatedOk
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="ma-content-block lg:flex justify-between p-4">
|
||||
<div class="lg:w-full w-full lg:ml-4 mt-5 lg:mt-0">
|
||||
<!-- CRUD组件 -->
|
||||
<ma-crud :options="crudOptions" :columns="crudColumns" ref="crudRef">
|
||||
<ma-crud :options="crudOptions" :columns="crudColumns" ref="crudRef" @beforeCancel="handleBeforeCancel">
|
||||
<template #ident="{ record }">
|
||||
{{ showType(record) }}
|
||||
</template>
|
||||
@@ -42,94 +42,17 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from "vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import testDemandApi from "@/api/project/testDemand"
|
||||
import { useTreeDataStore } from "@/store"
|
||||
import { ref } from "vue"
|
||||
import commonApi from "@/api/common"
|
||||
import PinYinMatch from "pinyin-match"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
// hooks
|
||||
import useCrudRef from "./hooks/useCrudRef"
|
||||
import useRalateDemand from "./hooks/useRalateDemand"
|
||||
|
||||
const treeDataStore = useTreeDataStore()
|
||||
const route = useRoute()
|
||||
const crudRef = ref()
|
||||
// 根据传参获取key,分别为轮次、设计需求的key
|
||||
const roundNumber = route.query.key.split("-")[0]
|
||||
const dutNumber = route.query.key.split("-")[1]
|
||||
const designDemandNumber = route.query.key.split("-")[2]
|
||||
const projectId = ref(route.query.id)
|
||||
// ~~~~~关联相关变量和函数~~~~~
|
||||
// 定义关联弹窗变量函数
|
||||
const visible = ref(false)
|
||||
const relatedData = ref([])
|
||||
const computedRelatedData = computed(() => {
|
||||
const labelResultList = []
|
||||
options.value.forEach((item) => {
|
||||
if (item.children) {
|
||||
item.children.forEach((child) => {
|
||||
if (relatedData.value.includes(child.value)) {
|
||||
labelResultList.push(child.label)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return labelResultList
|
||||
})
|
||||
// 定义cascader的加载圈
|
||||
const cascaderLoading = ref(false)
|
||||
// 点击关联测试项-button
|
||||
const handleOpenRelationCSX = async () => {
|
||||
// 请求接口获取数据
|
||||
cascaderLoading.value = true
|
||||
visible.value = true
|
||||
// 点击进入时清除关联
|
||||
relatedData.value = []
|
||||
const res = await testDemandApi.getRelatedTestDemand({ id: projectId.value, round: roundNumber })
|
||||
options.value = res.data
|
||||
// 找出本设计需求design对应已关联的测试项
|
||||
const res_exist = await testDemandApi.getExistRelatedTestDemand({
|
||||
project_id: projectId.value,
|
||||
roundNumber,
|
||||
dutNumber,
|
||||
designDemandNumber
|
||||
})
|
||||
relatedData.value = res_exist.data
|
||||
cascaderLoading.value = false
|
||||
}
|
||||
// 点击关联确定按钮
|
||||
const handleRelatedOk = async () => {
|
||||
// 获取级联数据
|
||||
const relationDestItemIds = relatedData.value
|
||||
if (relationDestItemIds.length > 0) {
|
||||
const res = await testDemandApi.solveRelatedTestDemand({
|
||||
data: relationDestItemIds,
|
||||
project_id: projectId.value,
|
||||
roundNumber,
|
||||
dutNumber,
|
||||
designDemandNumber
|
||||
})
|
||||
if (res.code == 200) {
|
||||
Message.success(res.message)
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
const res = await testDemandApi.solveRelatedTestDemand({
|
||||
data: [],
|
||||
project_id: projectId.value,
|
||||
roundNumber,
|
||||
dutNumber,
|
||||
designDemandNumber
|
||||
})
|
||||
if (res.code == 200) {
|
||||
Message.success(res.message)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
// 级联cascade组件options
|
||||
const options = ref([])
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
const { projectId, crudRef, crudOptions, crudColumns, handleBeforeCancel } = useCrudRef()
|
||||
// 关联弹窗、关联的事件处理
|
||||
const { visible, relatedData, options, cascaderLoading, computedRelatedData, handleOpenRelationCSX, handleRelatedOk } =
|
||||
useRalateDemand(projectId)
|
||||
|
||||
// 标识显示字段
|
||||
const testTypeDict = ref([])
|
||||
@@ -147,204 +70,12 @@ const showType = (record) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 () {
|
||||
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 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) {
|
||||
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 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,
|
||||
operationColumn: true,
|
||||
operationColumnAlign: "center",
|
||||
formOption: {
|
||||
width: 1200
|
||||
}
|
||||
})
|
||||
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: "请保证测试类型选择正确",
|
||||
// 这是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,
|
||||
addDefaultValue: "覆盖需求相关功能",
|
||||
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",
|
||||
placeholder: "对应大纲测试项表格的测试项描述",
|
||||
rules: [{ required: true, message: "测试子项描述必填" }]
|
||||
},
|
||||
{
|
||||
title: "条件",
|
||||
dataIndex: "condition",
|
||||
placeholder: "在什么环境和前置条件下"
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "operation",
|
||||
placeholder: "通过xxx操作"
|
||||
},
|
||||
{
|
||||
title: "观察",
|
||||
dataIndex: "observe",
|
||||
placeholder: "查看xxx内容"
|
||||
},
|
||||
{
|
||||
title: "期望",
|
||||
dataIndex: "expect",
|
||||
placeholder: "xxx结果正确"
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
// 暴露给route-view的刷新表格函数
|
||||
const refreshCrudTable = () => {
|
||||
crudRef.value.refresh()
|
||||
}
|
||||
defineExpose({ refreshCrudTable })
|
||||
|
||||
defineOptions({
|
||||
name: "designDemand"
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="ma-content-block lg:flex justify-between p-4">
|
||||
<div class="lg:w-full w-full lg:ml-4 mt-5 lg:mt-0">
|
||||
<!-- CRUD组件 -->
|
||||
<ma-crud :options="crudOptions" :columns="crudColumns" ref="crudRef">
|
||||
<ma-crud :options="crudOptions" :columns="crudColumns" ref="crudRef" @beforeCancel="handleBeforeCancel">
|
||||
<template #ident="{ record }">
|
||||
{{ showType(record) }}
|
||||
</template>
|
||||
@@ -13,11 +13,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import { ref } from "vue"
|
||||
import { ref, getCurrentInstance } from "vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import caseApi from "@/api/project/case"
|
||||
import { useTreeDataStore } from "@/store"
|
||||
import ProblemForm from "@/views/project/case/components/ProblemForm.vue"
|
||||
import { isEqual, cloneDeep } from "lodash"
|
||||
const problemFormRef = ref(null)
|
||||
const title = ref("问题单表单")
|
||||
const treeDataStore = useTreeDataStore()
|
||||
@@ -34,7 +35,29 @@ const showType = (record) => {
|
||||
return "YL-" + record.testType + "-" + record.ident + "-" + key_string.toString().padStart(3, "0")
|
||||
}
|
||||
|
||||
// crud设置
|
||||
// crud设置以及是否保留step数据事件函数
|
||||
const app = getCurrentInstance().appContext.config.globalProperties
|
||||
let beforeFormStep = undefined
|
||||
const handleBeforeCancel = () => {
|
||||
if (!beforeFormStep) {
|
||||
return
|
||||
}
|
||||
console.log(beforeFormStep)
|
||||
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: "新增用例" },
|
||||
@@ -44,6 +67,9 @@ const crudOptions = ref({
|
||||
isDbClickEdit: false, // 关闭双击编辑
|
||||
// 处理新增删除后树状图显示
|
||||
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]
|
||||
@@ -57,6 +83,9 @@ const crudOptions = ref({
|
||||
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]
|
||||
|
||||
Reference in New Issue
Block a user