parent
8d87368469
commit
89bd4836d2
|
@ -1,7 +1,8 @@
|
||||||
import MSR from '@/api/http/index';
|
import MSR from '@/api/http/index';
|
||||||
import * as bugURL from '@/api/requrls/bug-management';
|
import * as bugURL from '@/api/requrls/bug-management';
|
||||||
|
|
||||||
import { BugExportParams, BugListItem, DefaultTemplate } from '@/models/bug-management';
|
import { BugEditFormObject, BugExportParams, BugListItem } from '@/models/bug-management';
|
||||||
|
import { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||||
import { CommonList, TableQueryParams, TemplateOption } from '@/models/common';
|
import { CommonList, TableQueryParams, TemplateOption } from '@/models/common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,17 +13,35 @@ import { CommonList, TableQueryParams, TemplateOption } from '@/models/common';
|
||||||
export function getBugList(data: TableQueryParams) {
|
export function getBugList(data: TableQueryParams) {
|
||||||
return MSR.post<CommonList<BugListItem>>({ url: bugURL.postTableListUrl, data });
|
return MSR.post<CommonList<BugListItem>>({ url: bugURL.postTableListUrl, data });
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
export function updateBug(data: TableQueryParams) {
|
* 更新Bug
|
||||||
return MSR.post({ url: bugURL.postUpdateBugUrl, data });
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function updateBug(data: { request: BugEditFormObject; fileList: File[] }) {
|
||||||
|
return MSR.uploadFile({ url: bugURL.postUpdateBugUrl }, data, '', true);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 批量更新
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export function updateBatchBug(data: TableQueryParams) {
|
export function updateBatchBug(data: TableQueryParams) {
|
||||||
return MSR.post({ url: bugURL.postBatchUpdateBugUrl, data });
|
return MSR.post({ url: bugURL.postBatchUpdateBugUrl, data });
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
export function createBug(data: TableQueryParams) {
|
* 创建Bug
|
||||||
return MSR.uploadFile({ url: bugURL.postCreateBugUrl }, { request: data.request, fileList: data.fileList }, '');
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function createBug(data: { request: BugEditFormObject; fileList: File[] }) {
|
||||||
|
return MSR.uploadFile({ url: bugURL.postCreateBugUrl }, data, '', true);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取 bug 详情
|
||||||
|
*/
|
||||||
|
export function getBugDetail(id: string) {
|
||||||
|
return MSR.get({ url: `${bugURL.getBugDetailUrl}${id}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteSingleBug(data: TableQueryParams) {
|
export function deleteSingleBug(data: TableQueryParams) {
|
||||||
|
@ -38,14 +57,14 @@ export function getTemplageOption(params: { projectId: string }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTemplateById(data: TableQueryParams) {
|
export function getTemplateById(data: TableQueryParams) {
|
||||||
return MSR.get({ url: bugURL.getTemplateUrl, data });
|
return MSR.post({ url: bugURL.getTemplateUrl, data });
|
||||||
}
|
}
|
||||||
// 获取导出字段配置
|
// 获取导出字段配置
|
||||||
export function getExportConfig(projectId: string) {
|
export function getExportConfig(projectId: string) {
|
||||||
return MSR.get({ url: `${bugURL.getExportConfigUrl}${projectId}` });
|
return MSR.get({ url: `${bugURL.getExportConfigUrl}${projectId}` });
|
||||||
}
|
}
|
||||||
// 获取模版详情
|
// 获取模版详情
|
||||||
export function getTemplateDetailInfo(data: DefaultTemplate) {
|
export function getTemplateDetailInfo(data: { id: string; projectId: string }) {
|
||||||
return MSR.post({ url: `${bugURL.getTemplateDetailUrl}`, data });
|
return MSR.post({ url: `${bugURL.getTemplateDetailUrl}`, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,3 +77,7 @@ export function syncBugOpenSource(params: { projectId: string }) {
|
||||||
export function exportBug(data: BugExportParams) {
|
export function exportBug(data: BugExportParams) {
|
||||||
return MSR.post({ url: bugURL.postExportBugUrl, data });
|
return MSR.post({ url: bugURL.postExportBugUrl, data });
|
||||||
}
|
}
|
||||||
|
// 获取关联文件列表
|
||||||
|
export function getAssociatedFileList(data: TableQueryParams) {
|
||||||
|
return MSR.post<CommonList<AssociatedList>>({ url: bugURL.postAssociatedFileListUrl, data });
|
||||||
|
}
|
||||||
|
|
|
@ -4,9 +4,11 @@ export const postBatchUpdateBugUrl = '/bug/batch-update';
|
||||||
export const postCreateBugUrl = '/bug/add';
|
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/detail';
|
||||||
export const getTemplageOption = '/bug/template/option';
|
export const getTemplageOption = '/bug/template/option';
|
||||||
export const getExportConfigUrl = '/bug/export/columns/';
|
export const getExportConfigUrl = '/bug/export/columns/';
|
||||||
export const getTemplateDetailUrl = '/bug/template/detail';
|
export const getTemplateDetailUrl = '/bug/template/detail';
|
||||||
export const getSyncBugOpenSourceUrl = '/bug/sync/';
|
export const getSyncBugOpenSourceUrl = '/bug/sync/';
|
||||||
export const postExportBugUrl = '/bug/export';
|
export const postExportBugUrl = '/bug/export';
|
||||||
|
export const postAssociatedFileListUrl = '/bug/relate/case/page';
|
||||||
|
export const getBugDetailUrl = '/bug/detail/';
|
||||||
|
|
|
@ -140,6 +140,7 @@
|
||||||
couplingConfig: {
|
couplingConfig: {
|
||||||
...item.props.couplingConfig,
|
...item.props.couplingConfig,
|
||||||
},
|
},
|
||||||
|
sourceType: item.sourceType || '',
|
||||||
};
|
};
|
||||||
return formItemRule;
|
return formItemRule;
|
||||||
});
|
});
|
||||||
|
|
|
@ -93,6 +93,15 @@ export interface FormItem {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FormValueType =
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| string[]
|
||||||
|
| number[]
|
||||||
|
| Record<string, any>
|
||||||
|
| Record<string, any>[];
|
||||||
|
|
||||||
interface FomItemSelect extends FormItemComplexCommonConfig {
|
interface FomItemSelect extends FormItemComplexCommonConfig {
|
||||||
selectMultiple?: boolean; // 选择器是否多选
|
selectMultiple?: boolean; // 选择器是否多选
|
||||||
selectMultipleLimit?: [number, number]; // 选择器多选时最少和最多可选项数,如:[1, 3],表示最少选1项,最多选3项;[0, 3]表示最多选3项,可不选;[1, 0]表示最少选1项,不限制最大可选数
|
selectMultipleLimit?: [number, number]; // 选择器多选时最少和最多可选项数,如:[1, 3],表示最少选1项,最多选3项;[0, 3]表示最多选3项,可不选;[1, 0]表示最少选1项,不限制最大可选数
|
||||||
|
|
|
@ -11,6 +11,8 @@ export enum FormCreateKeyEnum {
|
||||||
CASE_CUSTOM_ATTRS = 'caseCustomAttributes',
|
CASE_CUSTOM_ATTRS = 'caseCustomAttributes',
|
||||||
// 用例tab详情字段
|
// 用例tab详情字段
|
||||||
CASE_CUSTOM_ATTRS_DETAIL = 'caseCustomAttributesDetail',
|
CASE_CUSTOM_ATTRS_DETAIL = 'caseCustomAttributesDetail',
|
||||||
|
// bug 详情
|
||||||
|
BUG_DETAIL = 'bugDetail',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { FormItemType } from '@/components/pure/ms-form-create/types';
|
||||||
|
|
||||||
import { BatchApiParams } from './common';
|
import { BatchApiParams } from './common';
|
||||||
|
|
||||||
export interface BugListItem {
|
export interface BugListItem {
|
||||||
|
@ -25,12 +27,21 @@ export interface BugExportColumn {
|
||||||
export interface BugExportParams extends BatchApiParams {
|
export interface BugExportParams extends BatchApiParams {
|
||||||
bugExportColumns: BugExportColumn[]; // 导出字段
|
bugExportColumns: BugExportColumn[]; // 导出字段
|
||||||
}
|
}
|
||||||
|
export interface BugEditCustomField {
|
||||||
// 获取默认模版缺陷
|
type: FormItemType; // 表单项类型
|
||||||
export interface DefaultTemplate {
|
fieldId: string;
|
||||||
|
fieldName: string;
|
||||||
|
value: string;
|
||||||
|
platformOptionJson?: string; // 选项的 Json
|
||||||
|
required: boolean;
|
||||||
|
}
|
||||||
|
export interface BugEditFormObject {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
export interface BugEditCustomFieldItem {
|
||||||
id: string;
|
id: string;
|
||||||
projectId: string;
|
name: string;
|
||||||
fromStatusId?: string;
|
type: string;
|
||||||
platformBugKey?: string;
|
value: string;
|
||||||
}
|
}
|
||||||
export default {};
|
export default {};
|
||||||
|
|
|
@ -35,7 +35,12 @@ const useFormCreateStore = defineStore('form-create', {
|
||||||
(formItemType: any) => item.type?.toUpperCase() === formItemType
|
(formItemType: any) => item.type?.toUpperCase() === formItemType
|
||||||
);
|
);
|
||||||
if (currentTypeForm) {
|
if (currentTypeForm) {
|
||||||
fieldType = FieldTypeFormRules[currentTypeForm].type;
|
if (currentTypeForm === 'INPUT' && item.subDesc) {
|
||||||
|
// 如果是input类型并且有subDesc说明是JiraKey 类型
|
||||||
|
fieldType = 'JiraKey';
|
||||||
|
} else {
|
||||||
|
fieldType = FieldTypeFormRules[currentTypeForm].type;
|
||||||
|
}
|
||||||
const options = item?.options;
|
const options = item?.options;
|
||||||
const currentOptions = options?.map((optionsItem) => {
|
const currentOptions = options?.map((optionsItem) => {
|
||||||
return {
|
return {
|
||||||
|
@ -55,6 +60,7 @@ const useFormCreateStore = defineStore('form-create', {
|
||||||
options: !item.optionMethod ? currentOptions : [],
|
options: !item.optionMethod ? currentOptions : [],
|
||||||
link: item.couplingConfig?.cascade,
|
link: item.couplingConfig?.cascade,
|
||||||
rule: item.validate || [],
|
rule: item.validate || [],
|
||||||
|
sourceType: item.type, // 原始表单类型
|
||||||
// 梳理表单所需要属性
|
// 梳理表单所需要属性
|
||||||
props: {
|
props: {
|
||||||
...FieldTypeFormRules[currentTypeForm].props,
|
...FieldTypeFormRules[currentTypeForm].props,
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
<template>
|
||||||
|
<a-input
|
||||||
|
v-model:model-value="moduleKeyword"
|
||||||
|
:placeholder="t('project.fileManagement.folderSearchPlaceholder')"
|
||||||
|
allow-clear
|
||||||
|
class="mb-[16px]"
|
||||||
|
></a-input>
|
||||||
|
<a-spin class="min-h-[400px] w-full" :loading="loading">
|
||||||
|
<MsTree
|
||||||
|
v-model:focus-node-key="focusNodeKey"
|
||||||
|
:selected-keys="props.selectedKeys"
|
||||||
|
:data="folderTree"
|
||||||
|
:keyword="moduleKeyword"
|
||||||
|
:expand-all="props.isExpandAll"
|
||||||
|
:empty-text="t('project.fileManagement.noFolder')"
|
||||||
|
:virtual-list-props="virtualListProps"
|
||||||
|
:draggable="false"
|
||||||
|
:field-names="{
|
||||||
|
title: 'name',
|
||||||
|
key: 'id',
|
||||||
|
children: 'children',
|
||||||
|
count: 'count',
|
||||||
|
}"
|
||||||
|
block-node
|
||||||
|
title-tooltip-position="left"
|
||||||
|
@select="folderNodeSelect"
|
||||||
|
>
|
||||||
|
<template #title="nodeData">
|
||||||
|
<div class="inline-flex w-full">
|
||||||
|
<div class="one-line-text w-[calc(100%-32px)] text-[var(--color-text-1)]">
|
||||||
|
<MsIcon type="icon-icon_folder_filled1" size="14" class="mr-1 text-[var(--color-text-4)]" />{{
|
||||||
|
nodeData.name
|
||||||
|
}}</div
|
||||||
|
>
|
||||||
|
<div class="ml-[4px] text-[var(--color-text-4)]">({{ nodeData.count || 0 }})</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MsTree>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
|
import MsTree from '@/components/business/ms-tree/index.vue';
|
||||||
|
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useAppStore from '@/store/modules/app';
|
||||||
|
import { mapTree } from '@/utils';
|
||||||
|
|
||||||
|
import { ModuleTreeNode } from '@/models/projectManagement/file';
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
isExpandAll: boolean;
|
||||||
|
selectedKeys?: Array<string | number>; // 选中的节点 key
|
||||||
|
modulesCount?: Record<string, number>; // 模块数量统计对象
|
||||||
|
showType?: string; // 显示类型
|
||||||
|
getTreeRequest: (params: any) => Promise<ModuleTreeNode[]>; // 获取模块树接口
|
||||||
|
activeFolder: string | number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:selectedKeys', 'init', 'folderNodeSelect', 'update:activeFolder']);
|
||||||
|
|
||||||
|
const moduleKeyword = ref('');
|
||||||
|
const folderTree = ref<ModuleTreeNode[]>([]);
|
||||||
|
const focusNodeKey = ref<string | number>('');
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const virtualListProps = computed(() => {
|
||||||
|
return {
|
||||||
|
height: 'calc(100vh - 296px)',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理文件夹树节点选中事件
|
||||||
|
*/
|
||||||
|
function folderNodeSelect(_selectedKeys: (string | number)[], node: MsTreeNodeData) {
|
||||||
|
const offspringIds: string[] = [];
|
||||||
|
mapTree(node.children || [], (e) => {
|
||||||
|
offspringIds.push(e.id);
|
||||||
|
return e;
|
||||||
|
});
|
||||||
|
|
||||||
|
emit('folderNodeSelect', _selectedKeys, offspringIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedKeys = ref(props.selectedKeys || []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化模块树
|
||||||
|
* @param isSetDefaultKey 是否设置第一个节点为选中节点
|
||||||
|
*/
|
||||||
|
async function initModules(isSetDefaultKey = false) {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await props.getTreeRequest(appStore.currentProjectId);
|
||||||
|
folderTree.value = mapTree<ModuleTreeNode>(res, (e) => {
|
||||||
|
return {
|
||||||
|
...e,
|
||||||
|
hideMoreAction: e.id === 'root',
|
||||||
|
draggable: false,
|
||||||
|
disabled: false,
|
||||||
|
count: props.modulesCount?.[e.id] || 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (isSetDefaultKey) {
|
||||||
|
selectedKeys.value = [folderTree.value[0].id];
|
||||||
|
emit('update:activeFolder', folderTree.value[0].id);
|
||||||
|
}
|
||||||
|
emit('init', folderTree.value);
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.showType,
|
||||||
|
(val) => {
|
||||||
|
if (val === 'Module') {
|
||||||
|
initModules(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化模块文件数量
|
||||||
|
*/
|
||||||
|
watch(
|
||||||
|
() => props.modulesCount,
|
||||||
|
(obj) => {
|
||||||
|
folderTree.value = mapTree<ModuleTreeNode>(folderTree.value, (node) => {
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
count: obj?.[node.id] || 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
|
@ -0,0 +1,313 @@
|
||||||
|
<template>
|
||||||
|
<div class="pl-4">
|
||||||
|
<div class="header">
|
||||||
|
<div
|
||||||
|
><span class="one-line-text max-w-[300px]">{{ moduleInfo.name }}</span
|
||||||
|
><span class="ml-[4px] text-[var(--color-text-4)]">({{ moduleInfo.count }})</span></div
|
||||||
|
>
|
||||||
|
<div class="header-right">
|
||||||
|
<a-select v-model="tableFileType" class="w-[240px]" :loading="fileTypeLoading" @change="searchList">
|
||||||
|
<a-option key="" value="">{{ t('common.all') }}</a-option>
|
||||||
|
<a-option v-for="item of tableFileTypeOptions" :key="item" :value="item">
|
||||||
|
{{ item }}
|
||||||
|
</a-option>
|
||||||
|
</a-select>
|
||||||
|
<a-input-search
|
||||||
|
v-model:model-value="keyword"
|
||||||
|
:placeholder="t('project.fileManagement.folderSearchPlaceholder')"
|
||||||
|
allow-clear
|
||||||
|
class="w-[240px]"
|
||||||
|
@search="searchList"
|
||||||
|
@press-enter="searchList"
|
||||||
|
/></div>
|
||||||
|
</div>
|
||||||
|
<ms-base-table v-bind="propsRes" ref="tableRef" no-disable v-on="propsEvent">
|
||||||
|
<template #name="{ record }">
|
||||||
|
<MsTag
|
||||||
|
v-if="record.fileType.toLowerCase() === 'jar'"
|
||||||
|
theme="light"
|
||||||
|
type="success"
|
||||||
|
:self-style="
|
||||||
|
record.enable
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
color: 'var(--color-text-4)',
|
||||||
|
backgroundColor: 'var(--color-text-n9)',
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ t(record.enable ? 'common.enable' : 'common.disable') }}
|
||||||
|
</MsTag>
|
||||||
|
<a-tooltip :content="record.name">
|
||||||
|
<div class="one-line-text max-w-[168px]">{{ record.name }}</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<template #size="{ record }">
|
||||||
|
<span>{{ formatFileSize(record.size) }}</span>
|
||||||
|
</template>
|
||||||
|
</ms-base-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { debounce } from 'lodash-es';
|
||||||
|
|
||||||
|
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||||
|
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||||
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
|
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||||
|
|
||||||
|
import { getFileTypes, getRepositoryFileTypes } from '@/api/modules/project-management/fileManagement';
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useAppStore from '@/store/modules/app';
|
||||||
|
import useUserStore from '@/store/modules/user';
|
||||||
|
import { findNodeByKey, formatFileSize } from '@/utils';
|
||||||
|
|
||||||
|
import type { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||||
|
import type { CommonList, TableQueryParams } from '@/models/common';
|
||||||
|
import type { FileListQueryParams, ModuleTreeNode } from '@/models/projectManagement/file';
|
||||||
|
import { Repository } from '@/models/projectManagement/file';
|
||||||
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
activeFolder: string;
|
||||||
|
activeFolderType: 'folder' | 'module' | 'storage';
|
||||||
|
offspringIds: string[]; // 当前选中文件夹的所有子孙节点id
|
||||||
|
modulesCount: Record<string, any>; // 模块数量
|
||||||
|
folderTree: ModuleTreeNode[];
|
||||||
|
selectFile: AssociatedList[]; // 表格选中项
|
||||||
|
getListRequest: (params: TableQueryParams) => Promise<CommonList<AssociatedList>>;
|
||||||
|
showType: 'Module' | 'Storage'; // 展示类型
|
||||||
|
storageList: Repository[]; // 存储库列表
|
||||||
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'init', params: FileListQueryParams): void;
|
||||||
|
(e: 'update:selectFile', val: AssociatedList[]): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const tableFileTypeOptions = ref<string[]>([]);
|
||||||
|
const tableFileType = ref(''); // 文件格式筛选
|
||||||
|
const keyword = ref('');
|
||||||
|
const fileTypeLoading = ref(false);
|
||||||
|
const fileType = ref('module'); // 当前查看的文件类型,模块/存储库
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const combine = ref<Record<string, any>>({});
|
||||||
|
const isMyOrAllFolder = computed(() => ['my', 'all'].includes(props.activeFolder)); // 是否是我的文件/全部文件
|
||||||
|
|
||||||
|
const columns: MsTableColumn = [
|
||||||
|
{
|
||||||
|
title: 'project.fileManagement.name',
|
||||||
|
slotName: 'name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
width: 270,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'project.fileManagement.type',
|
||||||
|
dataIndex: 'fileType',
|
||||||
|
width: 90,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'project.fileManagement.tag',
|
||||||
|
dataIndex: 'tags',
|
||||||
|
isTag: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'project.fileManagement.creator',
|
||||||
|
dataIndex: 'creator',
|
||||||
|
showTooltip: true,
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'project.fileManagement.updater',
|
||||||
|
dataIndex: 'updateUser',
|
||||||
|
showTooltip: true,
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'project.fileManagement.updateTime',
|
||||||
|
dataIndex: 'updateTime',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||||
|
props.getListRequest,
|
||||||
|
{
|
||||||
|
columns,
|
||||||
|
tableKey: TableKeyEnum.FILE_MANAGEMENT_FILE,
|
||||||
|
showSetting: false,
|
||||||
|
selectable: true,
|
||||||
|
showSelectAll: true,
|
||||||
|
heightUsed: 300,
|
||||||
|
},
|
||||||
|
(item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
tags: item.tags?.map((e: string) => ({ id: e, name: e })) || [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function emitTableParams() {
|
||||||
|
emit('init', {
|
||||||
|
keyword: keyword.value,
|
||||||
|
fileType: tableFileType.value,
|
||||||
|
moduleIds: [],
|
||||||
|
projectId: appStore.currentProjectId,
|
||||||
|
current: propsRes.value.msPagination?.current,
|
||||||
|
pageSize: propsRes.value.msPagination?.pageSize,
|
||||||
|
combine: combine.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTableParams() {
|
||||||
|
if (props.activeFolder === 'my') {
|
||||||
|
combine.value.createUser = userStore.id;
|
||||||
|
} else {
|
||||||
|
combine.value.createUser = '';
|
||||||
|
}
|
||||||
|
if (fileType.value === 'storage') {
|
||||||
|
combine.value.storage = 'git';
|
||||||
|
} else {
|
||||||
|
combine.value.storage = 'minio';
|
||||||
|
}
|
||||||
|
let moduleIds: string[] = [props.activeFolder, ...props.offspringIds];
|
||||||
|
|
||||||
|
if (isMyOrAllFolder.value) {
|
||||||
|
moduleIds = [];
|
||||||
|
}
|
||||||
|
setLoadListParams({
|
||||||
|
keyword: keyword.value,
|
||||||
|
fileType: tableFileType.value,
|
||||||
|
moduleIds,
|
||||||
|
projectId: appStore.currentProjectId,
|
||||||
|
combine: combine.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchList = debounce(() => {
|
||||||
|
setTableParams();
|
||||||
|
loadList();
|
||||||
|
emitTableParams();
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化文件类型筛选选项
|
||||||
|
*/
|
||||||
|
async function initFileTypes() {
|
||||||
|
try {
|
||||||
|
fileTypeLoading.value = true;
|
||||||
|
let res = null;
|
||||||
|
if (fileType.value === 'storage') {
|
||||||
|
res = await getRepositoryFileTypes(appStore.currentProjectId);
|
||||||
|
} else {
|
||||||
|
res = await getFileTypes(appStore.currentProjectId);
|
||||||
|
}
|
||||||
|
tableFileType.value = '';
|
||||||
|
tableFileTypeOptions.value = res;
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
fileTypeLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.activeFolderType,
|
||||||
|
() => {
|
||||||
|
initFileTypes();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.activeFolderType,
|
||||||
|
(val) => {
|
||||||
|
if (val === 'folder') {
|
||||||
|
fileType.value = 'module';
|
||||||
|
} else {
|
||||||
|
fileType.value = val;
|
||||||
|
}
|
||||||
|
setTableParams();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.activeFolder,
|
||||||
|
() => {
|
||||||
|
keyword.value = '';
|
||||||
|
searchList();
|
||||||
|
resetSelector();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const moduleInfo = computed(() => {
|
||||||
|
if (props.showType === 'Module') {
|
||||||
|
return {
|
||||||
|
name: findNodeByKey<Record<string, any>>(props.folderTree, props.activeFolder, 'id')?.name,
|
||||||
|
count: props.modulesCount[props.activeFolder],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const storageItem = props.storageList.find((item) => item.id === props.activeFolder);
|
||||||
|
return {
|
||||||
|
name: storageItem?.name,
|
||||||
|
count: storageItem?.count,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableSelected = ref<AssociatedList[]>([]);
|
||||||
|
|
||||||
|
const selectedIds = computed(() => {
|
||||||
|
return [...propsRes.value.selectedKeys];
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => selectedIds.value,
|
||||||
|
() => {
|
||||||
|
tableSelected.value = propsRes.value.data.filter((item: any) => selectedIds.value.indexOf(item.id) > -1);
|
||||||
|
emit('update:selectFile', tableSelected.value);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
resetSelector,
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
resetSelector();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
resetSelector();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.header {
|
||||||
|
@apply flex items-center justify-between;
|
||||||
|
|
||||||
|
margin-bottom: 16px;
|
||||||
|
.header-right {
|
||||||
|
@apply ml-auto flex items-center justify-end;
|
||||||
|
|
||||||
|
width: 70%;
|
||||||
|
gap: 8px;
|
||||||
|
.show-type-icon {
|
||||||
|
:deep(.arco-radio-button-content) {
|
||||||
|
@apply flex;
|
||||||
|
|
||||||
|
padding: 4px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,273 @@
|
||||||
|
<template>
|
||||||
|
<MsDrawer
|
||||||
|
v-model:visible="showDrawer"
|
||||||
|
:mask="false"
|
||||||
|
:title="t('caseManagement.featureCase.associatedFile')"
|
||||||
|
:ok-text="t('caseManagement.featureCase.associated')"
|
||||||
|
:ok-loading="drawerLoading"
|
||||||
|
:ok-disabled="selectFile.length < 1"
|
||||||
|
:width="1200"
|
||||||
|
unmount-on-close
|
||||||
|
:show-continue="false"
|
||||||
|
@confirm="handleDrawerConfirm"
|
||||||
|
@cancel="handleDrawerCancel"
|
||||||
|
>
|
||||||
|
<MsSplitBox>
|
||||||
|
<template #left>
|
||||||
|
<div class="p-[16px] pt-0">
|
||||||
|
<div class="folder">
|
||||||
|
<div class="folder-text">
|
||||||
|
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
|
||||||
|
<div class="folder-name">{{ t('project.fileManagement.allFile') }}</div>
|
||||||
|
<div class="folder-count">({{ allFileCount }})</div>
|
||||||
|
</div>
|
||||||
|
<div class="ml-auto flex items-center">
|
||||||
|
<a-tooltip
|
||||||
|
:content="isExpandAll ? t('project.fileManagement.collapseAll') : t('project.fileManagement.expandAll')"
|
||||||
|
>
|
||||||
|
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="changeExpand">
|
||||||
|
<MsIcon :type="isExpandAll ? 'icon-icon_folder_collapse1' : 'icon-icon_folder_expansion1'" />
|
||||||
|
</MsButton>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-divider class="my-[8px]" />
|
||||||
|
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type" @change="changeShowType">
|
||||||
|
<a-radio value="Module">{{ t('project.fileManagement.module') }}</a-radio>
|
||||||
|
<a-radio value="Storage">{{ t('project.fileManagement.storage') }}</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
<div v-show="showType === 'Module'">
|
||||||
|
<FileTree
|
||||||
|
ref="folderTreeRef"
|
||||||
|
v-model:selected-keys="selectedKeys"
|
||||||
|
v-model:active-folder="activeFolder"
|
||||||
|
:is-expand-all="isExpandAll"
|
||||||
|
:modules-count="modulesCount"
|
||||||
|
:show-type="showType"
|
||||||
|
:get-tree-request="props.getTreeRequest"
|
||||||
|
@init="setRootModules"
|
||||||
|
@folder-node-select="folderNodeSelect"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-show="showType === 'Storage'">
|
||||||
|
<StorageList
|
||||||
|
v-model:drawer-visible="storageDrawerVisible"
|
||||||
|
v-model:active-folder="activeFolder"
|
||||||
|
:modules-count="modulesCount"
|
||||||
|
:show-type="showType"
|
||||||
|
@item-click="storageItemSelect"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #right>
|
||||||
|
<LinkFileTable
|
||||||
|
v-model:selectFile="selectFile"
|
||||||
|
:active-folder="activeFolder"
|
||||||
|
:active-folder-type="activeFolderType"
|
||||||
|
:offspring-ids="offspringIds"
|
||||||
|
:modules-count="modulesCount"
|
||||||
|
:folder-tree="folderTree"
|
||||||
|
:storage-list="storageList"
|
||||||
|
:show-type="showType"
|
||||||
|
:get-list-request="props.getListRequest"
|
||||||
|
@init="handleModuleTableInit"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</MsSplitBox>
|
||||||
|
</MsDrawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||||
|
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||||
|
import FileTree from './fileTree.vue';
|
||||||
|
import LinkFileTable from './linkFileTable.vue';
|
||||||
|
import StorageList from './storageList.vue';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
|
import type { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||||
|
import type { CommonList, TableQueryParams } from '@/models/common';
|
||||||
|
import { FileListQueryParams, ModuleTreeNode, Repository } from '@/models/projectManagement/file';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
visible: boolean;
|
||||||
|
getTreeRequest: (params: any) => Promise<ModuleTreeNode[]>; // 获取左侧树请求
|
||||||
|
getCountRequest: (params: any) => Promise<Record<string, any>>; // 获取左侧树模块数量请求
|
||||||
|
getListRequest: (params: TableQueryParams) => Promise<CommonList<AssociatedList>>; // 获取表格请求
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'save', val: AssociatedList[]): void;
|
||||||
|
(e: 'update:visible', val: boolean): void;
|
||||||
|
}>();
|
||||||
|
const showDrawer = computed({
|
||||||
|
get() {
|
||||||
|
return props.visible;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
emit('update:visible', val);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const drawerLoading = ref<boolean>(false);
|
||||||
|
|
||||||
|
const activeFolderType = ref<'folder' | 'module' | 'storage'>('module');
|
||||||
|
|
||||||
|
const activeFolder = ref<string>('root');
|
||||||
|
const selectedKeys = computed({
|
||||||
|
get: () => [activeFolder.value],
|
||||||
|
set: (val) => val,
|
||||||
|
});
|
||||||
|
const offspringIds = ref<string[]>([]);
|
||||||
|
|
||||||
|
const modulesCount = ref<Record<string, number>>({});
|
||||||
|
const myFileCount = ref(0);
|
||||||
|
const allFileCount = ref(0);
|
||||||
|
|
||||||
|
const isExpandAll = ref(false);
|
||||||
|
|
||||||
|
function changeExpand() {
|
||||||
|
isExpandAll.value = !isExpandAll.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileShowType = 'Module' | 'Storage';
|
||||||
|
const showType = ref<FileShowType>('Module');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理文件夹树节点选中事件
|
||||||
|
*/
|
||||||
|
function folderNodeSelect(keys: string[], _offspringIds: string[]) {
|
||||||
|
[activeFolder.value] = keys;
|
||||||
|
activeFolderType.value = 'module';
|
||||||
|
offspringIds.value = [..._offspringIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置根模块名称列表
|
||||||
|
* @param names 根模块名称列表
|
||||||
|
*/
|
||||||
|
|
||||||
|
const folderTree = ref<ModuleTreeNode[]>([]);
|
||||||
|
const rootModulesName = ref<string[]>([]); // 根模块名称列表
|
||||||
|
function setRootModules(treeNode: ModuleTreeNode[]) {
|
||||||
|
folderTree.value = treeNode;
|
||||||
|
rootModulesName.value = treeNode.map((e) => e.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 初始化模块文件数量
|
||||||
|
*/
|
||||||
|
async function initModulesCount(params: FileListQueryParams) {
|
||||||
|
try {
|
||||||
|
modulesCount.value = await props.getCountRequest(params);
|
||||||
|
myFileCount.value = modulesCount.value.my || 0;
|
||||||
|
allFileCount.value = modulesCount.value.all || 0;
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableFilterParams = ref<FileListQueryParams>({
|
||||||
|
moduleIds: [],
|
||||||
|
fileType: '',
|
||||||
|
projectId: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
function changeShowType(val: string | number | boolean) {
|
||||||
|
showType.value = val as FileShowType;
|
||||||
|
if (val === 'Storage') {
|
||||||
|
initModulesCount({
|
||||||
|
...tableFilterParams.value,
|
||||||
|
combine: {
|
||||||
|
...tableFilterParams.value.combine,
|
||||||
|
storage: 'git',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
initModulesCount(tableFilterParams.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 右侧表格数据刷新后,若当前展示的是模块,则刷新模块树的统计数量
|
||||||
|
*/
|
||||||
|
function handleModuleTableInit(params: FileListQueryParams) {
|
||||||
|
initModulesCount(params);
|
||||||
|
tableFilterParams.value = { ...params };
|
||||||
|
}
|
||||||
|
|
||||||
|
const storageDrawerVisible = ref(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理存储库列表项选中事件
|
||||||
|
*/
|
||||||
|
const storageList = ref<Repository[]>([]);
|
||||||
|
function storageItemSelect(key: string, storages: Repository[]) {
|
||||||
|
storageList.value = storages;
|
||||||
|
activeFolder.value = key;
|
||||||
|
activeFolderType.value = 'storage';
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectFile = ref<AssociatedList[]>([]);
|
||||||
|
|
||||||
|
function handleDrawerConfirm() {
|
||||||
|
emit('save', selectFile.value);
|
||||||
|
showDrawer.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrawerCancel() {
|
||||||
|
showDrawer.value = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.folder {
|
||||||
|
@apply flex cursor-pointer items-center justify-between;
|
||||||
|
|
||||||
|
padding: 8px 4px;
|
||||||
|
border-radius: var(--border-radius-small);
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(var(--primary-1));
|
||||||
|
}
|
||||||
|
.folder-text {
|
||||||
|
@apply flex cursor-pointer items-center;
|
||||||
|
.folder-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: var(--color-text-4);
|
||||||
|
}
|
||||||
|
.folder-name {
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
.folder-count {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: var(--color-text-4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.folder-text--active {
|
||||||
|
.folder-icon,
|
||||||
|
.folder-name,
|
||||||
|
.folder-count {
|
||||||
|
color: rgb(var(--primary-5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.file-show-type {
|
||||||
|
@apply grid grid-cols-2;
|
||||||
|
|
||||||
|
margin-bottom: 8px;
|
||||||
|
:deep(.arco-radio-button-content) {
|
||||||
|
@apply text-center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.arco-drawer-body) {
|
||||||
|
padding: 0 16px !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,169 @@
|
||||||
|
<template>
|
||||||
|
<a-input
|
||||||
|
v-model:model-value="storageKeyword"
|
||||||
|
:placeholder="t('project.fileManagement.folderSearchPlaceholder')"
|
||||||
|
allow-clear
|
||||||
|
class="mb-[8px]"
|
||||||
|
></a-input>
|
||||||
|
<a-spin class="h-full w-full" :loading="loading">
|
||||||
|
<MsList
|
||||||
|
v-model:focus-item-key="focusItemKey"
|
||||||
|
:virtual-list-props="{
|
||||||
|
height: 'calc(100vh - 325px)',
|
||||||
|
}"
|
||||||
|
:data="storageList"
|
||||||
|
:bordered="false"
|
||||||
|
:split="false"
|
||||||
|
:empty-text="t('project.fileManagement.noStorage')"
|
||||||
|
item-key-field="id"
|
||||||
|
class="mr-[-6px]"
|
||||||
|
>
|
||||||
|
<template #title="{ item, index }">
|
||||||
|
<div :key="index" class="storage" @click="setActiveFolder(item.id)">
|
||||||
|
<div :class="activeStorageNode === item.id ? 'storage-text storage-text--active' : 'storage-text'">
|
||||||
|
<MsIcon type="icon-icon_git" class="storage-icon" />
|
||||||
|
<div class="storage-name">{{ item.name }}</div>
|
||||||
|
<div class="storage-count">({{ item.count }})</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MsList>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import { debounce } from 'lodash-es';
|
||||||
|
|
||||||
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
|
import MsList from '@/components/pure/ms-list/index.vue';
|
||||||
|
|
||||||
|
import { getRepositories } from '@/api/modules/project-management/fileManagement';
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
|
import { Repository } from '@/models/projectManagement/file';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
activeFolder: string | number;
|
||||||
|
drawerVisible: boolean;
|
||||||
|
showType: string;
|
||||||
|
modulesCount?: Record<string, number>; // 模块数量统计对象
|
||||||
|
}>();
|
||||||
|
const emit = defineEmits(['update:drawerVisible', 'itemClick', 'update:activeFolder']);
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const activeStorageNode = computed({
|
||||||
|
get() {
|
||||||
|
return props.activeFolder;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
emit('update:activeFolder', val);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const storageKeyword = ref('');
|
||||||
|
const originStorageList = ref<Repository[]>([]);
|
||||||
|
const storageList = ref(originStorageList.value);
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const searchStorage = debounce(() => {
|
||||||
|
storageList.value = originStorageList.value.filter((item) => item.name.includes(storageKeyword.value));
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => storageKeyword.value,
|
||||||
|
() => {
|
||||||
|
if (storageKeyword.value === '') {
|
||||||
|
storageList.value = [...originStorageList.value];
|
||||||
|
}
|
||||||
|
searchStorage();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化存储库列表
|
||||||
|
*/
|
||||||
|
async function initRepositories(setDefaultKeys = false) {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await getRepositories(appStore.currentProjectId);
|
||||||
|
originStorageList.value = res;
|
||||||
|
storageList.value = originStorageList.value.map((e) => ({
|
||||||
|
...e,
|
||||||
|
count: props.modulesCount?.[e.id] || 0,
|
||||||
|
}));
|
||||||
|
if (setDefaultKeys) {
|
||||||
|
activeStorageNode.value = storageList.value[0].id;
|
||||||
|
emit('itemClick', storageList.value[0].id, storageList.value);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.showType,
|
||||||
|
(val) => {
|
||||||
|
if (val === 'Storage') {
|
||||||
|
initRepositories(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化模块文件数量
|
||||||
|
*/
|
||||||
|
watch(
|
||||||
|
() => props.modulesCount,
|
||||||
|
(obj) => {
|
||||||
|
storageList.value = originStorageList.value.map((e) => ({
|
||||||
|
...e,
|
||||||
|
count: obj?.[e.id] || 0,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const focusItemKey = ref('');
|
||||||
|
|
||||||
|
function setActiveFolder(id: string) {
|
||||||
|
emit('itemClick', id, storageList.value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.storage {
|
||||||
|
@apply flex cursor-pointer items-center justify-between;
|
||||||
|
|
||||||
|
border-radius: var(--border-radius-small);
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(var(--primary-1));
|
||||||
|
}
|
||||||
|
.storage-text {
|
||||||
|
@apply flex cursor-pointer items-center;
|
||||||
|
.storage-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: var(--color-text-4);
|
||||||
|
}
|
||||||
|
.storage-name {
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
.storage-count {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: var(--color-text-4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.storage-text--active {
|
||||||
|
.storage-icon,
|
||||||
|
.storage-name,
|
||||||
|
.storage-count {
|
||||||
|
color: rgb(var(--primary-5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,53 +1,71 @@
|
||||||
<template>
|
<template>
|
||||||
<MsCard :special-height="-54" no-content-padding divider-has-p-x has-breadcrumb :title="title">
|
<MsCard
|
||||||
|
:special-height="-54"
|
||||||
|
no-content-padding
|
||||||
|
divider-has-p-x
|
||||||
|
has-breadcrumb
|
||||||
|
:title="title"
|
||||||
|
:loading="loading"
|
||||||
|
@save="saveHandler"
|
||||||
|
@save-and-continue="saveHandler"
|
||||||
|
>
|
||||||
<template #headerRight>
|
<template #headerRight>
|
||||||
<a-select
|
<a-select
|
||||||
v-model="templateId"
|
v-model="form.templateId"
|
||||||
class="w-[240px]"
|
class="w-[240px]"
|
||||||
:options="templateOption"
|
:options="templateOption"
|
||||||
allow-search
|
allow-search
|
||||||
:placeholder="t('bugManagement.edit.defaultSystemTemplate')"
|
:placeholder="t('bugManagement.edit.defaultSystemTemplate')"
|
||||||
|
@change="templateChange"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<a-form ref="formRef" :model="form" layout="vertical">
|
<a-form ref="formRef" :model="form" layout="vertical">
|
||||||
<div class="flex flex-row" style="height: calc(100vh - 224px)">
|
<div class="flex flex-row" style="height: calc(100vh - 224px)">
|
||||||
<div class="left mt-[16px] min-w-[732px] grow pl-[24px]">
|
<div class="left mt-[16px] min-w-[732px] grow pl-[24px]">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
field="name"
|
field="title"
|
||||||
:label="t('bugManagement.bugName')"
|
:label="t('bugManagement.bugName')"
|
||||||
:rules="[{ required: true, message: t('bugManagement.edit.nameIsRequired') }]"
|
:rules="[{ required: true, message: t('bugManagement.edit.nameIsRequired') }]"
|
||||||
:placeholder="t('bugManagement.edit.pleaseInputBugName')"
|
:placeholder="t('bugManagement.edit.pleaseInputBugName')"
|
||||||
>
|
>
|
||||||
<a-input v-model="form.name" :max-length="255" show-word-limit />
|
<a-input v-model="form.title" :max-length="255" show-word-limit />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :label="t('bugManagement.edit.content')">
|
<a-form-item field="description" :label="t('bugManagement.edit.content')">
|
||||||
<MsRichText v-model="form.content" />
|
<MsRichText v-model="form.description" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="attachment" :label="t('bugManagement.edit.file')">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="mb-1">
|
||||||
|
<a-dropdown position="tr" trigger="hover">
|
||||||
|
<a-button type="outline">
|
||||||
|
<template #icon> <icon-plus class="text-[14px]" /> </template>
|
||||||
|
{{ t('bugManagement.edit.uploadFile') }}
|
||||||
|
</a-button>
|
||||||
|
<template #content>
|
||||||
|
<a-upload
|
||||||
|
ref="uploadRef"
|
||||||
|
v-model:file-list="fileList"
|
||||||
|
:auto-upload="false"
|
||||||
|
:show-file-list="false"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
@change="handleChange"
|
||||||
|
>
|
||||||
|
<template #upload-button>
|
||||||
|
<a-button type="text" class="!text-[var(--color-text-1)]">
|
||||||
|
<icon-upload />{{ t('bugManagement.edit.localUpload') }}</a-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</a-upload>
|
||||||
|
<a-button type="text" class="!text-[var(--color-text-1)]" @click="associatedFile">
|
||||||
|
<MsIcon type="icon-icon_link-copy_outlined" size="16" />{{
|
||||||
|
t('bugManagement.edit.linkFile')
|
||||||
|
}}</a-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('bugManagement.edit.file') }}</div>
|
|
||||||
|
|
||||||
<a-dropdown trigger="hover">
|
|
||||||
<template #content>
|
|
||||||
<MsUpload
|
|
||||||
v-model:file-list="fileList"
|
|
||||||
:auto-upload="false"
|
|
||||||
multiple
|
|
||||||
draggable
|
|
||||||
accept="unknown"
|
|
||||||
is-limit
|
|
||||||
size-unit="MB"
|
|
||||||
:max-size="500"
|
|
||||||
>
|
|
||||||
<a-doption>{{ t('bugManagement.edit.localUpload') }}</a-doption>
|
|
||||||
</MsUpload>
|
|
||||||
<a-doption @click="handleLineFile">{{ t('bugManagement.edit.linkFile') }}</a-doption>
|
|
||||||
</template>
|
|
||||||
<a-button type="outline">
|
|
||||||
<template #icon>
|
|
||||||
<icon-plus />
|
|
||||||
</template>
|
|
||||||
{{ t('bugManagement.edit.uploadFile') }}
|
|
||||||
</a-button>
|
|
||||||
</a-dropdown>
|
|
||||||
<div class="mb-[8px] mt-[2px] text-[var(--color-text-4)]">{{ t('bugManagement.edit.fileExtra') }}</div>
|
<div class="mb-[8px] mt-[2px] text-[var(--color-text-4)]">{{ t('bugManagement.edit.fileExtra') }}</div>
|
||||||
<FileList
|
<FileList
|
||||||
:show-tab="false"
|
:show-tab="false"
|
||||||
|
@ -60,33 +78,25 @@
|
||||||
</FileList>
|
</FileList>
|
||||||
</div>
|
</div>
|
||||||
<a-divider class="ml-[16px]" direction="vertical" />
|
<a-divider class="ml-[16px]" direction="vertical" />
|
||||||
<div class="right mt-[16px] grow pr-[24px]">
|
<div class="right mt-[16px] max-w-[433px] grow pr-[24px]">
|
||||||
<a-form-item
|
<!-- <a-form-item
|
||||||
:label="t('bugManagement.handleMan')"
|
:label="t('bugManagement.handleMan')"
|
||||||
field="handleMan"
|
field="handleMan"
|
||||||
:rules="[{ required: true, message: t('bugManagement.edit.handleManIsRequired') }]"
|
:rules="[{ required: true, message: t('bugManagement.edit.handleManIsRequired') }]"
|
||||||
>
|
>
|
||||||
<MsUserSelector
|
<MsUserSelector
|
||||||
v-model:model-value="form.handleMan"
|
v-model:model-value="form.handleMan"
|
||||||
|
:type="UserRequestTypeEnum.PROJECT_PERMISSION_MEMBER"
|
||||||
|
:load-option-params="{ projectId: appStore.currentProjectId }"
|
||||||
placeholder="bugManagement.edit.handleManPlaceholder"
|
placeholder="bugManagement.edit.handleManPlaceholder"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item> -->
|
||||||
<a-form-item
|
<MsFormCreate
|
||||||
field="status"
|
v-if="formRules.length"
|
||||||
:label="t('bugManagement.status')"
|
ref="formCreateRef"
|
||||||
:rules="[{ required: true, message: t('bugManagement.edit.statusIsRequired') }]"
|
:form-rule="formRules"
|
||||||
>
|
:form-create-key="FormCreateKeyEnum.BUG_DETAIL"
|
||||||
<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-form-item field="tag" :label="t('bugManagement.tag')">
|
||||||
<a-input-tag
|
<a-input-tag
|
||||||
v-model:model-value="form.tag"
|
v-model:model-value="form.tag"
|
||||||
|
@ -98,21 +108,64 @@
|
||||||
</div>
|
</div>
|
||||||
</a-form>
|
</a-form>
|
||||||
</MsCard>
|
</MsCard>
|
||||||
|
<div>
|
||||||
|
<MsUpload
|
||||||
|
v-model:file-list="fileList"
|
||||||
|
accept="none"
|
||||||
|
:auto-upload="false"
|
||||||
|
:sub-text="acceptType === 'jar' ? '' : t('project.fileManagement.normalFileSubText', { size: 50 })"
|
||||||
|
multiple
|
||||||
|
draggable
|
||||||
|
size-unit="MB"
|
||||||
|
:max-size="50"
|
||||||
|
:is-all-screen="true"
|
||||||
|
class="mb-[16px]"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<RelateFileDrawer
|
||||||
|
v-model:visible="associatedDrawer"
|
||||||
|
:get-tree-request="getModules"
|
||||||
|
:get-count-request="getModulesCount"
|
||||||
|
:get-list-request="getAssociatedFileList"
|
||||||
|
@save="saveSelectAssociatedFile"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { FileItem } from '@arco-design/web-vue';
|
import { FileItem, Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||||
|
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||||
|
import { FormItem } from '@/components/pure/ms-form-create/types';
|
||||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||||
import FileList from '@/components/pure/ms-upload/fileList.vue';
|
import FileList from '@/components/pure/ms-upload/fileList.vue';
|
||||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||||
import { MsUserSelector } from '@/components/business/ms-user-selector';
|
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
|
import RelateFileDrawer from './components/relateFile/relateFileDrawer.vue';
|
||||||
|
|
||||||
import { getTemplageOption } from '@/api/modules/bug-management';
|
// import { MsUserSelector } from '@/components/business/ms-user-selector';
|
||||||
|
// import { UserRequestTypeEnum } from '@/components/business/ms-user-selector/utils';
|
||||||
|
import {
|
||||||
|
createBug,
|
||||||
|
getAssociatedFileList,
|
||||||
|
getBugDetail,
|
||||||
|
getTemplageOption,
|
||||||
|
getTemplateById,
|
||||||
|
} from '@/api/modules/bug-management';
|
||||||
|
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
|
import useFormCreateStore from '@/store/modules/form-create/form-create';
|
||||||
|
import { scrollIntoView } from '@/utils/dom';
|
||||||
|
|
||||||
|
import { BugEditCustomField, BugEditCustomFieldItem, BugEditFormObject } from '@/models/bug-management';
|
||||||
|
import { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||||
|
import { SelectValue } from '@/models/projectManagement/menuManagement';
|
||||||
|
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||||
|
|
||||||
|
import { convertToFile } from '../case-management/caseManagementFeature/components/utils';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
@ -122,36 +175,73 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
const formCreateStore = useFormCreateStore();
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const templateOption = ref<TemplateOption[]>([]);
|
const templateOption = ref<TemplateOption[]>([]);
|
||||||
const form = ref({
|
const form = ref<BugEditFormObject>({
|
||||||
name: '',
|
projectId: appStore.currentProjectId,
|
||||||
content: '',
|
title: '',
|
||||||
|
description: '',
|
||||||
templateId: '',
|
templateId: '',
|
||||||
handleMan: [],
|
|
||||||
status: '',
|
|
||||||
severity: '',
|
|
||||||
tag: [],
|
tag: [],
|
||||||
});
|
});
|
||||||
const formRef = ref<any>(null);
|
const formRef = ref();
|
||||||
|
const formCreateRef = ref();
|
||||||
|
|
||||||
const fileList = ref<FileItem[]>([]);
|
const fileList = ref<FileItem[]>([]);
|
||||||
|
const formRules = ref<FormItem[]>([]);
|
||||||
|
const associatedDrawer = ref(false);
|
||||||
|
const loading = ref(false);
|
||||||
|
const acceptType = ref('none'); // 模块-上传文件类型
|
||||||
|
|
||||||
// 模板id
|
|
||||||
const templateId = ref<string>('');
|
|
||||||
const isEdit = computed(() => !!route.query.id);
|
const isEdit = computed(() => !!route.query.id);
|
||||||
|
|
||||||
const title = computed(() => {
|
const title = computed(() => {
|
||||||
return isEdit.value ? t('bugManagement.editBug') : t('bugManagement.createBug');
|
return isEdit.value ? t('bugManagement.editBug') : t('bugManagement.createBug');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 处理表单格式
|
||||||
|
const getFormRules = (arr: BugEditCustomField[]) => {
|
||||||
|
formRules.value = [];
|
||||||
|
if (Array.isArray(arr) && arr.length) {
|
||||||
|
formRules.value = arr.map((item) => {
|
||||||
|
return {
|
||||||
|
type: item.type,
|
||||||
|
name: item.fieldId,
|
||||||
|
label: item.fieldName,
|
||||||
|
value: item.value,
|
||||||
|
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : [],
|
||||||
|
required: item.required as boolean,
|
||||||
|
props: {
|
||||||
|
modelValue: item.value,
|
||||||
|
options: item.platformOptionJson ? JSON.parse(item.platformOptionJson) : [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const templateChange = async (v: SelectValue) => {
|
||||||
|
if (v) {
|
||||||
|
try {
|
||||||
|
const res = await getTemplateById({ projectId: appStore.currentProjectId, id: v });
|
||||||
|
getFormRules(res.customFields);
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getTemplateOptions = async () => {
|
const getTemplateOptions = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await getTemplageOption({ projectId: appStore.currentProjectId });
|
const res = await getTemplageOption({ projectId: appStore.currentProjectId });
|
||||||
templateOption.value = res.map((item) => {
|
templateOption.value = res.map((item) => {
|
||||||
if (item.enableDefault && !isEdit.value) {
|
if (item.enableDefault && !isEdit.value) {
|
||||||
templateId.value = item.id;
|
// 当创建时 选中默认模板
|
||||||
|
form.value.templateId = item.id;
|
||||||
|
templateChange(item.id);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
label: item.name,
|
label: item.name,
|
||||||
|
@ -196,10 +286,95 @@
|
||||||
return Promise.resolve(fileItem);
|
return Promise.resolve(fileItem);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLineFile = () => {};
|
function beforeUpload(file: File) {
|
||||||
|
const _maxSize = 50 * 1024 * 1024;
|
||||||
|
if (file.size > _maxSize) {
|
||||||
|
Message.warning(t('ms.upload.overSize'));
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function associatedFile() {
|
||||||
|
associatedDrawer.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChange(_fileList: MsFileItem[]) {
|
||||||
|
fileList.value = _fileList.map((e) => {
|
||||||
|
return {
|
||||||
|
...e,
|
||||||
|
enable: true, // 是否启用
|
||||||
|
local: true, // 是否本地文件
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理关联文件
|
||||||
|
function saveSelectAssociatedFile(fileData: AssociatedList[]) {
|
||||||
|
const fileResultList = fileData.map((fileInfo) => convertToFile(fileInfo));
|
||||||
|
fileList.value.push(...fileResultList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存
|
||||||
|
const saveHandler = async () => {
|
||||||
|
formRef.value.validate((error: any) => {
|
||||||
|
if (!error) {
|
||||||
|
formCreateRef.value.formApi.validate(async (valid: any) => {
|
||||||
|
if (valid === true) {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const customFields: BugEditCustomFieldItem[] = [];
|
||||||
|
const formRuleList = formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.BUG_DETAIL);
|
||||||
|
if (formRuleList && formRuleList.length) {
|
||||||
|
formRuleList.forEach((item) => {
|
||||||
|
customFields.push({
|
||||||
|
id: item.field as string,
|
||||||
|
name: item.title as string,
|
||||||
|
type: item.sourceType as string,
|
||||||
|
value: item.value as string,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const tmpObj = {
|
||||||
|
...form.value,
|
||||||
|
tag: form.value.tag.join(',') || '',
|
||||||
|
customFields,
|
||||||
|
};
|
||||||
|
await createBug({ request: tmpObj, fileList: fileList.value as unknown as File[] });
|
||||||
|
Message.success(t('common.createSuccess'));
|
||||||
|
} catch (err) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(err);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDetailInfo = async () => {
|
||||||
|
const id = route.query.id as string;
|
||||||
|
// TODO: 等后端接口
|
||||||
|
const res = await getBugDetail(id);
|
||||||
|
const { customFields, file } = res;
|
||||||
|
formRules.value = customFields;
|
||||||
|
fileList.value = file;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initDefaultFields = () => {
|
||||||
|
getTemplateOptions();
|
||||||
|
};
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
getTemplateOptions();
|
if (isEdit.value) {
|
||||||
|
// 详情
|
||||||
|
getDetailInfo();
|
||||||
|
} else {
|
||||||
|
initDefaultFields();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,7 @@
|
||||||
noDisable: false,
|
noDisable: false,
|
||||||
size: 'default',
|
size: 'default',
|
||||||
showSetting: true,
|
showSetting: true,
|
||||||
|
heightUsed: 286,
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
(record) => handleNameChange(record)
|
(record) => handleNameChange(record)
|
||||||
|
|
|
@ -166,6 +166,7 @@
|
||||||
noDisable: false,
|
noDisable: false,
|
||||||
size: 'default',
|
size: 'default',
|
||||||
showSetting: true,
|
showSetting: true,
|
||||||
|
heightUsed: 286,
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
handleNameChange
|
handleNameChange
|
||||||
|
|
|
@ -161,6 +161,7 @@
|
||||||
{
|
{
|
||||||
tableKey: TableKeyEnum.SYSTEM_PROJECT,
|
tableKey: TableKeyEnum.SYSTEM_PROJECT,
|
||||||
scroll: { x: '1600px' },
|
scroll: { x: '1600px' },
|
||||||
|
heightUsed: 286,
|
||||||
selectable: false,
|
selectable: false,
|
||||||
noDisable: false,
|
noDisable: false,
|
||||||
size: 'default',
|
size: 'default',
|
||||||
|
|
Loading…
Reference in New Issue