000
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
<script setup></script>
|
||||
|
||||
<template>
|
||||
<a-config-provider>
|
||||
<router-view />
|
||||
</a-config-provider>
|
||||
</template>
|
||||
<script setup></script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -71,4 +71,17 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 根据项目id查询项目->看板的所有信息
|
||||
* @returns 返回看板所有信息
|
||||
*/
|
||||
getBoardInfo(projectId) {
|
||||
return request({
|
||||
url: `/testmanage/project/board`,
|
||||
method: "get",
|
||||
params: {
|
||||
id: projectId
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
5
cdTMP/src/assets/funcImg/loading.svg
Normal file
5
cdTMP/src/assets/funcImg/loading.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="50px" height="50px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50" xml:space="preserve">
|
||||
<path fill="#409eff" d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z" transform="rotate(275.098 25 25)">
|
||||
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur=".8s" repeatCount="indefinite"></animateTransform>
|
||||
</path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 617 B |
@@ -1,12 +1,3 @@
|
||||
<!--
|
||||
- MineAdmin is committed to providing solutions for quickly building web applications
|
||||
- Please view the LICENSE file that was distributed with this source code,
|
||||
- For the full copyright and license information.
|
||||
- Thank you very much for using MineAdmin.
|
||||
-
|
||||
- @Author X.Mo<root@imoi.cn>
|
||||
- @Link https://gitee.com/xmo/mineadmin-vue
|
||||
-->
|
||||
<template>
|
||||
<component
|
||||
:is="componentName"
|
||||
@@ -16,6 +7,7 @@
|
||||
ok-text="保存"
|
||||
cancel-text="关闭"
|
||||
draggable
|
||||
:mask-closable="options.formOption.mask"
|
||||
:width="options.formOption.width"
|
||||
:fullscreen="options.formOption.isFull || false"
|
||||
unmount-on-close
|
||||
|
||||
@@ -5,13 +5,20 @@
|
||||
unmount-on-close
|
||||
@cancel="modal.cancel"
|
||||
:width="width"
|
||||
draggable
|
||||
:on-before-cancel="modal.customCancel"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<template #title>
|
||||
{{ prop.title }}
|
||||
</template>
|
||||
<slot name="body"></slot>
|
||||
<ma-form ref="maFormRef" :columns="prop.column" v-model="form" :options="{ ...options, showButtons: false }" />
|
||||
<ma-form
|
||||
ref="maFormRef"
|
||||
:columns="prop.column"
|
||||
v-model="form"
|
||||
:options="{ ...options, showButtons: false }"
|
||||
></ma-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
@@ -60,7 +67,7 @@ const modal = reactive({
|
||||
return prop.submit(form._rawValue)
|
||||
},
|
||||
customCancel() {
|
||||
if(prop.customCancel){
|
||||
if (prop.customCancel) {
|
||||
return prop.customCancel()
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import auth from "./auth/index"
|
||||
import role from "./role/index"
|
||||
import copy from "./copy/index"
|
||||
import loading from "./loading/index"
|
||||
|
||||
export default {
|
||||
install(Vue) {
|
||||
Vue.directive("auth", auth)
|
||||
Vue.directive("role", role)
|
||||
Vue.directive("copy", copy)
|
||||
Vue.directive("loading", loading)
|
||||
}
|
||||
}
|
||||
|
||||
34
cdTMP/src/directives/loading/index.js
Normal file
34
cdTMP/src/directives/loading/index.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// 用于远程加载数据时候显示加载中
|
||||
import imgUrl from "@/assets/funcImg/loading.svg"
|
||||
import styles from "./loading.module.less"
|
||||
|
||||
// 创建img元素
|
||||
function createImg() {
|
||||
const imgEle = document.createElement("img")
|
||||
// 给个html自定义属性
|
||||
imgEle.dataset.role = "loading"
|
||||
imgEle.src = imgUrl
|
||||
imgEle.classList.add(styles.img)
|
||||
imgEle.title = "loading element"
|
||||
return imgEle
|
||||
}
|
||||
|
||||
// 通过el找到img元素-在update钩子的时候,在update时已经创建了img元素了
|
||||
function getImgElement(element) {
|
||||
return element.querySelector("img[data-role=loading]")
|
||||
}
|
||||
|
||||
export default function (el, binding) {
|
||||
const img = getImgElement(el)
|
||||
if (binding.value) {
|
||||
// 这里要判断是否有元素,否则在update钩子会创建多个!!!
|
||||
if (!img) {
|
||||
const img = createImg()
|
||||
el.appendChild(img)
|
||||
}
|
||||
} else {
|
||||
if (img) {
|
||||
img.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
6
cdTMP/src/directives/loading/loading.module.less
Normal file
6
cdTMP/src/directives/loading/loading.module.less
Normal file
@@ -0,0 +1,6 @@
|
||||
.img {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
23
cdTMP/src/hooks/fetchData.js
Normal file
23
cdTMP/src/hooks/fetchData.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ref } from "vue"
|
||||
|
||||
/**
|
||||
* 该hook传入一个远程数据储存默认值,以及请求远程数据的函数
|
||||
*/
|
||||
const useFetchData = (defaultValue = {}, fetDataFunc) => {
|
||||
const loadingData = ref(defaultValue) // 远程请求的数据
|
||||
const isDataLoading = ref(false)
|
||||
// 该hook需要组件里面提供 -> fetchData的函数,返回远程请求数据的东西
|
||||
/// 相当于created
|
||||
async function fetchOrigin() {
|
||||
isDataLoading.value = true
|
||||
const res = await fetDataFunc()
|
||||
loadingData.value = res.data
|
||||
isDataLoading.value = false
|
||||
}
|
||||
fetchOrigin()
|
||||
return {
|
||||
loadingData,
|
||||
isDataLoading
|
||||
}
|
||||
}
|
||||
export default useFetchData
|
||||
@@ -146,7 +146,9 @@ const paddingStyle = computed(() => {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.work-area {
|
||||
position: relative; // 注意这个是改变v-loading这些东西
|
||||
}
|
||||
.menu-wrapper {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
|
||||
@@ -134,7 +134,8 @@
|
||||
:options="roundOption"
|
||||
width="800px"
|
||||
:submit="handleRoundSubmit"
|
||||
></ma-form-modal>
|
||||
>
|
||||
</ma-form-modal>
|
||||
<!-- 如果没有第一轮的SO_dut则弹窗 -->
|
||||
<ma-form-modal
|
||||
ref="soDutFormRef"
|
||||
@@ -143,7 +144,12 @@
|
||||
width="800px"
|
||||
:submit="handleSoDutSubmit"
|
||||
:custom-cancel="handleSoDutCancel"
|
||||
></ma-form-modal>
|
||||
cancelText="返回项目页面"
|
||||
:cancel-button-props="{ status: 'warning' }"
|
||||
:closable="false"
|
||||
:mask-closable="false"
|
||||
>
|
||||
</ma-form-modal>
|
||||
<Progress
|
||||
:visible="visible"
|
||||
:isComplete="isComplete"
|
||||
@@ -158,15 +164,6 @@
|
||||
alignPoint
|
||||
:style="{ display: 'block' }"
|
||||
>
|
||||
<div
|
||||
:style="{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '300px',
|
||||
backgroundColor: 'var(--color-fill-2)'
|
||||
}"
|
||||
></div>
|
||||
<template #content>
|
||||
<a-dgroup title="执行操作">
|
||||
<a-doption @click="handleDoptionClickGreateCases">
|
||||
@@ -369,8 +366,8 @@ const handleSoDutSubmit = async (data) => {
|
||||
}
|
||||
// ~~~~定义弹出a-form-modal的cancel方法-返回false则无法关闭弹窗~~~~
|
||||
const handleSoDutCancel = () => {
|
||||
Notification.error("必须按要求添加源代码信息,无法关闭!")
|
||||
return false
|
||||
Notification.error("必须按要求添加源代码信息,返回项目列表页面!")
|
||||
router.replace({ name: "Projmanage" })
|
||||
}
|
||||
// 初始化树状数据
|
||||
// so_dut弹窗ref对象
|
||||
@@ -686,7 +683,6 @@ const roundColumn = ref([
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
formType: "card",
|
||||
title: "极端工况信息",
|
||||
@@ -775,7 +771,9 @@ const soDutColumn = ref([
|
||||
{
|
||||
title: "用户标识",
|
||||
dataIndex: "userRef",
|
||||
placeholder: "请输入用户标识"
|
||||
placeholder: "请输入用户标识",
|
||||
help: "客户使用的标识",
|
||||
rules: [{ required: true, message: "用户标识为客户的标识,必填,可随意填写后面再修改" }]
|
||||
},
|
||||
{
|
||||
title: "单位",
|
||||
@@ -866,7 +864,7 @@ const handleProblemShowClick = () => {
|
||||
const handleDoptionClickGreateCases = async () => {
|
||||
// 将project_id加入参数
|
||||
rightClickNode.project_id = projectId.value
|
||||
const res = await caseApi.createByDemand(rightClickNode)
|
||||
await caseApi.createByDemand(rightClickNode)
|
||||
routeViewRef.value.refresh()
|
||||
}
|
||||
/// 复制modal级联选择器的选项
|
||||
|
||||
@@ -24,7 +24,8 @@ app.use(ArcoVueIcon)
|
||||
app.use(router)
|
||||
app.use(pinia)
|
||||
app.use(globalComponents)
|
||||
// app.use(directive)
|
||||
import directives from "@/directives"
|
||||
app.use(directives)
|
||||
|
||||
// 注册ma-icon图标
|
||||
const modules = import.meta.glob("./assets/ma-icons/*.vue", { eager: true })
|
||||
|
||||
@@ -98,10 +98,9 @@ const router = createRouter({
|
||||
locale: "问题单详情",
|
||||
icon: "icon-arrow-right"
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// 后台管理的路由以及404和重定向路由
|
||||
...appRoutes,
|
||||
REDIRECT_MAIN,
|
||||
|
||||
@@ -21,6 +21,21 @@ const TESTMANAGE = {
|
||||
locale: "项目管理",
|
||||
icon: "icon-folder"
|
||||
}
|
||||
},
|
||||
// 二级路由(非三级路由,但是想办法把左侧菜单删除)
|
||||
{
|
||||
path: "/projBoard/:projectId",
|
||||
name: "projBoard",
|
||||
component: () => import("@/views/testmanage/projBoard/index.vue"),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
roles: ["*"],
|
||||
locale: "项目看板",
|
||||
icon: "icon-folder",
|
||||
hideInMenu: true,
|
||||
ignoreCache: false,
|
||||
noAffix: true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<a-modal v-model:visible="visible" fullscreen :footer="false">
|
||||
<template #title>维护数据字典 →【{{ currentRow.name }}】</template>
|
||||
<!-- crud组件 -->
|
||||
<div class="lg:w-full w-full lg:ml-4 mt-5 lg:mt-0">
|
||||
<div class="lg:w-full w-full lg:mt-0">
|
||||
<ma-crud :options="crudOptions" :columns="columns" ref="crudRef">
|
||||
<!-- 排序列 -->
|
||||
<template #sort="{ record }">
|
||||
@@ -93,6 +93,7 @@ const crudOptions = ref({
|
||||
operationColumn: true,
|
||||
operationWidth: 160,
|
||||
operationColumnAlign: "center",
|
||||
showTools: false,
|
||||
beforeAdd: (form) => {
|
||||
form.id = currentRow.value?.id
|
||||
},
|
||||
@@ -183,7 +184,7 @@ const columns = ref([
|
||||
dataIndex: "source",
|
||||
align: "center",
|
||||
search: false,
|
||||
placeholder: "如果不是标准则不填",
|
||||
placeholder: "如果不是标准则不填"
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
@@ -60,7 +60,8 @@ const crudOptions = ref({
|
||||
rowSelection: { showCheckedAll: true },
|
||||
searchColNumber: 4,
|
||||
tablePagination: false,
|
||||
operationColumn: true
|
||||
operationColumn: true,
|
||||
showTools:false,
|
||||
})
|
||||
|
||||
const crudColumns = ref([
|
||||
|
||||
@@ -79,7 +79,7 @@ const crudOptions = ref({
|
||||
${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} >
|
||||
${td[round_key].children[dut_key].children[design_key].children[test_key].children[case_key].title} > 用例-`
|
||||
${td[round_key].children[dut_key].children[design_key].children[test_key].children[case_key].title} > 问题单-`
|
||||
return true
|
||||
},
|
||||
beforeOpenEdit: function (record) {
|
||||
|
||||
@@ -249,11 +249,12 @@ const crudColumns = ref([
|
||||
align: "center",
|
||||
formType: "select",
|
||||
sortable: { sortDirections: ["ascend", "descend"] },
|
||||
addDefaultValue: "3",
|
||||
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)
|
||||
@@ -261,7 +262,7 @@ const crudColumns = ref([
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "测试手段",
|
||||
@@ -299,7 +300,9 @@ const crudColumns = ref([
|
||||
const subItemFormData = crudRef.value.getFormData().testContent
|
||||
// 取出充分性条件字段字符串
|
||||
const mapRes = subItemFormData.map((subItem) => subItem.subName)
|
||||
crudRef.value.getFormData().adequacy = `测试用例覆盖${mapRes.join('、')}子项要求的全部内容。\n所有用例执行完毕,对于未执行的用例说明未执行原因。`
|
||||
crudRef.value.getFormData().adequacy = `测试用例覆盖${mapRes.join(
|
||||
"、"
|
||||
)}子项要求的全部内容。\n所有用例执行完毕,对于未执行的用例说明未执行原因。`
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -130,17 +130,17 @@ const crudColumns = ref([
|
||||
width: 120,
|
||||
dataIndex: "ident",
|
||||
search: true,
|
||||
commonRules: [{ required: true, message: "标识是必填" }],
|
||||
validateTrigger: "blur",
|
||||
placeholder: "请输入文档中设计需求的标识"
|
||||
placeholder: "请输入文档中设计需求的标识",
|
||||
help:'若不知道则填"无"或不填'
|
||||
},
|
||||
{
|
||||
title: "需求名称",
|
||||
title: "设需名称",
|
||||
align: "center",
|
||||
width: 150,
|
||||
dataIndex: "name",
|
||||
search: true,
|
||||
commonRules: [{ required: true, message: "需求名称是必填" }],
|
||||
commonRules: [{ required: true, message: "设计需求名称是必填" }],
|
||||
validateTrigger: "blur"
|
||||
},
|
||||
{
|
||||
@@ -148,7 +148,8 @@ const crudColumns = ref([
|
||||
align: "center",
|
||||
width: 150,
|
||||
dataIndex: "chapter",
|
||||
search: true
|
||||
search: true,
|
||||
help:'若为隐含需求则填"/"'
|
||||
},
|
||||
{
|
||||
title: "需求类型",
|
||||
|
||||
@@ -71,7 +71,8 @@ const crudOptions = ref({
|
||||
operationColumnAlign: "center",
|
||||
formOption: {
|
||||
viewType: "drawer",
|
||||
width: 600
|
||||
width: 600,
|
||||
mask: false
|
||||
}
|
||||
})
|
||||
|
||||
@@ -118,7 +119,8 @@ const crudColumns = ref([
|
||||
comment_line: { display: true },
|
||||
total_code_line: { display: true },
|
||||
total_line: { display: true },
|
||||
comment_percent: { display: true }
|
||||
comment_percent: { display: true },
|
||||
release_date: { display: false }
|
||||
}
|
||||
} else {
|
||||
// 其他数据清除
|
||||
@@ -129,7 +131,8 @@ const crudColumns = ref([
|
||||
comment_line: { display: false },
|
||||
total_code_line: { display: false },
|
||||
total_line: { display: false },
|
||||
comment_percent: { display: false }
|
||||
comment_percent: { display: false },
|
||||
release_date: { display: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,7 +143,7 @@ const crudColumns = ref([
|
||||
align: "center",
|
||||
dataIndex: "name",
|
||||
search: true,
|
||||
commonRules: [{ required: true, message: "需求名称是必填" }],
|
||||
commonRules: [{ required: true, message: "被测件名称必填" }],
|
||||
validateTrigger: "blur"
|
||||
},
|
||||
{
|
||||
@@ -157,7 +160,8 @@ const crudColumns = ref([
|
||||
dataIndex: "ref",
|
||||
search: true,
|
||||
commonRules: [{ required: true, message: "用户标识或编号必填" }],
|
||||
validateTrigger: "blur"
|
||||
validateTrigger: "blur",
|
||||
help: "客户使用的标识"
|
||||
},
|
||||
{
|
||||
title: "单位",
|
||||
@@ -181,7 +185,8 @@ const crudColumns = ref([
|
||||
align: "center",
|
||||
dataIndex: "black_line",
|
||||
formType: "input-number",
|
||||
commonRules: [{ required: true, message: "空行数必填" }]
|
||||
commonRules: [{ required: true, message: "空行数必填" }],
|
||||
min: 0
|
||||
},
|
||||
{
|
||||
title: "纯代码行",
|
||||
@@ -189,7 +194,8 @@ const crudColumns = ref([
|
||||
align: "center",
|
||||
dataIndex: "code_line",
|
||||
formType: "input-number",
|
||||
commonRules: [{ required: true, message: "纯代码行数必填" }]
|
||||
commonRules: [{ required: true, message: "纯代码行数必填" }],
|
||||
min: 0
|
||||
},
|
||||
{
|
||||
title: "纯注释行",
|
||||
@@ -197,7 +203,8 @@ const crudColumns = ref([
|
||||
align: "center",
|
||||
dataIndex: "comment_line",
|
||||
formType: "input-number",
|
||||
commonRules: [{ required: true, message: "纯注释行数必填" }]
|
||||
commonRules: [{ required: true, message: "纯注释行数必填" }],
|
||||
min: 0
|
||||
},
|
||||
{
|
||||
title: "混合行",
|
||||
@@ -205,7 +212,9 @@ const crudColumns = ref([
|
||||
align: "center",
|
||||
dataIndex: "mix_line",
|
||||
formType: "input-number",
|
||||
commonRules: [{ required: true, message: "混合行数必填" }]
|
||||
help: "混合行是指:代码中一行即包含代码也包含注释",
|
||||
commonRules: [{ required: true, message: "混合行数必填" }],
|
||||
min: 0
|
||||
},
|
||||
{
|
||||
title: "注释率 %",
|
||||
@@ -248,7 +257,7 @@ const crudColumns = ref([
|
||||
)
|
||||
}
|
||||
},
|
||||
// 注意这个是个创新点
|
||||
// 字段交互控制
|
||||
control(value, data) {
|
||||
data.comment_percent = (
|
||||
(parseFloat(data.comment_line) + parseFloat(data.mix_line)) /
|
||||
|
||||
105
cdTMP/src/views/testmanage/projBoard/cpns/RoundInfo.vue
Normal file
105
cdTMP/src/views/testmanage/projBoard/cpns/RoundInfo.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div class="round-info-container">
|
||||
<div class="ma-content-block rounded-sm flex-column justify-between w-full p-3 bg-color">
|
||||
<div class="title">{{ props.data.name }}信息</div>
|
||||
<div class="info-list">
|
||||
<a-list :gridProps="{ gutter: 0, span: 6 }" class="list-container">
|
||||
<template #header><div class="header">设计需求下面测试项/用例统计信息</div></template>
|
||||
<a-list-item v-for="(item, index) in props.data.desings" :key="index">
|
||||
<a-list-item-meta class="meta" :title="`${item.name}`"></a-list-item-meta>
|
||||
<div class="item-count">
|
||||
测试项数 : <span class="count">{{ item.demand_count }}</span>
|
||||
</div>
|
||||
<div class="item-count">
|
||||
用例数 : <span class="count">{{ item.case_count }}</span>
|
||||
</div>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
<a-list class="list-container">
|
||||
<template #header><div class="header">测试类型统计信息</div></template>
|
||||
<a-table
|
||||
:bordered="false"
|
||||
:data="resolveData"
|
||||
:columns="columns"
|
||||
size="small"
|
||||
:pagination="false"
|
||||
></a-table>
|
||||
</a-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from "vue"
|
||||
import columns from "./tableColumn.js"
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
const resolveData = computed(() => {
|
||||
let resData = []
|
||||
let res = props.data.method_demand
|
||||
Object.keys(res).forEach((key) => {
|
||||
const value = res[key]
|
||||
resData.push({
|
||||
name: key,
|
||||
demand_count: value,
|
||||
case_count: 0
|
||||
})
|
||||
})
|
||||
let res2 = props.data.method_case
|
||||
Object.keys(res2).forEach((key) => {
|
||||
const value = res2[key]
|
||||
resData.forEach((item) => {
|
||||
if (item.name === key) {
|
||||
item.case_count = value
|
||||
}
|
||||
})
|
||||
})
|
||||
return resData
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.round-info-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.title {
|
||||
margin: 10px;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.count {
|
||||
font-weight: 700;
|
||||
}
|
||||
.meta {
|
||||
font-size: 15px;
|
||||
width: 80%;
|
||||
border-bottom: 1px dashed var(--color-text-4);
|
||||
margin-bottom: 2px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.list-container {
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
.info-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
.header {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
</style>
|
||||
67
cdTMP/src/views/testmanage/projBoard/cpns/TimeLine.vue
Normal file
67
cdTMP/src/views/testmanage/projBoard/cpns/TimeLine.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="time-line-container">
|
||||
<div class="ma-content-block rounded-sm flex-column justify-between w-full p-3 bg-color">
|
||||
<div class="title">填写的项目时间轴</div>
|
||||
<a-timeline direction="horizontal" class="timeline" mode="alternate">
|
||||
<a-timeline-item :label="pInfo.time_line.start_time">
|
||||
<a-row :style="{ display: 'inline-flex', alignItems: 'center' }">
|
||||
<div>开始时间</div>
|
||||
</a-row>
|
||||
</a-timeline-item>
|
||||
<a-timeline-item
|
||||
v-for="(item, index) in pInfo.time_line.round_time"
|
||||
:key="index"
|
||||
:label="`结束时间 : ${item.end}`"
|
||||
>
|
||||
<a-col>
|
||||
<div>{{ item.name }}</div>
|
||||
<div class="a-col-title">开始时间 : {{ item.start }}</div>
|
||||
</a-col>
|
||||
</a-timeline-item>
|
||||
<a-timeline-item :label="pInfo.time_line.end_time">
|
||||
<a-row :style="{ display: 'inline-flex', alignItems: 'center' }">
|
||||
<div>结束时间</div>
|
||||
</a-row>
|
||||
</a-timeline-item>
|
||||
<div class="info">
|
||||
<a-alert>测试人员填写的项目开始时间、结束时间、轮次时间均会影响生成文档的时间!</a-alert>
|
||||
</div>
|
||||
</a-timeline>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 1.定义props
|
||||
const props = defineProps({
|
||||
pInfo: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.title {
|
||||
margin: 10px;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.timeline {
|
||||
position: relative;
|
||||
padding: 50px;
|
||||
width: 100%;
|
||||
.info {
|
||||
width: 180px;
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 1rem;
|
||||
}
|
||||
}
|
||||
.a-col-title {
|
||||
font-size: 12px;
|
||||
margin-bottom: -5px;
|
||||
margin-top: 5px;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
</style>
|
||||
89
cdTMP/src/views/testmanage/projBoard/cpns/Title.vue
Normal file
89
cdTMP/src/views/testmanage/projBoard/cpns/Title.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div class="title-container">
|
||||
<div class="ma-content-block rounded-sm flex-col justify-between w-full p-3 bg-color">
|
||||
<a-page-header
|
||||
@back="handleBackClick"
|
||||
:style="{ background: 'var(--color-bg-2)' }"
|
||||
:title="props.pInfo.ident"
|
||||
>
|
||||
<template #subtitle>
|
||||
<a-space>
|
||||
<span>{{ props.pInfo.name }}</span>
|
||||
<a-tag color="red" size="small">{{ props.pInfo.step }}</a-tag>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-page-header>
|
||||
<div class="title">基本信息</div>
|
||||
<div class="item-container">
|
||||
<a-card
|
||||
class="item"
|
||||
v-for="(val, key) in pInfo.title_info"
|
||||
:style="{ width: '360px' }"
|
||||
:title="key"
|
||||
:key="key"
|
||||
hoverable
|
||||
>
|
||||
<ul class="li-container">
|
||||
<li v-for="(v, k) in val" :key="k">
|
||||
<div class="key">{{ k }}:</div>
|
||||
<div class="value">{{ v }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</a-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRoute, useRouter } from "vue-router"
|
||||
const router = useRouter()
|
||||
|
||||
// 1.头部-点击返回
|
||||
const handleBackClick = () => {
|
||||
router.go(-1)
|
||||
}
|
||||
// 2.定义props
|
||||
const props = defineProps({
|
||||
pInfo: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.arco-page-header-main) {
|
||||
align-items: center;
|
||||
}
|
||||
.item-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
.item {
|
||||
height: 11rem;
|
||||
.li-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
li {
|
||||
display: flex;
|
||||
line-height: 1.5;
|
||||
gap: 5px;
|
||||
.value {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.title {
|
||||
margin: 10px;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
}
|
||||
</style>
|
||||
18
cdTMP/src/views/testmanage/projBoard/cpns/tableColumn.js
Normal file
18
cdTMP/src/views/testmanage/projBoard/cpns/tableColumn.js
Normal file
@@ -0,0 +1,18 @@
|
||||
export default [
|
||||
{
|
||||
title: "测试类型",
|
||||
dataIndex: "name",
|
||||
ellipsis: true,
|
||||
align: "center"
|
||||
},
|
||||
{
|
||||
title: "测试项数量",
|
||||
dataIndex: "demand_count",
|
||||
align: "center"
|
||||
},
|
||||
{
|
||||
title: "用例数量",
|
||||
dataIndex: "case_count",
|
||||
align: "center"
|
||||
}
|
||||
]
|
||||
33
cdTMP/src/views/testmanage/projBoard/index.vue
Normal file
33
cdTMP/src/views/testmanage/projBoard/index.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="proj-board-container" v-loading="isDataLoading">
|
||||
<a-layout-content class="flex flex-col gap-2" v-if="!isDataLoading">
|
||||
<!-- 返回前面一页的按钮,以及项目整体情况 -->
|
||||
<Title :pInfo="loadingData"></Title>
|
||||
<!-- 时间线显示项目情况 -->
|
||||
<time-line :pInfo="loadingData"></time-line>
|
||||
<!-- 以轮次为合集展示需求下面的测试项数、用例数,测试类型下面测试项和用例数量 -->
|
||||
<round-info v-for="item in loadingData.statistics" :data="item"></round-info>
|
||||
</a-layout-content>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Title from "./cpns/Title.vue"
|
||||
import TimeLine from "./cpns/TimeLine.vue"
|
||||
import projectApi from "@/api/project/project"
|
||||
import { useRoute } from "vue-router"
|
||||
import RoundInfo from "./cpns/RoundInfo.vue"
|
||||
const route = useRoute()
|
||||
// hooks
|
||||
import useFetchData from "@/hooks/fetchData"
|
||||
const fetchData = async () => {
|
||||
return projectApi.getBoardInfo(route.params.projectId)
|
||||
}
|
||||
const { loadingData, isDataLoading } = useFetchData({}, fetchData)
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ma-content-block) {
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
</style>
|
||||
@@ -2,7 +2,13 @@
|
||||
<!-- 描述列表组件 -->
|
||||
<a-modal width="1000px" v-model:visible="visible" :footer="false">
|
||||
<template #title>项目名称:{{ previewRecord.name }}</template>
|
||||
<ma-info :columns="props.columns" :data="previewRecord" :column="1" size="mini"></ma-info>
|
||||
<ma-info
|
||||
class="my-custom-class"
|
||||
:columns="props.columns"
|
||||
:data="previewRecord"
|
||||
:column="1"
|
||||
size="mini"
|
||||
></ma-info>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
@@ -26,4 +32,13 @@ defineExpose({ open })
|
||||
// MA-INFO的columns
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
<style lang="less" scoped>
|
||||
.my-custom-class {
|
||||
:deep(.arco-space-horizontal) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
:deep(.arco-space-item){
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
工作区
|
||||
</a-button>
|
||||
<a-link @click="previewRef.open(record)"><icon-eye />预览</a-link>
|
||||
<a-link @click="handleBoardClick(record)"><icon-dashboard />项目看板</a-link>
|
||||
</template>
|
||||
</ma-crud>
|
||||
</div>
|
||||
@@ -328,6 +329,15 @@ const createWtdItem = async (record) => {
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// 1.跳转到项目看板页面
|
||||
const handleBoardClick = (record) => {
|
||||
router.push({
|
||||
name: "projBoard",
|
||||
params: {
|
||||
projectId: record.id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// CRUD-OPTIONS
|
||||
const crudRef = ref()
|
||||
@@ -343,7 +353,7 @@ const crudOptions = ref({
|
||||
operationWidth: 500,
|
||||
showIndex: false,
|
||||
showTools: false,
|
||||
operationColumnWidth: 220, // 操作列宽度
|
||||
operationColumnWidth: 280, // 操作列宽度
|
||||
operationColumnAlign: "center", // 操作列对齐方式
|
||||
// 处理弹窗的title
|
||||
beforeOpenAdd: function () {
|
||||
@@ -386,30 +396,27 @@ const crudOptions = ref({
|
||||
{ span: 12, formList: [{ dataIndex: "member" }] },
|
||||
{ span: 6, formList: [{ dataIndex: "soft_type" }] },
|
||||
{ span: 6, formList: [{ dataIndex: "devplant" }] },
|
||||
{ span: 24, formList: [{ dataIndex: "abbreviation" }] },
|
||||
{ span: 8, formList: [{ dataIndex: "quality_person" }] },
|
||||
{ span: 8, formList: [{ dataIndex: "vise_person" }] },
|
||||
{ span: 8, formList: [{ dataIndex: "config_person" }] }
|
||||
{ span: 6, formList: [{ dataIndex: "abbreviation" }] },
|
||||
{ span: 6, formList: [{ dataIndex: "quality_person" }] },
|
||||
{ span: 6, formList: [{ dataIndex: "vise_person" }] },
|
||||
{ span: 6, formList: [{ dataIndex: "config_person" }] }
|
||||
]
|
||||
},
|
||||
{
|
||||
formType: "grid",
|
||||
cols: [{ span: 24, formList: [{ dataIndex: "security_level" }] }]
|
||||
},
|
||||
{
|
||||
formType: "grid",
|
||||
cols: [
|
||||
{ span: 12, formList: [{ dataIndex: "test_level" }] },
|
||||
{ span: 6, formList: [{ dataIndex: "security_level" }] },
|
||||
{ span: 6, formList: [{ dataIndex: "language" }] },
|
||||
{ span: 12, formList: [{ dataIndex: "plant_type" }] }
|
||||
]
|
||||
},
|
||||
{
|
||||
formType: "grid",
|
||||
cols: [{ span: 24, formList: [{ dataIndex: "report_type" }] }]
|
||||
cols: [{ span: 24, formList: [{ dataIndex: "test_level" }] }]
|
||||
},
|
||||
{
|
||||
formType: "grid",
|
||||
cols: [{ span: 24, formList: [{ dataIndex: "language" }] }]
|
||||
cols: [{ span: 24, formList: [{ dataIndex: "report_type" }] }]
|
||||
},
|
||||
{
|
||||
formType: "grid",
|
||||
@@ -484,6 +491,7 @@ const crudColumns = ref([
|
||||
},
|
||||
{
|
||||
title: "项目名称",
|
||||
width: 110,
|
||||
dataIndex: "name",
|
||||
search: true,
|
||||
commonRules: [{ required: true, message: "名称是必填" }]
|
||||
@@ -491,7 +499,7 @@ const crudColumns = ref([
|
||||
{ title: "工程型号", dataIndex: "engin_model", hide: true },
|
||||
{ title: "分系统", dataIndex: "section_system", hide: true },
|
||||
{ title: "子系统", dataIndex: "sub_system", hide: true },
|
||||
{ title: "设备", dataIndex: "device", hide: true },
|
||||
{ title: "设备名称", dataIndex: "device", hide: true },
|
||||
{
|
||||
title: "开始日期",
|
||||
dataIndex: "beginTime",
|
||||
@@ -502,7 +510,7 @@ const crudColumns = ref([
|
||||
title: "结束时间",
|
||||
dataIndex: "endTime",
|
||||
formType: "date",
|
||||
extra: "注意:开始时间和结束时间影响大纲、报告多个时间,谨慎填写",
|
||||
extra: "注意:结束时间需要晚于最后一轮结束时间",
|
||||
commonRules: [
|
||||
{
|
||||
required: true,
|
||||
@@ -626,7 +634,7 @@ const crudColumns = ref([
|
||||
title: "测试级别",
|
||||
dataIndex: "test_level",
|
||||
commonRules: [{ required: true, message: "请至少选择一个测试级别" }],
|
||||
addDefaultValue: ["6"],
|
||||
addDefaultValue: ["4"],
|
||||
hide: true,
|
||||
formType: "checkbox",
|
||||
dict: { name: "test_level", props: { label: "title", value: "key" } }
|
||||
@@ -643,7 +651,7 @@ const crudColumns = ref([
|
||||
{
|
||||
title: "报告类型",
|
||||
dataIndex: "report_type",
|
||||
addDefaultValue: "1",
|
||||
addDefaultValue: "9",
|
||||
search: true,
|
||||
commonRules: [{ required: true, message: "报告类型必填" }],
|
||||
// 字典-report_type
|
||||
@@ -656,16 +664,18 @@ const crudColumns = ref([
|
||||
addDefaultValue: ["1"],
|
||||
commonRules: [{ required: true, message: "请至少选择一个" }],
|
||||
hide: true,
|
||||
formType: "checkbox",
|
||||
formType: "select",
|
||||
multiple: true,
|
||||
dict: { name: "language", props: { label: "title", value: "key" } }
|
||||
},
|
||||
{
|
||||
title: "依据标准",
|
||||
dataIndex: "standard",
|
||||
addDefaultValue: ["1"],
|
||||
addDefaultValue: ["1", "2", "3", "4", "9"],
|
||||
commonRules: [{ required: true, message: "请至少选择一个" }],
|
||||
hide: true,
|
||||
formType: "checkbox",
|
||||
multiple: true,
|
||||
formType: "select",
|
||||
dict: { name: "standard", props: { label: "title", value: "key" } }
|
||||
},
|
||||
{
|
||||
@@ -681,21 +691,27 @@ const crudColumns = ref([
|
||||
title: "联系人",
|
||||
dataIndex: "entrust_contact",
|
||||
hide: true,
|
||||
rules: [{ required: true, message: "联系人必填" }]
|
||||
commonRules: [{ required: true, message: "联系人必填" }]
|
||||
},
|
||||
{
|
||||
formType: "input",
|
||||
title: "联系电话",
|
||||
maxLength: 11,
|
||||
dataIndex: "entrust_contact_phone",
|
||||
hide: true,
|
||||
rules: [{ required: true, message: "联系电话必填" }]
|
||||
commonRules: [
|
||||
{ required: true, message: "联系电话必填" },
|
||||
{
|
||||
match: /^1[3456789]\d{9}$/,
|
||||
message: "电话号码格式错误"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
formType: "input",
|
||||
title: "电子邮箱",
|
||||
dataIndex: "entrust_email",
|
||||
hide: true,
|
||||
rules: [{ required: true, message: "电子邮箱必填" }]
|
||||
hide: true
|
||||
},
|
||||
{
|
||||
title: "单位",
|
||||
@@ -710,21 +726,27 @@ const crudColumns = ref([
|
||||
title: "联系人",
|
||||
dataIndex: "dev_contact",
|
||||
hide: true,
|
||||
rules: [{ required: true, message: "联系人必填" }]
|
||||
commonRules: [{ required: true, message: "联系人必填" }]
|
||||
},
|
||||
{
|
||||
formType: "input",
|
||||
title: "联系电话",
|
||||
maxLength: 11,
|
||||
dataIndex: "dev_contact_phone",
|
||||
hide: true,
|
||||
rules: [{ required: true, message: "联系电话必填" }]
|
||||
commonRules: [
|
||||
{ required: true, message: "联系电话必填" },
|
||||
{
|
||||
match: /^1[3456789]\d{9}$/,
|
||||
message: "电话号码格式错误"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
formType: "input",
|
||||
title: "电子邮箱",
|
||||
dataIndex: "dev_email",
|
||||
hide: true,
|
||||
rules: [{ required: true, message: "电子邮箱必填" }]
|
||||
hide: true
|
||||
},
|
||||
{
|
||||
title: "单位",
|
||||
@@ -739,21 +761,27 @@ const crudColumns = ref([
|
||||
title: "联系人",
|
||||
dataIndex: "test_contact",
|
||||
hide: true,
|
||||
rules: [{ required: true, message: "联系人必填" }]
|
||||
commonRules: [{ required: true, message: "联系人必填" }]
|
||||
},
|
||||
{
|
||||
formType: "input",
|
||||
title: "联系电话",
|
||||
dataIndex: "test_contact_phone",
|
||||
hide: true,
|
||||
rules: [{ required: true, message: "联系电话必填" }]
|
||||
maxLength: 11,
|
||||
commonRules: [
|
||||
{ required: true, message: "联系电话必填" },
|
||||
{
|
||||
match: /^1[3456789]\d{9}$/,
|
||||
message: "电话号码格式错误"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
formType: "input",
|
||||
title: "电子邮箱",
|
||||
dataIndex: "test_email",
|
||||
hide: true,
|
||||
rules: [{ required: true, message: "电子邮箱必填" }]
|
||||
hide: true
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
|
||||
Reference in New Issue
Block a user