feat(缺陷管理): 编辑缺陷假页面
This commit is contained in:
parent
730583ecf9
commit
349fa22764
|
@ -2,7 +2,7 @@ import MSR from '@/api/http/index';
|
||||||
import * as bugURL from '@/api/requrls/bug-management';
|
import * as bugURL from '@/api/requrls/bug-management';
|
||||||
|
|
||||||
import { BugListItem } from '@/models/bug-management';
|
import { BugListItem } from '@/models/bug-management';
|
||||||
import { CommonList, TableQueryParams } from '@/models/common';
|
import { CommonList, TableQueryParams, TemplateOption } from '@/models/common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表格的查询
|
* 表格的查询
|
||||||
|
@ -33,8 +33,8 @@ export function deleteBatchBug(data: TableQueryParams) {
|
||||||
return MSR.post({ url: bugURL.postBatchDeleteBugUrl, data });
|
return MSR.post({ url: bugURL.postBatchDeleteBugUrl, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTemplageOption(data: TableQueryParams) {
|
export function getTemplageOption(params: { projectId: string }) {
|
||||||
return MSR.get({ url: bugURL.getTemplageOption, data });
|
return MSR.get<TemplateOption[]>({ url: bugURL.getTemplageOption, params });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTemplateById(data: TableQueryParams) {
|
export function getTemplateById(data: TableQueryParams) {
|
||||||
|
|
|
@ -5,4 +5,4 @@ export const postCreateBugUrl = '/bug/add';
|
||||||
export const getDeleteBugUrl = '/bug/delete/';
|
export const getDeleteBugUrl = '/bug/delete/';
|
||||||
export const postBatchDeleteBugUrl = '/bug/batch-delete';
|
export const postBatchDeleteBugUrl = '/bug/batch-delete';
|
||||||
export const getTemplateUrl = '/bug/template';
|
export const getTemplateUrl = '/bug/template';
|
||||||
export const getTemplageOption = '/bug/template-option';
|
export const getTemplageOption = '/bug/template/option';
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-scrollbar>
|
</a-scrollbar>
|
||||||
|
<div :class="{ 'px-[24px]': props.dividerHasPX }">
|
||||||
<a-divider v-if="!props.simple && !props.hideDivider" class="mb-[16px] mt-0" />
|
<a-divider v-if="!props.simple && !props.hideDivider" class="mb-[16px] mt-0" />
|
||||||
|
</div>
|
||||||
<div class="ms-card-container">
|
<div class="ms-card-container">
|
||||||
<a-scrollbar :class="props.noContentPadding ? '' : 'pr-[5px]'" :style="getComputedContentStyle">
|
<a-scrollbar :class="props.noContentPadding ? '' : 'pr-[5px]'" :style="getComputedContentStyle">
|
||||||
<div class="relative h-full w-full" :style="{ minWidth: `${props.minWidth || 1000}px` }">
|
<div class="relative h-full w-full" :style="{ minWidth: `${props.minWidth || 1000}px` }">
|
||||||
|
@ -86,6 +88,7 @@
|
||||||
isFullscreen?: boolean; // 是否全屏
|
isFullscreen?: boolean; // 是否全屏
|
||||||
hideDivider?: boolean; // 是否隐藏分割线
|
hideDivider?: boolean; // 是否隐藏分割线
|
||||||
handleBack: () => void; // 自定义返回按钮触发事件
|
handleBack: () => void; // 自定义返回按钮触发事件
|
||||||
|
dividerHasPX: boolean; // 分割线是否有左右padding;
|
||||||
}>
|
}>
|
||||||
>(),
|
>(),
|
||||||
{
|
{
|
||||||
|
@ -99,6 +102,7 @@
|
||||||
hasBreadcrumb: false,
|
hasBreadcrumb: false,
|
||||||
noContentPadding: false,
|
noContentPadding: false,
|
||||||
noBottomRadius: false,
|
noBottomRadius: false,
|
||||||
|
dividerHasPX: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// import { unified } from 'unified';
|
/**
|
||||||
// import rehypeParse from 'rehype-parse';
|
*
|
||||||
// import rehypeFormat from 'rehype-format';
|
* @name: MsRichText.vue
|
||||||
// import rehypeStringify from 'rehype-stringify';
|
* @param {string} modelValue v-model绑定的值
|
||||||
import { useLocalStorage } from '@vueuse/core';
|
* @return {string} 返回编辑器内容
|
||||||
|
* @description: 富文本编辑器
|
||||||
|
* @example:
|
||||||
|
* import { unified } from 'unified';
|
||||||
|
* import rehypeParse from 'rehype-parse';
|
||||||
|
* import rehypeFormat from 'rehype-format';
|
||||||
|
* import rehypeStringify from 'rehype-stringify';
|
||||||
|
* return unified().use(rehypeParse).use(rehypeFormat).use(rehypeStringify).processSync(content.value);
|
||||||
|
*/
|
||||||
import useLocale from '@/locale/useLocale';
|
import useLocale from '@/locale/useLocale';
|
||||||
|
|
||||||
import '@halo-dev/richtext-editor/dist/style.css';
|
import '@halo-dev/richtext-editor/dist/style.css';
|
||||||
|
@ -57,7 +64,7 @@
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(['update:model-value']);
|
const emit = defineEmits(['update:model-value']);
|
||||||
|
|
||||||
const content = useLocalStorage('content', '');
|
const content = ref('');
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
content: content.value,
|
content: content.value,
|
||||||
|
@ -122,22 +129,11 @@
|
||||||
],
|
],
|
||||||
onUpdate: () => {
|
onUpdate: () => {
|
||||||
content.value = `${editor.value?.getHTML()}`;
|
content.value = `${editor.value?.getHTML()}`;
|
||||||
console.log(content.value);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// const formatContent = computed(() => {
|
|
||||||
// return unified().use(rehypeParse).use(rehypeFormat).use(rehypeStringify).processSync(content.value);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// watchEffect(() => {
|
|
||||||
// console.log(String(formatContent.value));
|
|
||||||
// });
|
|
||||||
const { currentLocale } = useLocale();
|
const { currentLocale } = useLocale();
|
||||||
|
|
||||||
// const locale = useLocalStorage('locale', 'zh-CN');
|
|
||||||
const locale = computed(() => currentLocale.value as 'zh-CN' | 'en-US');
|
const locale = computed(() => currentLocale.value as 'zh-CN' | 'en-US');
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(val) => {
|
(val) => {
|
||||||
|
@ -156,13 +152,19 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div style="height: 140px" class="rich-wrapper flex w-full">
|
<div class="rich-wrapper flex w-full">
|
||||||
<RichTextEditor v-if="editor" :editor="editor" :locale="locale" />
|
<RichTextEditor v-if="editor" :editor="editor" :locale="locale" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.rich-wrapper {
|
.rich-wrapper {
|
||||||
|
position: relative;
|
||||||
border: 1px solid var(--color-text-n8);
|
border: 1px solid var(--color-text-n8);
|
||||||
|
:deep(.halo-rich-text-editor .ProseMirror) {
|
||||||
|
p:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="props.mode === 'remote'" class="sticky top-[0] z-[9999] mb-[8px] flex justify-between bg-white">
|
<div
|
||||||
|
v-if="props.mode === 'remote' && props.showTab"
|
||||||
|
class="sticky top-[0] z-[9999] mb-[8px] flex justify-between bg-white"
|
||||||
|
>
|
||||||
<a-radio-group v-model:model-value="fileListTab" type="button" size="small">
|
<a-radio-group v-model:model-value="fileListTab" type="button" size="small">
|
||||||
<a-radio value="all">{{ `${t('ms.upload.all')} (${innerFileList.length})` }}</a-radio>
|
<a-radio value="all">{{ `${t('ms.upload.all')} (${innerFileList.length})` }}</a-radio>
|
||||||
<a-radio value="waiting">{{ `${t('ms.upload.uploading')} (${totalWaitingFileList.length})` }}</a-radio>
|
<a-radio value="waiting">{{ `${t('ms.upload.uploading')} (${totalWaitingFileList.length})` }}</a-radio>
|
||||||
|
@ -116,11 +119,13 @@
|
||||||
requestParams?: Record<string, any>; // 上传文件时,额外的请求参数
|
requestParams?: Record<string, any>; // 上传文件时,额外的请求参数
|
||||||
route?: string; // 用于后台上传文件时,查看详情跳转的路由
|
route?: string; // 用于后台上传文件时,查看详情跳转的路由
|
||||||
routeQuery?: Record<string, string>; // 用于后台上传文件时,查看详情跳转的路由参数
|
routeQuery?: Record<string, string>; // 用于后台上传文件时,查看详情跳转的路由参数
|
||||||
|
showTab?: boolean; // 是否显示tab
|
||||||
handleDelete?: (item: MsFileItem) => void;
|
handleDelete?: (item: MsFileItem) => void;
|
||||||
handleReupload?: (item: MsFileItem) => void;
|
handleReupload?: (item: MsFileItem) => void;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
mode: 'remote',
|
mode: 'remote',
|
||||||
|
showTab: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|
|
@ -73,4 +73,5 @@ export default {
|
||||||
'common.copy': 'Copy',
|
'common.copy': 'Copy',
|
||||||
'common.fork': 'Fork',
|
'common.fork': 'Fork',
|
||||||
'common.more': 'More',
|
'common.more': 'More',
|
||||||
|
'common.recycle': 'Recycle Bin',
|
||||||
};
|
};
|
||||||
|
|
|
@ -73,4 +73,5 @@ export default {
|
||||||
'common.copy': '复制',
|
'common.copy': '复制',
|
||||||
'common.fork': '关注',
|
'common.fork': '关注',
|
||||||
'common.more': '更多',
|
'common.more': '更多',
|
||||||
|
'common.recycle': '回收站',
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,6 +30,12 @@ export interface CommonList<T> {
|
||||||
list: T[];
|
list: T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TemplateOption {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
enableDefault: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BatchApiParams {
|
export interface BatchApiParams {
|
||||||
selectIds: string[]; // 已选 ID 集合,当 selectAll 为 false 时接口会使用该字段
|
selectIds: string[]; // 已选 ID 集合,当 selectAll 为 false 时接口会使用该字段
|
||||||
excludeIds?: string[]; // 需要忽略的用户 id 集合,当selectAll为 true 时接口会使用该字段
|
excludeIds?: string[]; // 需要忽略的用户 id 集合,当selectAll为 true 时接口会使用该字段
|
||||||
|
|
|
@ -15,12 +15,47 @@ const BugManagement: AppRouteRecordRaw = {
|
||||||
hideChildrenInMenu: true,
|
hideChildrenInMenu: true,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
// 缺陷管理-首页
|
||||||
{
|
{
|
||||||
path: 'index',
|
path: 'index',
|
||||||
name: 'bugManagementIndex',
|
name: 'bugManagementIndex',
|
||||||
component: () => import('@/views/bug-management/index.vue'),
|
component: () => import('@/views/bug-management/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
locale: 'bugManagement.index',
|
||||||
roles: ['*'],
|
roles: ['*'],
|
||||||
|
isTopMenu: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 缺陷管理-编辑缺陷
|
||||||
|
{
|
||||||
|
path: 'edit',
|
||||||
|
name: 'bugManagementBugEdit',
|
||||||
|
component: () => import('@/views/bug-management/edit.vue'),
|
||||||
|
meta: {
|
||||||
|
locale: 'bugManagement.editBug',
|
||||||
|
roles: ['*'],
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
name: 'bugManagementIndex',
|
||||||
|
locale: 'bugManagement.index',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'bugManagementBugEdit',
|
||||||
|
locale: 'bugManagement.editBug',
|
||||||
|
editLocale: 'menu.settings.organization.templateFieldSetting',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 回收站
|
||||||
|
{
|
||||||
|
path: 'recycle',
|
||||||
|
name: 'bugManagementRecycle',
|
||||||
|
component: () => import('@/views/bug-management/recycle.vue'),
|
||||||
|
meta: {
|
||||||
|
locale: 'bugManagement.recycle',
|
||||||
|
roles: ['*'],
|
||||||
|
isTopMenu: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
<template>
|
||||||
|
<MsCard :special-height="-54" no-content-padding divider-has-p-x has-breadcrumb :title="title">
|
||||||
|
<template #headerRight>
|
||||||
|
<a-select
|
||||||
|
v-model="templateId"
|
||||||
|
class="w-[240px]"
|
||||||
|
:options="templateOption"
|
||||||
|
allow-search
|
||||||
|
:placeholder="t('bugManagement.edit.defaultSystemTemplate')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<a-form ref="formRef" :model="form" layout="vertical">
|
||||||
|
<div class="flex flex-row" style="height: calc(100vh - 224px)">
|
||||||
|
<div class="left mt-[16px] min-w-[732px] grow pl-[24px]">
|
||||||
|
<a-form-item
|
||||||
|
field="name"
|
||||||
|
:label="t('bugManagement.bugName')"
|
||||||
|
:rules="[{ required: true, message: t('bugManagement.edit.nameIsRequired') }]"
|
||||||
|
:placeholder="t('bugManagement.edit.pleaseInputBugName')"
|
||||||
|
>
|
||||||
|
<a-input v-model="form.name" :max-length="255" show-word-limit />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item :label="t('bugManagement.edit.content')">
|
||||||
|
<MsRichText v-model="form.content" />
|
||||||
|
</a-form-item>
|
||||||
|
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('bugManagement.edit.file') }}</div>
|
||||||
|
<MsUpload
|
||||||
|
v-model:file-list="fileList"
|
||||||
|
:auto-upload="false"
|
||||||
|
multiple
|
||||||
|
draggable
|
||||||
|
accept="unknown"
|
||||||
|
is-limit
|
||||||
|
size-unit="MB"
|
||||||
|
:max-size="500"
|
||||||
|
>
|
||||||
|
<a-button type="outline">
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
{{ t('bugManagement.edit.uploadFile') }}
|
||||||
|
</a-button>
|
||||||
|
</MsUpload>
|
||||||
|
<div class="mb-[8px] mt-[2px] text-[var(--color-text-4)]">{{ t('bugManagement.edit.fileExtra') }}</div>
|
||||||
|
<FileList
|
||||||
|
:show-tab="false"
|
||||||
|
:file-list="fileList"
|
||||||
|
:upload-func="uploadFile"
|
||||||
|
@delete-file="deleteFile"
|
||||||
|
@reupload="reupload"
|
||||||
|
@handle-preview="handlePreview"
|
||||||
|
>
|
||||||
|
</FileList>
|
||||||
|
</div>
|
||||||
|
<a-divider class="ml-[16px]" direction="vertical" />
|
||||||
|
<div class="right mt-[16px] grow pr-[24px]">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('bugManagement.handleMan')"
|
||||||
|
field="handleMan"
|
||||||
|
:rules="[{ required: true, message: t('bugManagement.edit.handleManIsRequired') }]"
|
||||||
|
>
|
||||||
|
<MsUserSelector
|
||||||
|
v-model:model-value="form.handleMan"
|
||||||
|
placeholder="bugManagement.edit.handleManPlaceholder"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
field="status"
|
||||||
|
:label="t('bugManagement.status')"
|
||||||
|
:rules="[{ required: true, message: t('bugManagement.edit.statusIsRequired') }]"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
v-model:model-value="form.status"
|
||||||
|
:placeholder="t('bugManagement.edit.statusPlaceholder')"
|
||||||
|
></a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="severity" :label="t('bugManagement.severity')">
|
||||||
|
<a-select
|
||||||
|
v-model:model-value="form.severity"
|
||||||
|
:placeholder="t('bugManagement.edit.severityPlaceholder')"
|
||||||
|
></a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="tag" :label="t('bugManagement.tag')">
|
||||||
|
<a-input-tag
|
||||||
|
v-model:model-value="form.tag"
|
||||||
|
:placeholder="t('bugManagement.edit.tagPlaceholder')"
|
||||||
|
allow-clear
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form>
|
||||||
|
</MsCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { FileItem } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||||
|
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||||
|
import FileList from '@/components/pure/ms-upload/fileList.vue';
|
||||||
|
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||||
|
import { MsUserSelector } from '@/components/business/ms-user-selector';
|
||||||
|
|
||||||
|
import { getTemplageOption } from '@/api/modules/bug-management';
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import { useAppStore } from '@/store';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
interface TemplateOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const templateOption = ref<TemplateOption[]>([]);
|
||||||
|
const form = ref({
|
||||||
|
name: '',
|
||||||
|
content: '',
|
||||||
|
templateId: '',
|
||||||
|
handleMan: [],
|
||||||
|
status: '',
|
||||||
|
severity: '',
|
||||||
|
tag: [],
|
||||||
|
});
|
||||||
|
const formRef = ref<any>(null);
|
||||||
|
|
||||||
|
const fileList = ref<FileItem[]>([]);
|
||||||
|
|
||||||
|
// 模板id
|
||||||
|
const templateId = ref<string>('');
|
||||||
|
const isEdit = computed(() => !!route.query.id);
|
||||||
|
|
||||||
|
const title = computed(() => {
|
||||||
|
return isEdit.value ? t('bugManagement.editBug') : t('bugManagement.createBug');
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTemplateOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getTemplageOption({ projectId: appStore.currentProjectId });
|
||||||
|
templateOption.value = res.map((item) => {
|
||||||
|
if (item.enableDefault && !isEdit.value) {
|
||||||
|
templateId.value = item.id;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePreview = (item: FileItem) => {
|
||||||
|
const { url } = item;
|
||||||
|
window.open(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteFile = (item: FileItem) => {
|
||||||
|
fileList.value = fileList.value.filter((e) => e.uid !== item.uid);
|
||||||
|
};
|
||||||
|
|
||||||
|
const reupload = (item: FileItem) => {
|
||||||
|
fileList.value = fileList.value.map((e) => {
|
||||||
|
if (e.uid === item.uid) {
|
||||||
|
return {
|
||||||
|
...e,
|
||||||
|
status: 'init',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadFile = (file: File) => {
|
||||||
|
const fileItem: FileItem = {
|
||||||
|
uid: `${Date.now()}`,
|
||||||
|
name: file.name,
|
||||||
|
status: 'init',
|
||||||
|
file,
|
||||||
|
};
|
||||||
|
fileList.value.push(fileItem);
|
||||||
|
return Promise.resolve(fileItem);
|
||||||
|
};
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
getTemplateOptions();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
:deep(.arco-form-item-extra) {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-4);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -4,7 +4,7 @@
|
||||||
<template #left>
|
<template #left>
|
||||||
<div class="flex gap-[12px]">
|
<div class="flex gap-[12px]">
|
||||||
<a-button type="primary" @click="handleCreate">{{ t('bugManagement.createBug') }} </a-button>
|
<a-button type="primary" @click="handleCreate">{{ t('bugManagement.createBug') }} </a-button>
|
||||||
<a-button type="primary" @click="handleSync">{{ t('bugManagement.syncBug') }} </a-button>
|
<a-button type="outline" @click="handleSync">{{ t('bugManagement.syncBug') }} </a-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</MsAdvanceFilter>
|
</MsAdvanceFilter>
|
||||||
|
@ -199,8 +199,9 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
// eslint-disable-next-line no-console
|
router.push({
|
||||||
console.log('create');
|
name: 'bugManagementBugEdit',
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const handleSync = () => {
|
const handleSync = () => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
export default {
|
export default {
|
||||||
bugManagement: {
|
bugManagement: {
|
||||||
|
index: '缺陷管理',
|
||||||
|
editBug: '编辑缺陷',
|
||||||
|
recycle: '回收站',
|
||||||
createBug: '创建缺陷',
|
createBug: '创建缺陷',
|
||||||
syncBug: '同步缺陷',
|
syncBug: '同步缺陷',
|
||||||
ID: 'ID',
|
ID: 'ID',
|
||||||
|
@ -14,5 +17,21 @@ export default {
|
||||||
updateUser: '更新人',
|
updateUser: '更新人',
|
||||||
createTime: '创建时间',
|
createTime: '创建时间',
|
||||||
updateTime: '更新时间',
|
updateTime: '更新时间',
|
||||||
|
edit: {
|
||||||
|
defaultSystemTemplate: '默认为系统模板',
|
||||||
|
content: '缺陷内容',
|
||||||
|
file: '附件',
|
||||||
|
fileExtra: '支持任意类型文件,单个文件大小不超过 500MB',
|
||||||
|
pleaseInputBugName: '请输入缺陷名称',
|
||||||
|
nameIsRequired: '缺陷名称不能为空',
|
||||||
|
pleaseInputBugContent: '请输入缺陷内容',
|
||||||
|
tagPlaceholder: '输入内容后回车可直接添加标签',
|
||||||
|
handleManPlaceholder: '请选择处理人',
|
||||||
|
handleManIsRequired: '处理人不能为空',
|
||||||
|
statusPlaceholder: '请选择缺陷状态',
|
||||||
|
statusIsRequired: '状态不能为空',
|
||||||
|
severityPlaceholder: '请选择严重程度',
|
||||||
|
uploadFile: '添加附件',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,239 @@
|
||||||
|
<template>
|
||||||
|
<MsCard simple>
|
||||||
|
<MsAdvanceFilter :filter-config-list="filterConfigList" :row-count="filterRowCount">
|
||||||
|
<template #left>
|
||||||
|
<div class="flex gap-[12px]">
|
||||||
|
<a-button type="primary" @click="handleCreate">{{ t('bugManagement.createBug') }} </a-button>
|
||||||
|
<a-button type="primary" @click="handleSync">{{ t('bugManagement.syncBug') }} </a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MsAdvanceFilter>
|
||||||
|
<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 lang="ts" setup>
|
||||||
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
import { MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||||
|
import { FilterFormItem, 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 tableStore = useTableStore();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const projectId = computed(() => appStore.currentProjectId);
|
||||||
|
const filterVisible = ref(false);
|
||||||
|
const filterRowCount = ref(0);
|
||||||
|
const filterConfigList = reactive<FilterFormItem[]>([
|
||||||
|
{
|
||||||
|
title: 'bugManagement.ID',
|
||||||
|
dataIndex: 'num',
|
||||||
|
type: FilterType.INPUT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'bugManagement.bugName',
|
||||||
|
dataIndex: 'name',
|
||||||
|
type: FilterType.SELECT,
|
||||||
|
selectProps: {
|
||||||
|
mode: 'static',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'bugManagement.severity',
|
||||||
|
dataIndex: 'severity',
|
||||||
|
type: FilterType.SELECT,
|
||||||
|
selectProps: {
|
||||||
|
mode: 'static',
|
||||||
|
multiple: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'bugManagement.createTime',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
type: FilterType.DATE_PICKER,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const heightUsed = computed(() => 286 + (filterVisible.value ? 160 + (filterRowCount.value - 1) * 60 : 0));
|
||||||
|
|
||||||
|
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, setProps } = useTable(
|
||||||
|
postProjectTableByOrg,
|
||||||
|
{
|
||||||
|
tableKey: TableKeyEnum.BUG_MANAGEMENT,
|
||||||
|
selectable: false,
|
||||||
|
noDisable: false,
|
||||||
|
showJumpMethod: true,
|
||||||
|
showSetting: true,
|
||||||
|
scroll: { x: '1769px' },
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
(record) => handleNameChange(record)
|
||||||
|
);
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
setProps({ heightUsed: heightUsed.value });
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchData = async (v = '') => {
|
||||||
|
setKeyword(v);
|
||||||
|
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 jumpToTestPlan = (record: BugListItem) => {
|
||||||
|
router.push({
|
||||||
|
name: 'testPlan',
|
||||||
|
query: {
|
||||||
|
bugId: record.id,
|
||||||
|
projectId: projectId.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setLoadListParams({ projectId: projectId.value });
|
||||||
|
fetchData();
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Reference in New Issue