feat: 高级筛选&缺陷管理基础逻辑
This commit is contained in:
parent
a93aa618c3
commit
1ecf35b325
|
@ -0,0 +1,42 @@
|
|||
import MSR from '@/api/http/index';
|
||||
import * as bugURL from '@/api/requrls/bug-management';
|
||||
|
||||
import { BugListItem } from '@/models/bug-management';
|
||||
import { CommonList, TableQueryParams } from '@/models/common';
|
||||
|
||||
/**
|
||||
* 表格的查询
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
export function getBugList(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<BugListItem>>({ url: bugURL.postTableListUrl, data });
|
||||
}
|
||||
|
||||
export function updateBug(data: TableQueryParams) {
|
||||
return MSR.post({ url: bugURL.postUpdateBugUrl, data });
|
||||
}
|
||||
|
||||
export function updateBatchBug(data: TableQueryParams) {
|
||||
return MSR.post({ url: bugURL.postBatchUpdateBugUrl, data });
|
||||
}
|
||||
|
||||
export function createBug(data: TableQueryParams) {
|
||||
return MSR.post({ url: bugURL.postCreateBugUrl, data });
|
||||
}
|
||||
|
||||
export function deleteBug(data: TableQueryParams) {
|
||||
return MSR.get({ url: bugURL.getDeleteBugUrl, data });
|
||||
}
|
||||
|
||||
export function deleteBatchBug(data: TableQueryParams) {
|
||||
return MSR.post({ url: bugURL.postBatchDeleteBugUrl, data });
|
||||
}
|
||||
|
||||
export function getTemplageOption(data: TableQueryParams) {
|
||||
return MSR.get({ url: bugURL.getTemplageOption, data });
|
||||
}
|
||||
|
||||
export function getTemplateById(data: TableQueryParams) {
|
||||
return MSR.get({ url: bugURL.getTemplateUrl, data });
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
export const postTableListUrl = '/bug/page';
|
||||
export const postUpdateBugUrl = '/bug/update';
|
||||
export const postBatchUpdateBugUrl = '/bug/batch-update';
|
||||
export const postCreateBugUrl = '/bug/add';
|
||||
export const getDeleteBugUrl = '/bug/delete/';
|
||||
export const postBatchDeleteBugUrl = '/bug/batch-delete';
|
||||
export const getTemplateUrl = '/bug/template';
|
||||
export const getTemplageOption = '/bug/template-option';
|
|
@ -92,7 +92,6 @@
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { TEST_PLAN_TEST_CASE } from './caseUtils';
|
||||
import type { SearchKeyType } from './type';
|
||||
import type { FormInstance } from '@arco-design/web-vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
<template>
|
||||
<a-form ref="formRef" :model="formModel" layout="vertical">
|
||||
<div class="w-full overflow-y-auto bg-[var(--color-text-n9)] px-[12px] py-[12px]">
|
||||
<header class="flex flex-row items-center justify-between">
|
||||
<div>{{ t('advanceFilter.setFilterCondition') }}</div>
|
||||
<div class="flex flex-row items-center text-[var(--color-text-2)]">
|
||||
<div>{{ t('advanceFilter.accordBelow') }}</div>
|
||||
<div class="ml-[16px]">
|
||||
<a-select v-model:model-value="accordBelow" size="small">
|
||||
<a-option value="all">{{ t('advanceFilter.all') }}</a-option>
|
||||
<a-option value="any">{{ t('advanceFilter.any') }}</a-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<div class="ml-[8px]">{{ t('advanceFilter.condition') }}</div>
|
||||
</div>
|
||||
</header>
|
||||
<article class="overflow-auto-y mt-[12px] flex max-h-[300px] flex-col gap-[8px]">
|
||||
<section
|
||||
v-for="(item, idx) in formModel.list"
|
||||
:key="item.dataIndex || `filter_item_${idx}`"
|
||||
class="flex flex-row items-center gap-[8px]"
|
||||
>
|
||||
<div class="flex-1 grow">
|
||||
<a-form-item
|
||||
:field="`list[${idx}].dataIndex`"
|
||||
hide-asterisk
|
||||
class="hidden-item"
|
||||
:rules="[{ required: true, message: t('advanceFilter.plaseSelectFilterDataIndex') }]"
|
||||
>
|
||||
<a-select v-model="item.dataIndex" allow-search @change="(v) => dataIndexChange(v, idx)">
|
||||
<a-option
|
||||
v-for="option in currentOptionArr"
|
||||
:key="option.dataIndex"
|
||||
:value="option.dataIndex"
|
||||
:disabled="option.disabled"
|
||||
>
|
||||
{{ t(option.title as string) }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="flex-1 grow-0">
|
||||
<a-form-item
|
||||
:field="`list[${idx}].operator`"
|
||||
hide-asterisk
|
||||
class="hidden-item"
|
||||
:rules="[{ required: true, message: t('advanceFilter.plaseSelectOperator') }]"
|
||||
>
|
||||
<a-select v-model="item.operator" class="w-[100px]" :disabled="!item.dataIndex">
|
||||
<a-option value="equal">{{ t('advanceFilter.operator.equal') }}</a-option>
|
||||
<a-option value="notEqual">{{ t('advanceFilter.operator.notEqual') }}</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="flex-1 grow">
|
||||
<a-form-item
|
||||
:field="`list[${idx}].value`"
|
||||
:rules="[{ required: true, message: t('advanceFilter.plaseInputFilterContent') }]"
|
||||
hide-asterisk
|
||||
class="hidden-item"
|
||||
>
|
||||
<a-input
|
||||
v-if="item.type === FilterType.INPUT"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
allow-clear
|
||||
:disabled="!item.dataIndex"
|
||||
:max-length="60"
|
||||
/>
|
||||
<a-select
|
||||
v-else-if="item.type === FilterType.SELECT"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
allow-clear
|
||||
allow-search
|
||||
:option="item.options"
|
||||
:placeholder="t('advanceFilter.pleaseSelect')"
|
||||
:disabled="!item.dataIndex"
|
||||
></a-select>
|
||||
<a-date-picker
|
||||
v-else-if="item.type === FilterType.DATE_PICKER"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
show-time
|
||||
format="YYYY-MM-DD hh:mm"
|
||||
:disabled="!item.dataIndex"
|
||||
/>
|
||||
<a-range-picker
|
||||
v-else-if="item.type === FilterType.RANGE_PICKER"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
show-time
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:disabled="!item.dataIndex"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="delete-btn" :class="{ 'delete-btn:disabled': idx === 0 }" @click="handleDeleteItem(idx)">
|
||||
<icon-minus-circle />
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
<footer
|
||||
class="mt-[12px] flex flex-row items-center justify-between"
|
||||
:class="{ '!justify-end': !showAddCondition }"
|
||||
>
|
||||
<div
|
||||
v-if="showAddCondition"
|
||||
class="flex cursor-pointer items-center gap-[4px] text-[rgb(var(--primary-7))]"
|
||||
@click="handleAddItem"
|
||||
>
|
||||
<icon-plus />
|
||||
<span>{{ t('advanceFilter.addCondition') }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<a-button class="mr-[8px]" @click="handleReset">{{ t('advanceFilter.reset') }}</a-button>
|
||||
<a-button type="primary" @click="handleFilter">{{ t('advanceFilter.filter') }}</a-button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FormInstance } from '@arco-design/web-vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { SelectValue } from '@/models/projectManagement/menuManagement';
|
||||
|
||||
import { AccordBelowType, BackEndEnum, FilterFormItem, FilterResult, FilterType } from './type';
|
||||
|
||||
const { t } = useI18n();
|
||||
const accordBelow = ref<AccordBelowType>('all');
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
const formModel = reactive<{ list: FilterFormItem[] }>({
|
||||
list: [],
|
||||
});
|
||||
const props = defineProps<{ configList: FilterFormItem[]; visible: boolean; count: number }>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'onSearch', value: FilterResult): void;
|
||||
(e: 'dataIndexChange', value: string): void;
|
||||
(e: 'update:count', value: number): void;
|
||||
}>();
|
||||
|
||||
// 获取当前可选的选项
|
||||
const getCurrentOptionArr = () => {
|
||||
const arr1 = props.configList;
|
||||
const arr2 = formModel.list.map((item) => item.dataIndex);
|
||||
const intersection = arr1.map((item1) => ({
|
||||
...item1,
|
||||
disabled: arr2.includes(item1.dataIndex),
|
||||
}));
|
||||
return intersection;
|
||||
};
|
||||
|
||||
const currentOptionArr = computed(() => getCurrentOptionArr());
|
||||
|
||||
// 是否显示添加条件按钮
|
||||
const showAddCondition = computed(() => {
|
||||
return currentOptionArr.value.some((item) => !item.disabled);
|
||||
});
|
||||
|
||||
const getInitItem = () => {
|
||||
return {
|
||||
dataIndex: '',
|
||||
type: FilterType.INPUT,
|
||||
operator: '',
|
||||
value: '',
|
||||
backendType: BackEndEnum.STRING,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 添加条件
|
||||
*/
|
||||
const handleAddItem = async () => {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
formModel.list.push(getInitItem());
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* @description 删除条件
|
||||
*/
|
||||
const handleDeleteItem = (index: number) => {
|
||||
if (index === 0) {
|
||||
return;
|
||||
}
|
||||
formModel.list.splice(index, 1);
|
||||
};
|
||||
/**
|
||||
* @description 重置
|
||||
*/
|
||||
const handleReset = () => {
|
||||
formRef.value?.resetFields();
|
||||
formModel.list = [getInitItem()];
|
||||
};
|
||||
/**
|
||||
* @description 筛选
|
||||
*/
|
||||
const handleFilter = () => {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
const tmpObj: FilterResult = {};
|
||||
formModel.list.forEach((item) => {
|
||||
tmpObj[item.dataIndex as string] = {
|
||||
operator: item.operator,
|
||||
value: item.value,
|
||||
backendType: item.backendType,
|
||||
};
|
||||
});
|
||||
tmpObj.accordBelow = accordBelow.value;
|
||||
emit('onSearch', tmpObj);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getAttributeByDataIndex = (dataIndex: string) => {
|
||||
return props.configList.find((item) => item.dataIndex === dataIndex);
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 筛选项变化
|
||||
*/
|
||||
const dataIndexChange = (dataIndex: SelectValue, idx: number) => {
|
||||
if (!dataIndex) {
|
||||
return;
|
||||
}
|
||||
const tmpObj = getAttributeByDataIndex(dataIndex as string);
|
||||
if (!tmpObj) {
|
||||
return;
|
||||
}
|
||||
const { type, backendType } = tmpObj;
|
||||
formModel.list[idx].operator = '';
|
||||
formModel.list[idx].backendType = backendType;
|
||||
formModel.list[idx].type = type;
|
||||
if (
|
||||
formModel.list[idx].type === FilterType.RANGE_PICKER ||
|
||||
formModel.list[idx].type === FilterType.MUTIPLE_SELECT
|
||||
) {
|
||||
formModel.list[idx].value = [];
|
||||
} else {
|
||||
formModel.list[idx].value = '';
|
||||
}
|
||||
emit('dataIndexChange', dataIndex as string);
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
formModel.list = [getInitItem()];
|
||||
});
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
if (!val) {
|
||||
emit('update:count', formModel.list.filter((item) => !!item.dataIndex).length);
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.delete-btn {
|
||||
padding: 8px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
color: var(--color-text-4);
|
||||
cursor: pointer;
|
||||
}
|
||||
.delete-btn:hover {
|
||||
color: rgb(var(--primary-5));
|
||||
background-color: rgb(var(--primary-2));
|
||||
}
|
||||
.delete-btn:disabled {
|
||||
@apply cursor-not-allowed hover:bg-transparent hover:text-[var(--color-text-4)];
|
||||
}
|
||||
:deep(.arco-form-item-layout-vertical > .arco-form-item-label-col) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
:deep(.arco-form-item.arco-form-item-error, .arco-form-item.arco-form-item-has-help) {
|
||||
position: relative;
|
||||
top: 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<MsTag
|
||||
:type="props.visible ? 'primary' : 'default'"
|
||||
:theme="props.visible ? 'lightOutLine' : 'outline'"
|
||||
size="large"
|
||||
class="mt-[3px] min-w-[64px] cursor-pointer"
|
||||
>
|
||||
<span :class="!props.visible ? 'text-[var(--color-text-4)]' : ''" @click="handleOpenFilter">
|
||||
<icon-filter class="text-[16px]" />
|
||||
<span class="ml-[4px]">
|
||||
<span v-if="props.count">{{ props.count }}</span>
|
||||
{{ t('common.filter') }}
|
||||
</span>
|
||||
</span>
|
||||
</MsTag>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsTag from '../ms-tag/ms-tag.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
count?: number;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', value: boolean): void;
|
||||
(e: 'update:count', value: number): void;
|
||||
}>();
|
||||
|
||||
const handleOpenFilter = () => {
|
||||
emit('update:visible', !props.visible);
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,2 @@
|
|||
export { default as FilterForm } from './FilterForm.vue';
|
||||
export { default as FilterIcon } from './FilterIcon.vue';
|
|
@ -0,0 +1,21 @@
|
|||
export default {
|
||||
'advanceFilter.operator.like': 'like',
|
||||
'advanceFilter.operator.not_like': 'not like',
|
||||
'advanceFilter.operator.in': 'in',
|
||||
'advanceFilter.operator.not_in': 'not in',
|
||||
'advanceFilter.operator.gt': 'gt',
|
||||
'advanceFilter.operator.ge': 'ge',
|
||||
'advanceFilter.operator.lt': 'lt',
|
||||
'advanceFilter.operator.le': 'le',
|
||||
'advanceFilter.operator.equals': 'equals',
|
||||
'advanceFilter.operator.between': 'between',
|
||||
'advanceFilter.setFilterCondition': 'Set Filter Condition',
|
||||
'advanceFilter.accordBelow': 'Accord below',
|
||||
'advanceFilter.all': 'All',
|
||||
'advanceFilter.any': 'Any',
|
||||
'advanceFilter.condition': 'Condition',
|
||||
'advanceFilter.addCondition': 'Add Condition',
|
||||
'advanceFilter.reset': 'Reset',
|
||||
'advanceFilter.filter': 'Filter',
|
||||
'advanceFilter.plaseInputFilterContent': 'Please input filter content',
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
export default {
|
||||
'advanceFilter.operator.like': '包含',
|
||||
'advanceFilter.operator.not_like': '不包含',
|
||||
'advanceFilter.operator.in': '在列表中',
|
||||
'advanceFilter.operator.not_in': '不在列表中',
|
||||
'advanceFilter.operator.gt': '大于',
|
||||
'advanceFilter.operator.ge': '大于等于',
|
||||
'advanceFilter.operator.lt': '小于',
|
||||
'advanceFilter.operator.le': '小于等于',
|
||||
'advanceFilter.operator.equal': '等于',
|
||||
'advanceFilter.operator.notEqual': '不等于',
|
||||
'advanceFilter.operator.between': '介于',
|
||||
'advanceFilter.setFilterCondition': '设置过滤条件',
|
||||
'advanceFilter.accordBelow': '满足以下',
|
||||
'advanceFilter.all': '所有',
|
||||
'advanceFilter.any': '任意',
|
||||
'advanceFilter.condition': '条件',
|
||||
'advanceFilter.addCondition': '添加条件',
|
||||
'advanceFilter.reset': '重置',
|
||||
'advanceFilter.filter': '过滤',
|
||||
'advanceFilter.plaseSelectFilterDataIndex': '请选择过滤条件',
|
||||
'advanceFilter.plaseInputFilterContent': '请输入筛选内容',
|
||||
'advanceFilter.plaseSelectOperator': '请选择运算符',
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
/* eslint-disable no-shadow */
|
||||
export enum BackEndEnum {
|
||||
STRING = 'string',
|
||||
ARRAY = 'array',
|
||||
TIME = 'time',
|
||||
}
|
||||
|
||||
export enum FilterType {
|
||||
INPUT = 'Input',
|
||||
SELECT = 'Select',
|
||||
DATE_PICKER = 'DatePicker',
|
||||
RANGE_PICKER = 'RangePicker',
|
||||
MUTIPLE_SELECT = 'MutiSelect',
|
||||
}
|
||||
|
||||
export interface FilterFormItem {
|
||||
dataIndex?: string; // 对应的row的数据key
|
||||
title?: string; // 显示的label 国际化字符串定义在前端
|
||||
type?: FilterType; // 类型:Input,Select,DatePicker,RangePicker
|
||||
value?: any; // 值 字符串 和 数组
|
||||
operator?: string; // 运算符号
|
||||
options?: any[]; // 下拉框的选项
|
||||
backendType?: BackEndEnum; // 后端类型 string array time
|
||||
}
|
||||
|
||||
export type AccordBelowType = 'all' | 'any';
|
||||
|
||||
export interface FilterResult {
|
||||
[key: string]: Pick<FilterFormItem, 'value' | 'operator' | 'backendType'> | AccordBelowType;
|
||||
}
|
||||
|
||||
export interface FilterFormProps {
|
||||
configList: FilterFormItem[];
|
||||
}
|
|
@ -36,7 +36,7 @@
|
|||
<a-table-column
|
||||
v-for="(item, idx) in currentColumns"
|
||||
:key="idx"
|
||||
:width="item.width"
|
||||
:width="item.isTag || item.isStringTag ? item.width || 360 : item.width"
|
||||
:align="item.align"
|
||||
:fixed="item.fixed"
|
||||
:sortable="item.sortable"
|
||||
|
|
|
@ -28,6 +28,7 @@ export enum TableKeyEnum {
|
|||
FILE_MANAGEMENT_VERSION = 'fileManagementVersion',
|
||||
PROJECT_MANAGEMENT_MENU_FALSE_ALERT = 'projectManagementMenuFalseAlert',
|
||||
ORGANIZATION_TEMPLATE_DEFECT_TABLE = 'organizationTemplateManagementDefect',
|
||||
BUG_MANAGEMENT = 'bugManagement',
|
||||
}
|
||||
|
||||
// 具有特殊功能的列
|
||||
|
|
|
@ -21,6 +21,7 @@ export default {
|
|||
'common.operation': '操作',
|
||||
'common.remove': '移除',
|
||||
'common.revoked': '已撤销',
|
||||
'common.filter': '筛选',
|
||||
'common.createSuccess': '创建成功',
|
||||
'common.createFailed': '创建失败',
|
||||
'common.updateSuccess': '更新成功',
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
export interface BugListItem {
|
||||
id: string; // 缺陷id
|
||||
num: string; // 缺陷编号
|
||||
name: string; // 缺陷名称
|
||||
severity: string; // 缺陷严重程度
|
||||
status: string; // 缺陷状态
|
||||
handleUser: string; // 缺陷处理人
|
||||
relationCaseCount: number; // 关联用例数
|
||||
platform: string; // 所属平台
|
||||
tag: string; // 缺陷标签
|
||||
createUser: string; // 创建人
|
||||
updateUser: string; // 更新人
|
||||
createTime: string; // 创建时间
|
||||
updateTime: string; // 更新时间
|
||||
deleted: string; // 删除标志
|
||||
}
|
||||
export default {};
|
|
@ -1,26 +1,254 @@
|
|||
<template>
|
||||
<MsCard simple>
|
||||
<h1>BugManagement is waiting for development </h1>
|
||||
<ms-pagination size="small" :total="100000" show-total show-jumper show-page-size />
|
||||
|
||||
<a-range-picker
|
||||
style="margin: 0 24px 24px 0; width: 360px"
|
||||
show-time
|
||||
:time-picker-props="{ defaultValue: ['00:00:00', '09:09:06'] }"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@change="onChange"
|
||||
@select="onSelect"
|
||||
@ok="onOk"
|
||||
<div class="flex flex-row justify-between">
|
||||
<div class="flex gap-[12px]">
|
||||
<a-button type="primary" @click="handleCreate">
|
||||
{{ t('bugManagement.createBug') }}
|
||||
</a-button>
|
||||
<a-button type="outline" @click="handleSync">
|
||||
{{ t('bugManagement.syncBug') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="flex flex-row gap-[8px]">
|
||||
<a-input-search
|
||||
v-model="keyword"
|
||||
:placeholder="t('system.user.searchUser')"
|
||||
class="w-[240px]"
|
||||
allow-clear
|
||||
@press-enter="fetchData"
|
||||
@search="fetchData"
|
||||
></a-input-search>
|
||||
<FilterIcon v-model:visible="filterVisible" :count="filterCount" />
|
||||
</div>
|
||||
</div>
|
||||
<FilterForm
|
||||
v-show="filterVisible"
|
||||
v-model:count="filterCount"
|
||||
:visible="filterVisible"
|
||||
:config-list="filterConfigList"
|
||||
class="mt-[8px]"
|
||||
@on-search="handleFilter"
|
||||
@data-index-change="dataIndexChange"
|
||||
/>
|
||||
<!-- <MsRichText v-model="content" /> -->
|
||||
<MsTimeSelector v-model="timeValue" />
|
||||
<div>value: {{ timeValue }}</div>
|
||||
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
|
||||
<template #numberOfCase="{ record }">
|
||||
<span class="cursor-pointer text-[rgb(var(--primary-5))]" @click="jumpToTestPlan(record)">{{
|
||||
record.memberCount
|
||||
}}</span>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<div class="flex flex-row flex-nowrap">
|
||||
<MsButton class="!mr-0" @click="handleCopy(record)">{{ t('common.copy') }}</MsButton>
|
||||
<a-divider direction="vertical" />
|
||||
<MsButton class="!mr-0" @click="handleEdit(record)">{{ t('common.edit') }}</MsButton>
|
||||
<a-divider direction="vertical" />
|
||||
<MsButton class="!mr-0" status="danger" @click="handleDelete(record)">{{ t('common.delete') }}</MsButton>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty> </template>
|
||||
</MsBaseTable>
|
||||
</MsCard>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import MsTimeSelector from '@/components/pure/ms-time-selector/MsTimeSelector.vue';
|
||||
<script lang="ts" setup>
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
const timeValue = ref('3M');
|
||||
import { FilterForm, FilterIcon } from '@/components/pure/ms-advance-filter';
|
||||
import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
|
||||
import { updateOrAddProjectUserGroup } from '@/api/modules/project-management/usergroup';
|
||||
import { postProjectTableByOrg } from '@/api/modules/setting/organizationAndProject';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import router from '@/router';
|
||||
import { useAppStore, useTableStore } from '@/store';
|
||||
|
||||
import { BugListItem } from '@/models/bug-management';
|
||||
import { OrgProjectTableItem } from '@/models/setting/system/orgAndProject';
|
||||
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const keyword = ref('');
|
||||
const tableStore = useTableStore();
|
||||
const appStore = useAppStore();
|
||||
const projectId = computed(() => appStore.currentProjectId);
|
||||
const filterVisible = ref(false);
|
||||
const filterCount = ref(0);
|
||||
const filterConfigList = reactive<FilterFormItem[]>([
|
||||
{
|
||||
title: 'bugManagement.ID',
|
||||
dataIndex: 'num',
|
||||
type: FilterType.INPUT,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.bugName',
|
||||
dataIndex: 'name',
|
||||
type: FilterType.SELECT,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.severity',
|
||||
dataIndex: 'severity',
|
||||
type: FilterType.MUTIPLE_SELECT,
|
||||
},
|
||||
]);
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'bugManagement.ID',
|
||||
dataIndex: 'num',
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.bugName',
|
||||
editType: ColumnEditTypeEnum.INPUT,
|
||||
dataIndex: 'name',
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.severity',
|
||||
slotName: 'memberCount',
|
||||
showDrag: true,
|
||||
dataIndex: 'severity',
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.status',
|
||||
dataIndex: 'status',
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.handleMan',
|
||||
dataIndex: 'handleUser',
|
||||
showTooltip: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.numberOfCase',
|
||||
dataIndex: 'relationCaseCount',
|
||||
slotName: 'numberOfCase',
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.belongPlatform',
|
||||
width: 180,
|
||||
showDrag: true,
|
||||
dataIndex: 'platform',
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.tag',
|
||||
showDrag: true,
|
||||
isStringTag: true,
|
||||
dataIndex: 'tag',
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.creator',
|
||||
dataIndex: 'createUser',
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.updateUser',
|
||||
dataIndex: 'updateUser',
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.createTime',
|
||||
dataIndex: 'createTime',
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.updateTime',
|
||||
dataIndex: 'updateTime',
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'common.operation',
|
||||
slotName: 'operation',
|
||||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
width: 230,
|
||||
},
|
||||
];
|
||||
await tableStore.initColumn(TableKeyEnum.BUG_MANAGEMENT, columns, 'drawer');
|
||||
|
||||
const handleNameChange = async (record: OrgProjectTableItem) => {
|
||||
try {
|
||||
await updateOrAddProjectUserGroup(record);
|
||||
Message.success(t('common.updateSuccess'));
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const { propsRes, propsEvent, loadList, setKeyword, setLoadListParams } = useTable(
|
||||
postProjectTableByOrg,
|
||||
{
|
||||
tableKey: TableKeyEnum.BUG_MANAGEMENT,
|
||||
selectable: false,
|
||||
noDisable: false,
|
||||
showJumpMethod: true,
|
||||
showSetting: true,
|
||||
scroll: { x: '1769px' },
|
||||
},
|
||||
undefined,
|
||||
(record) => handleNameChange(record)
|
||||
);
|
||||
|
||||
const fetchData = async () => {
|
||||
setKeyword(keyword.value);
|
||||
await loadList();
|
||||
};
|
||||
|
||||
const handleCreate = () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('create');
|
||||
};
|
||||
const handleSync = () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('sync');
|
||||
};
|
||||
|
||||
const handleCopy = (record: BugListItem) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('create', record);
|
||||
};
|
||||
|
||||
const handleEdit = (record: BugListItem) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('create', record);
|
||||
};
|
||||
|
||||
const handleDelete = (record: BugListItem) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('create', record);
|
||||
};
|
||||
|
||||
const handleFilter = (filter: FilterResult) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('filter', filter);
|
||||
};
|
||||
|
||||
const dataIndexChange = (dataIndex: string) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('dataIndexChange', dataIndex);
|
||||
};
|
||||
|
||||
const jumpToTestPlan = (record: BugListItem) => {
|
||||
router.push({
|
||||
name: 'testPlan',
|
||||
query: {
|
||||
bugId: record.id,
|
||||
projectId: projectId.value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
setLoadListParams({ projectId: projectId.value });
|
||||
fetchData();
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
export default {
|
||||
bugManagement: {
|
||||
createBug: 'Create Bug',
|
||||
syncBug: 'Sync Bug',
|
||||
ID: 'ID',
|
||||
bugName: 'Bug Name',
|
||||
severity: 'Severity',
|
||||
status: 'Status',
|
||||
handleMan: 'Handler',
|
||||
numberOfCase: 'Number of Cases',
|
||||
belongPlatform: 'Belong Platform',
|
||||
tag: 'Tag',
|
||||
creator: 'Creator',
|
||||
updateUser: 'Updater',
|
||||
createTime: 'Create Time',
|
||||
updateTime: 'Update Time',
|
||||
},
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
export default {
|
||||
bugManagement: {
|
||||
createBug: '创建缺陷',
|
||||
syncBug: '同步缺陷',
|
||||
ID: 'ID',
|
||||
bugName: '缺陷名称',
|
||||
severity: '严重程度',
|
||||
status: '状态',
|
||||
handleMan: '处理人',
|
||||
numberOfCase: '用例数',
|
||||
belongPlatform: '所属平台',
|
||||
tag: '标签',
|
||||
creator: '创建人',
|
||||
updateUser: '更新人',
|
||||
createTime: '创建时间',
|
||||
updateTime: '更新时间',
|
||||
},
|
||||
};
|
Loading…
Reference in New Issue