feat(系统管理): 组织模板管理页面和封装表单级联formCreate
This commit is contained in:
parent
8a711405eb
commit
a7538c1fad
|
@ -9,20 +9,45 @@ import {
|
|||
GetFieldDetailUrl,
|
||||
GetOrganizeTemplateDetailUrl,
|
||||
GetOrganizeTemplateUrl,
|
||||
GetProjectTemplateDetailUrl,
|
||||
isEnableTemplateUrl,
|
||||
SetOrganizeTemplateUrl,
|
||||
UpdateFieldUrl,
|
||||
UpdateOrganizeTemplateUrl,
|
||||
UpdateProjectTemplateUrl,
|
||||
} from '@/api/requrls/setting/template';
|
||||
|
||||
import { CommonList, TableQueryParams } from '@/models/common';
|
||||
import type { AddOrUpdateField, DefinedFieldItem, OrganizeTemplateItem } from '@/models/setting/template';
|
||||
import type {
|
||||
ActionTemplateManage,
|
||||
AddOrUpdateField,
|
||||
DefinedFieldItem,
|
||||
OrganizeTemplateItem,
|
||||
} from '@/models/setting/template';
|
||||
|
||||
/** *
|
||||
* 模版
|
||||
*/
|
||||
// 获取模版列表(组织)
|
||||
export function getOrganizeTemplateList(organizationId: string, scene: string) {
|
||||
return MSR.get<OrganizeTemplateItem[]>({ url: GetOrganizeTemplateUrl, params: `/${organizationId}/${scene}` });
|
||||
export function getOrganizeTemplateList(params: TableQueryParams) {
|
||||
return MSR.get({ url: `${GetOrganizeTemplateUrl}/${params.organizationId}/${params.scene}` });
|
||||
}
|
||||
// 获取模版详情
|
||||
export function getOrganizeTemplateInfo(id: string) {
|
||||
return MSR.get({ url: `${GetOrganizeTemplateDetailUrl}/${id}` });
|
||||
}
|
||||
// 创建模板列表(组织)
|
||||
export function createOrganizeTemplateInfo(data: ActionTemplateManage) {
|
||||
return MSR.post({ url: `${CreateOrganizeTemplateUrl}`, data });
|
||||
}
|
||||
|
||||
// 编辑模板列表(组织)
|
||||
export function updateOrganizeTemplateInfo(data: ActionTemplateManage) {
|
||||
return MSR.post({ url: `${UpdateOrganizeTemplateUrl}`, data });
|
||||
}
|
||||
// 是否启用组织XX模板
|
||||
export function isEnableTemplate(organizationId: string, scene: string) {
|
||||
return MSR.get<boolean>({ url: `${isEnableTemplateUrl}/${organizationId}/${scene}` });
|
||||
}
|
||||
|
||||
/** *
|
||||
|
|
|
@ -29,6 +29,8 @@ export const GetOrganizeTemplateDetailUrl = '/organization/template/get';
|
|||
export const DeleteOrganizeTemplateUrl = '/organization/template/delete';
|
||||
// 关闭组织模板,开启项目模版
|
||||
export const EnableOrOffTemplateUrl = '/organization/template/disable';
|
||||
// 是否启用组织模板
|
||||
export const isEnableTemplateUrl = '/organization/template/is-enable';
|
||||
|
||||
// 系统设置-组织-自定义字段
|
||||
|
||||
|
|
|
@ -209,6 +209,7 @@
|
|||
.arco-select-view,
|
||||
.arco-select-view-single,
|
||||
.arco-select {
|
||||
width: 100%;
|
||||
border: 1px solid var(--color-text-input-border);
|
||||
background-color: var(--color-text-fff);
|
||||
&:not(:disabled):hover {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<MsTransfer
|
||||
v-model="target"
|
||||
:data="treeList"
|
||||
:title="[t('system.user.batchOptional'), t('system.user.batchChosen')]"
|
||||
:tree-filed="{
|
||||
key: 'id',
|
||||
title: 'name',
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
}, true);
|
||||
|
||||
function jumpTo(name: RouteRecordName) {
|
||||
router.push({ name });
|
||||
router.push({ name, query: route.query });
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
import { FormRule } from '@form-create/arco-design';
|
||||
|
||||
// 表单字段使用
|
||||
export const INPUT = {
|
||||
type: 'input',
|
||||
title: '',
|
||||
field: 'fieldName',
|
||||
value: '',
|
||||
props: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
};
|
||||
export const SELECT = {
|
||||
type: 'SearchSelect',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: '',
|
||||
options: [],
|
||||
props: {
|
||||
multiple: false,
|
||||
placeholder: '请选择',
|
||||
options: [],
|
||||
},
|
||||
};
|
||||
|
||||
export const MULTIPLE_SELECT = {
|
||||
type: 'SearchSelect',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: [],
|
||||
options: [],
|
||||
props: {
|
||||
multiple: true,
|
||||
placeholder: '请选择',
|
||||
options: [],
|
||||
},
|
||||
};
|
||||
|
||||
export const RADIO = {
|
||||
type: 'radio',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: '',
|
||||
options: [],
|
||||
};
|
||||
|
||||
export const CHECKBOX = {
|
||||
type: 'checkbox',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: [],
|
||||
options: [],
|
||||
};
|
||||
|
||||
export const MEMBER = {
|
||||
type: 'SearchSelect',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: '',
|
||||
options: [],
|
||||
props: {
|
||||
multiple: false,
|
||||
placeholder: '请选择',
|
||||
},
|
||||
};
|
||||
|
||||
export const MULTIPLE_MEMBER = {
|
||||
type: 'SearchSelect',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: '',
|
||||
options: [],
|
||||
props: {
|
||||
multiple: true,
|
||||
placeholder: '请选择',
|
||||
options: [],
|
||||
},
|
||||
};
|
||||
|
||||
export const DATE = {
|
||||
type: 'DatePicker',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: '',
|
||||
props: {
|
||||
'placeholder': '请选择',
|
||||
'format': 'YYYY/MM/DD',
|
||||
'show-time': false,
|
||||
},
|
||||
};
|
||||
|
||||
export const DATETIME = {
|
||||
type: 'DatePicker',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: '',
|
||||
props: {
|
||||
'placeholder': '请选择',
|
||||
'format': 'YYYY/MM/DD HH:mm:ss',
|
||||
'show-time': true,
|
||||
},
|
||||
};
|
||||
|
||||
export const FLOAT = {
|
||||
type: 'InputNumber',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: 0,
|
||||
props: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
};
|
||||
|
||||
export const INT = {
|
||||
type: 'InputNumber',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: 0,
|
||||
props: {
|
||||
precision: 0,
|
||||
placeholder: '请输入',
|
||||
},
|
||||
};
|
||||
|
||||
export const MULTIPLE_INPUT = {
|
||||
type: 'a-input-tag',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: [],
|
||||
props: {
|
||||
placeholder: '请选择',
|
||||
},
|
||||
};
|
||||
|
||||
export const TEXTAREA = {
|
||||
type: 'a-textarea',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: '',
|
||||
props: {
|
||||
'placeholder': '请输入',
|
||||
'auto-size': {
|
||||
minRows: 1,
|
||||
maxRows: 3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const FieldTypeFormRules: Record<string, FormRule> = {
|
||||
INPUT,
|
||||
SELECT,
|
||||
MULTIPLE_SELECT,
|
||||
RADIO,
|
||||
CHECKBOX,
|
||||
MEMBER,
|
||||
MULTIPLE_MEMBER,
|
||||
DATE,
|
||||
DATETIME,
|
||||
INT,
|
||||
FLOAT,
|
||||
MULTIPLE_INPUT,
|
||||
TEXTAREA,
|
||||
};
|
|
@ -0,0 +1,109 @@
|
|||
<template>
|
||||
<FormCreate v-model:api="formApi" :rule="formRules" :option="props.options || option"></FormCreate>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import { debounce } from 'lodash-es';
|
||||
|
||||
import PassWord from './formcreate-password.vue';
|
||||
import SearchSelect from './searchSelect.vue';
|
||||
|
||||
import useFormCreateStore from '@/store/modules/form-create/form-create';
|
||||
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
import type { FormItem } from './types';
|
||||
import { FormRuleItem } from './types';
|
||||
import formCreate, { FormRule } from '@form-create/arco-design';
|
||||
|
||||
const formCreateStore = useFormCreateStore();
|
||||
|
||||
formCreate.component('PassWord', PassWord);
|
||||
formCreate.component('SearchSelect', SearchSelect);
|
||||
|
||||
const FormCreate = formCreate.$form();
|
||||
const option = {
|
||||
resetBtn: false, // 不展示默认配置的重置和提交
|
||||
submitBtn: false,
|
||||
on: false, // 取消绑定on事件
|
||||
form: {
|
||||
layout: 'vertical',
|
||||
labelAlign: 'left',
|
||||
},
|
||||
// 暂时默认
|
||||
row: {
|
||||
gutter: 0,
|
||||
},
|
||||
wrap: {
|
||||
'asterisk-position': 'end',
|
||||
'validate-trigger': ['change'],
|
||||
},
|
||||
};
|
||||
// 处理配置项
|
||||
const props = defineProps<{
|
||||
options?: any; // 自定义配置
|
||||
formRule: FormItem[]; // 表单的规则
|
||||
formCreateKey: FormCreateKeyEnum[keyof FormCreateKeyEnum]; // 唯一表单Key
|
||||
}>();
|
||||
|
||||
const formApi = ref<any>({});
|
||||
|
||||
const formRules = ref<FormRule | undefined>([]);
|
||||
|
||||
// 计算被级联的项
|
||||
const cascadeItem = computed(() => {
|
||||
const currentFormCreateRules = formCreateStore.formCreateRuleMap.get(props.formCreateKey);
|
||||
// 获取当前列表里边所有包含cascade的item
|
||||
if (currentFormCreateRules) {
|
||||
const cascade = currentFormCreateRules
|
||||
.map((item: FormRuleItem) => item.link)
|
||||
.filter((item) => item)
|
||||
.flatMap((flatItem: any) => flatItem);
|
||||
// 给所有的link上边关联的某个item 进行绑定监视
|
||||
return currentFormCreateRules.filter((item: FormRuleItem) => {
|
||||
return cascade.indexOf(item.field) > -1;
|
||||
});
|
||||
}
|
||||
});
|
||||
// 计算远程检索的表单项
|
||||
const getOptionsRequest = debounce((val: FormRuleItem) => {
|
||||
// 获取当前变化的一项 监视到被级联的表单项
|
||||
// 从所有的列表项里边获取所有的link到的那一项
|
||||
const totalFormList = formCreateStore.formCreateRuleMap.get(props.formCreateKey);
|
||||
if (totalFormList) {
|
||||
const resultItem = totalFormList.find(
|
||||
(item) => item.link && (item.link as string[]).indexOf(val.field as string) > -1
|
||||
);
|
||||
if (resultItem) formCreateStore.getOptions(val, props.formCreateKey, resultItem, formApi.value);
|
||||
}
|
||||
}, 300);
|
||||
|
||||
watch(
|
||||
cascadeItem,
|
||||
(val) => {
|
||||
// 监视当前改变请求获取当前方法下边的options 和获取多有的字段值
|
||||
if (val) {
|
||||
val.forEach((item) => {
|
||||
if (item.value) {
|
||||
getOptionsRequest(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: false }
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
formCreateStore.setInitFormCreate(props.formCreateKey, props.formRule);
|
||||
formCreateStore.initFormCreateFormRules(props.formCreateKey);
|
||||
formRules.value = formCreateStore.formCreateRuleMap.get(props.formCreateKey);
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
formApi, // 对外暴漏用于表单校验和清除校验状态 具体参考form-create文档API
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@/store/modules/form-create/form-create
|
|
@ -6,10 +6,12 @@
|
|||
import { ref, watch, watchEffect } from 'vue';
|
||||
|
||||
import PassWord from './formcreate-password.vue';
|
||||
import SearchSelect from './searchSelect.vue';
|
||||
|
||||
import formCreate, { FormRule } from '@form-create/arco-design';
|
||||
|
||||
formCreate.component('PassWord', PassWord);
|
||||
formCreate.component('SearchSelect', SearchSelect);
|
||||
const FormCreate = formCreate.$form();
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -21,7 +23,7 @@
|
|||
const emits = defineEmits<{
|
||||
(e: 'update:api', val: any): void;
|
||||
}>();
|
||||
const formApi = ref({});
|
||||
const formApi = ref<any>({});
|
||||
|
||||
watchEffect(() => {
|
||||
formApi.value = props.api;
|
||||
|
@ -32,6 +34,18 @@
|
|||
emits('update:api', val);
|
||||
}
|
||||
);
|
||||
|
||||
const formRules = ref<FormRule | undefined>([]);
|
||||
watchEffect(() => {
|
||||
formRules.value = props.rule;
|
||||
});
|
||||
watch(
|
||||
() => props.rule,
|
||||
(val) => {
|
||||
formRules.value = val;
|
||||
formApi.value?.refresh();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
<template>
|
||||
<a-select
|
||||
v-model="selectValue"
|
||||
:placeholder="t(props.placeholder || 'common.pleaseSelect')"
|
||||
allow-search
|
||||
:multiple="props.multiple"
|
||||
@search="searchHandler"
|
||||
>
|
||||
<a-option v-for="opt of optionsList" :key="opt.value" :value="opt.value">{{ opt.label }}</a-option>
|
||||
</a-select>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { debounce } from 'lodash-es';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
optionMethod?: string; // 选项请求方法
|
||||
inputSearch?: boolean; // 是否支持远程检索
|
||||
modelValue: string[] | string | undefined; // 绑定值
|
||||
keyword?: string; // 级联搜索关键词
|
||||
formValue?: Record<string, any>; // 所有表单的值
|
||||
options?: { label: string; value: string }[];
|
||||
multiple?: boolean; // 是否多选
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
inputSearch: false,
|
||||
multiple: false,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits(['update:model-value']);
|
||||
const selectValue = ref([]);
|
||||
|
||||
const optionsList = ref<{ label: string; value: string }[]>([]);
|
||||
|
||||
// 内部的关键词
|
||||
const innerKeyword = ref<string | undefined>('');
|
||||
async function getOptionsList() {
|
||||
if (props.inputSearch && props.optionMethod) {
|
||||
try {
|
||||
setTimeout(() => {
|
||||
// console.log('模拟请求');
|
||||
optionsList.value = [
|
||||
{
|
||||
value: '111',
|
||||
label: '测试测试测试111111',
|
||||
},
|
||||
];
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
const searchHandler = debounce(async (inputVal: string) => {
|
||||
innerKeyword.value = inputVal;
|
||||
getOptionsList();
|
||||
}, 300);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
selectValue.value = val as any;
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => props.keyword,
|
||||
(val) => {
|
||||
if (val) {
|
||||
innerKeyword.value = val;
|
||||
getOptionsList();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => selectValue.value,
|
||||
(val) => {
|
||||
emit('update:model-value', val);
|
||||
}
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.options) optionsList.value = props.options;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -0,0 +1,77 @@
|
|||
import { FieldRule } from '@arco-design/web-vue';
|
||||
|
||||
import { FormRule } from '@form-create/arco-design';
|
||||
|
||||
export type FormItemType =
|
||||
| 'INPUT'
|
||||
| 'TEXTAREA'
|
||||
| 'SELECT'
|
||||
| 'MULTIPLE_SELECT'
|
||||
| 'RADIO'
|
||||
| 'CHECKBOX'
|
||||
| 'MEMBER'
|
||||
| 'MULTIPLE_MEMBER'
|
||||
| 'DATE'
|
||||
| 'DATETIME'
|
||||
| 'INT'
|
||||
| 'FLOAT'
|
||||
| 'MULTIPLE_INPUT'
|
||||
| 'INT'
|
||||
| 'FLOAT'
|
||||
| 'NUMBER';
|
||||
|
||||
// 表单选项
|
||||
export interface FormItemComplexCommonConfig {
|
||||
options: { label: string; value: string | number; disabled: boolean }[]; // 选择器、复选框组、单选框组选项列表
|
||||
optionsRemoteMethodKey?: string; // 选择器、复选框组、单选框组选项列表远程搜索或初始化方法名
|
||||
}
|
||||
export interface FormItemDefaultOptions {
|
||||
text: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export type FormRuleItem = FormRule & {
|
||||
props: Record<string, any>;
|
||||
};
|
||||
// 表单配置项
|
||||
export interface FormItem {
|
||||
type: FormItemType;
|
||||
name: string; // 表单项名称,作为唯一标志 --field
|
||||
label: string; // 表单项文本 --- title
|
||||
// 选择器的值绑定为Record<string, any>,避免携带远程搜索时默认选中的选项不在 options 列表中,所以还需要设置 fallbackOptions
|
||||
value: string | number | boolean | string[] | number[] | Record<string, any> | Record<string, any>[];
|
||||
subDesc?: string; // 表单项描述,在表单项下方显示
|
||||
inputSearch?: boolean; // 是否支持远程搜索
|
||||
tooltip?: ''; // 表单后边的提示info
|
||||
instructionsIcon?: ''; // 是否有图片在表单后边展示
|
||||
optionMethod?: string; // 请求检索的方法 两个参数 表单项的所有值
|
||||
options?: FormItemDefaultOptions[];
|
||||
required: boolean;
|
||||
validate?: FieldRule[];
|
||||
// 表单联动配置
|
||||
couplingConfig?: {
|
||||
// 联动类型,visible:显示隐藏,disabled:禁用启用,filterOptions:过滤选项,disabledOptions:禁用选项,initOptions:初始化选项。都由联动的表单项触发
|
||||
type: 'visible' | 'disabled' | 'filterOptions' | 'disabledOptions' | 'initOptions'; // 目前初始化选项
|
||||
cascade: string; // 联动表单项名称
|
||||
matchRule: 'same' | 'includes' | 'excludes' | RegExp; // 联动匹配规则,same:值相同,includes:值包含,excludes:值不包含, RegExp:自定义匹配正则表达式 // 场景 目前只考虑等于情况
|
||||
}[];
|
||||
// 表单布局
|
||||
wrap?: Record<string, any>;
|
||||
}
|
||||
|
||||
interface FomItemSelect extends FormItemComplexCommonConfig {
|
||||
selectMultiple?: boolean; // 选择器是否多选
|
||||
selectMultipleLimit?: [number, number]; // 选择器多选时最少和最多可选项数,如:[1, 3],表示最少选1项,最多选3项;[0, 3]表示最多选3项,可不选;[1, 0]表示最少选1项,不限制最大可选数
|
||||
}
|
||||
|
||||
interface FomItemCheckbox extends FormItemComplexCommonConfig {
|
||||
checkedAll?: boolean; // 复选框组是否支持全选
|
||||
checkedAllLabel?: string; // 复选框组全选选项文本
|
||||
checkedMax?: number; // 复选框组最多可选项数
|
||||
direction?: 'horizontal' | 'vertical'; // 单选框组选项排列方向,默认为 'horizontal'
|
||||
}
|
||||
|
||||
interface FormItemRadio extends FormItemComplexCommonConfig {
|
||||
type?: 'radio' | 'button'; // 单选框组选项排列方式,默认为 'radio'
|
||||
direction?: 'horizontal' | 'vertical'; // 单选框组选项排列方向,默认为 'horizontal'
|
||||
}
|
|
@ -18,8 +18,8 @@
|
|||
class="mr-[2px] text-xl text-[rgb(var(--danger-6))]"
|
||||
/>
|
||||
</slot>
|
||||
<span :class="titleClass">
|
||||
{{ characterLimit(props.title) || '' }}
|
||||
<span :class="[titleClass]">
|
||||
{{ props.title || '' }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 描述展示 -->
|
||||
|
@ -64,7 +64,7 @@
|
|||
{{ props.cancelText || t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" :loading="props.loading" @click="handleConfirm">
|
||||
{{ props.isDelete ? t('common.remove') : props.okText || t('common.confirm') }}
|
||||
{{ t(props.okText) || t('common.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -79,7 +79,6 @@
|
|||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { characterLimit } from '@/utils';
|
||||
|
||||
import type { FieldRule, FormInstance } from '@arco-design/web-vue';
|
||||
|
||||
|
@ -113,6 +112,7 @@
|
|||
{
|
||||
type: 'warning',
|
||||
isDelete: true, // 默认移除pop
|
||||
okText: 'common.remove',
|
||||
}
|
||||
);
|
||||
const emits = defineEmits<{
|
||||
|
@ -167,7 +167,7 @@
|
|||
// 获取当前标题的样式
|
||||
const titleClass = computed(() => {
|
||||
return props.isDelete
|
||||
? 'ml-2 font-[14px] text-[var(--color-text-1)]'
|
||||
? 'ml-2 font-medium text-[var(--color-text-1)] text-[14px]'
|
||||
: 'mb-[8px] font-medium text-[var(--color-text-1)] text-[14px]';
|
||||
});
|
||||
|
||||
|
|
|
@ -135,7 +135,13 @@
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div style="height: 100vh" class="flex">
|
||||
<div style="height: 140px" class="rich-wrapper flex w-full">
|
||||
<RichTextEditor v-if="editor" :editor="editor" :locale="locale" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.rich-wrapper {
|
||||
border: 1px solid var(--color-text-n8);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -21,7 +21,7 @@ export interface Pagination {
|
|||
const appStore = useAppStore();
|
||||
const tableStore = useTableStore();
|
||||
export default function useTableProps<T>(
|
||||
loadListFunc: (v?: TableQueryParams | any) => Promise<CommonList<MsTableDataItem<T>> | MsTableDataItem<T>>,
|
||||
loadListFunc?: (v?: TableQueryParams | any) => Promise<CommonList<MsTableDataItem<T>> | MsTableDataItem<T>>,
|
||||
props?: Partial<MsTableProps<T>>,
|
||||
// 数据处理的回调函数
|
||||
dataTransform?: (item: TableData) => (TableData & T) | any,
|
||||
|
@ -161,40 +161,42 @@ export default function useTableProps<T>(
|
|||
const { current, pageSize } = propsRes.value.msPagination as Pagination;
|
||||
const { rowKey, selectorStatus, excludeKeys } = propsRes.value;
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await loadListFunc({
|
||||
current,
|
||||
pageSize,
|
||||
sort: sortItem.value,
|
||||
filter: filterItem.value,
|
||||
keyword: keyword.value,
|
||||
...loadListParams.value,
|
||||
});
|
||||
const tmpArr = data.list;
|
||||
propsRes.value.data = tmpArr.map((item: MsTableDataItem<T>) => {
|
||||
if (item.updateTime) {
|
||||
item.updateTime = dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
if (item.createTime) {
|
||||
item.createTime = dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
if (dataTransform) {
|
||||
item = dataTransform(item);
|
||||
}
|
||||
if (selectorStatus === SelectAllEnum.ALL) {
|
||||
if (!excludeKeys.has(item[rowKey])) {
|
||||
setTableSelected(item[rowKey]);
|
||||
if (loadListFunc) {
|
||||
setLoading(true);
|
||||
const data = await loadListFunc({
|
||||
current,
|
||||
pageSize,
|
||||
sort: sortItem.value,
|
||||
filter: filterItem.value,
|
||||
keyword: keyword.value,
|
||||
...loadListParams.value,
|
||||
});
|
||||
const tmpArr = data.list;
|
||||
propsRes.value.data = tmpArr.map((item: MsTableDataItem<T>) => {
|
||||
if (item.updateTime) {
|
||||
item.updateTime = dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
if (item.createTime) {
|
||||
item.createTime = dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
if (dataTransform) {
|
||||
item = dataTransform(item);
|
||||
}
|
||||
if (selectorStatus === SelectAllEnum.ALL) {
|
||||
if (!excludeKeys.has(item[rowKey])) {
|
||||
setTableSelected(item[rowKey]);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
if (data.total === 0) {
|
||||
setTableErrorStatus('empty');
|
||||
} else {
|
||||
setTableErrorStatus(false);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
if (data.total === 0) {
|
||||
setTableErrorStatus('empty');
|
||||
} else {
|
||||
setTableErrorStatus(false);
|
||||
setPagination({ current: data.current, total: data.total });
|
||||
return data;
|
||||
}
|
||||
setPagination({ current: data.current, total: data.total });
|
||||
return data;
|
||||
} catch (err) {
|
||||
setTableErrorStatus('error');
|
||||
} finally {
|
||||
|
@ -208,26 +210,28 @@ export default function useTableProps<T>(
|
|||
} else {
|
||||
// 没分页的情况下,直接调用loadListFunc
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await loadListFunc({ keyword: keyword.value, ...loadListParams.value });
|
||||
if (data.length === 0) {
|
||||
setTableErrorStatus('empty');
|
||||
return;
|
||||
if (loadListFunc) {
|
||||
setLoading(true);
|
||||
const data = await loadListFunc({ keyword: keyword.value, ...loadListParams.value });
|
||||
if (data.length === 0) {
|
||||
setTableErrorStatus('empty');
|
||||
return;
|
||||
}
|
||||
setTableErrorStatus(false);
|
||||
propsRes.value.data = data.map((item: MsTableDataItem<T>) => {
|
||||
if (item.updateTime) {
|
||||
item.updateTime = dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
if (item.createTime) {
|
||||
item.createTime = dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
if (dataTransform) {
|
||||
item = dataTransform(item);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
return data;
|
||||
}
|
||||
setTableErrorStatus(false);
|
||||
propsRes.value.data = data.map((item: MsTableDataItem<T>) => {
|
||||
if (item.updateTime) {
|
||||
item.updateTime = dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
if (item.createTime) {
|
||||
item.createTime = dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
if (dataTransform) {
|
||||
item = dataTransform(item);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
return data;
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(err);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export enum FormCreateKeyEnum {
|
||||
ORGANIZE_TEMPLATE = 'OrganizeTemplate',
|
||||
ORGANIZE_TEMPLATE_PREVIEW_TEMPLATE = 'OrganizeTemplatePreview',
|
||||
}
|
||||
|
||||
export default {};
|
|
@ -61,6 +61,8 @@ export enum SettingRouteEnum {
|
|||
SETTING_ORGANIZATION_PROJECT = 'settingOrganizationProject',
|
||||
SETTING_ORGANIZATION_TEMPLATE = 'settingOrganizationTemplate',
|
||||
SETTING_ORGANIZATION_TEMPLATE_FILED_SETTING = 'settingOrganizationTemplateFiledSetting',
|
||||
SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT = 'settingOrganizationTemplateManagement',
|
||||
SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_DETAIL = 'settingOrganizationTemplateManagementDetail',
|
||||
SETTING_ORGANIZATION_SERVICE = 'settingOrganizationService',
|
||||
SETTING_ORGANIZATION_LOG = 'settingOrganizationLog',
|
||||
}
|
||||
|
|
|
@ -17,7 +17,10 @@ export enum TableKeyEnum {
|
|||
PROJECT_MEMBER = 'projectMember',
|
||||
PROJECT_USER_GROUP = 'projectUserGroup',
|
||||
ORGANIZATION_MEMBER = 'organizationMember',
|
||||
ORGANIZATION_TEMPLATE = 'organizationTemplate',
|
||||
ORGANIZATION_TEMPLATE_FIELD_SETTING = 'organizationTemplateFieldSetting',
|
||||
ORGANIZATION_TEMPLATE_MANAGEMENT = 'organizationTemplateManagement',
|
||||
ORGANIZATION_TEMPLATE_MANAGEMENT_FIELD = 'organizationTemplateManagementField',
|
||||
ORGANIZATION_TEMPLATE_MANAGEMENT_STEP = 'organizationTemplateManagementStep',
|
||||
ORGANIZATION_PROJECT = 'organizationProject',
|
||||
ORGANIZATION_PROJECT_USER_DRAWER = 'organizationProjectUserDrawer',
|
||||
FILE_MANAGEMENT_FILE = 'fileManagementFile',
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// 模版展示字段icon
|
||||
export enum TemplateIconEnum {
|
||||
INPUT = 'icon-icon_input', // 输入框
|
||||
TEXTAREA = 'icon-icon_style_one', // 文本
|
||||
|
@ -14,5 +15,16 @@ export enum TemplateIconEnum {
|
|||
FLOAT = 'icon-icon_pound', // 数字-浮点型
|
||||
MULTIPLE_INPUT = 'icon-icon_tag', // 多值输入框、
|
||||
NUMBER = 'icon-icon_pound', // 数字
|
||||
SYSTEM = 'icon-icon_pound',
|
||||
}
|
||||
|
||||
// 模版列表图标卡片icon
|
||||
export enum TemplateCardEnum {
|
||||
FUNCTIONAL = 'caseTemplate', // 用例模版
|
||||
API = 'api_ui_Template', // ui模板
|
||||
UI = 'api_ui_Template', // API模板
|
||||
TEST_PLAN = 'testPlanTemplate', // 测试计划模板
|
||||
BUG = 'defectTemplate', // 缺陷模板
|
||||
}
|
||||
|
||||
export default {};
|
||||
|
|
|
@ -60,4 +60,5 @@ export default {
|
|||
'common.allSelect': 'Select All',
|
||||
'common.setting': 'Setting',
|
||||
'common.resetDefault': 'Restore default',
|
||||
'common.pleaseSelect': 'Please Select',
|
||||
};
|
||||
|
|
|
@ -54,6 +54,9 @@ export default {
|
|||
'menu.settings.organization.project': 'Project',
|
||||
'menu.settings.organization.template': 'Template',
|
||||
'menu.settings.organization.templateFieldSetting': 'fieldSetting',
|
||||
'menu.settings.organization.templateManagementList': 'Template list',
|
||||
'menu.settings.organization.templateManagementEdit': 'Update Template',
|
||||
'menu.settings.organization.templateManagementDetail': 'Create Template',
|
||||
'menu.settings.organization.serviceIntegration': 'Service Integration',
|
||||
'menu.settings.organization.log': 'Log',
|
||||
'navbar.action.locale': 'Switch to English',
|
||||
|
|
|
@ -64,4 +64,5 @@ export default {
|
|||
'common.resetDefault': '恢复默认',
|
||||
'common.tagPlaceholder': '添加标签回车结束',
|
||||
'common.batchModify': '批量修改',
|
||||
'common.pleaseSelect': '请选择',
|
||||
};
|
||||
|
|
|
@ -54,6 +54,9 @@ export default {
|
|||
'menu.settings.organization.serviceIntegration': '服务集成',
|
||||
'menu.settings.organization.template': '模版',
|
||||
'menu.settings.organization.templateFieldSetting': '字段设置',
|
||||
'menu.settings.organization.templateManagementList': '模版列表',
|
||||
'menu.settings.organization.templateManagementDetail': '创建模版',
|
||||
'menu.settings.organization.templateManagementEdit': '更新模板',
|
||||
'menu.settings.organization.log': '日志',
|
||||
'navbar.action.locale': '切换为中文',
|
||||
...sys,
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import { LocationQueryValue } from 'vue-router';
|
||||
|
||||
// 模版管理
|
||||
import type { FormItem, FormItemType, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
|
||||
import { FormRule } from '@form-create/arco-design';
|
||||
|
||||
// 模版管理(组织)
|
||||
export interface OrganizeTemplateItem {
|
||||
id: string;
|
||||
name: string;
|
||||
|
@ -18,21 +22,33 @@ export interface OrganizeTemplateItem {
|
|||
}
|
||||
|
||||
export type SeneType = 'FUNCTIONAL' | 'BUG' | 'API' | 'UI' | 'TEST_PLAN' | LocationQueryValue[] | LocationQueryValue;
|
||||
|
||||
export interface FieldOptions {
|
||||
fieldId?: string;
|
||||
value: string | string[] | number | number[];
|
||||
text: string;
|
||||
internal?: boolean;
|
||||
}
|
||||
|
||||
// 自定义字段
|
||||
export interface DefinedFieldItem {
|
||||
id: string;
|
||||
name: string;
|
||||
scene: SeneType; // 使用场景
|
||||
type: string;
|
||||
type: FormItemType; // 表单类型
|
||||
remark: string;
|
||||
internal: boolean; // 是否是内置字段
|
||||
scopeType: string; // 组织或项目级别字段(PROJECT, ORGANIZATION)
|
||||
createTime: number;
|
||||
updateTime: number;
|
||||
createUser: string;
|
||||
refId: string; // 项目字段所关联的组织字段ID
|
||||
enableOptionKey: boolean; // 是否需要手动输入选项key
|
||||
refId: string | null; // 项目字段所关联的组织字段ID
|
||||
enableOptionKey: boolean | null; // 是否需要手动输入选项key
|
||||
scopeId: string; // 组织或项目ID
|
||||
options: FieldOptions[] | null;
|
||||
required?: boolean | undefined;
|
||||
fApi?: any; // 表单值
|
||||
formRules?: FormRuleItem[] | FormItem[] | FormRule[]; // 表单列表
|
||||
}
|
||||
|
||||
// 创建自定义字段
|
||||
|
@ -42,12 +58,55 @@ export interface FieldOption {
|
|||
text: string;
|
||||
}
|
||||
|
||||
// 新增 || 编辑参数
|
||||
export interface AddOrUpdateField {
|
||||
id?: string;
|
||||
name: string;
|
||||
scene: SeneType; // 使用场景
|
||||
type: string;
|
||||
type: FormItemType;
|
||||
remark: string; // 备注
|
||||
scopeId: string; // 组织或项目ID
|
||||
options?: FieldOption[];
|
||||
}
|
||||
|
||||
export interface fieldIconAndNameModal {
|
||||
key: string;
|
||||
iconName: string; // 图标名称
|
||||
label: string; // 对应标签
|
||||
}
|
||||
|
||||
// 模板管理列表(组织)
|
||||
export interface OrdTemplateManagement {
|
||||
id: string;
|
||||
name: string;
|
||||
remark: string; // 描述
|
||||
internal: boolean; // 是否是系统模板
|
||||
updateTime: number;
|
||||
createTime: number;
|
||||
createUser: string; // 创建人
|
||||
scopeType: string; // 组织或项目级别字段
|
||||
scopeId: string; // 组织或项目ID
|
||||
enableThirdPart: boolean; // 是否开启api字段名配置
|
||||
enableDefault: boolean; // 是否是默认模板
|
||||
refId: string; // 项目模板所关联的组织模板ID
|
||||
scene: string; // 使用场景
|
||||
}
|
||||
|
||||
// 创建模板& 更新模板管理项
|
||||
|
||||
export interface CustomField {
|
||||
fieldId: string;
|
||||
required: boolean; // 是否必填
|
||||
apiFieldId: string; // api字段名
|
||||
defaultValue: string; // 默认值
|
||||
}
|
||||
|
||||
export interface ActionTemplateManage {
|
||||
id?: string;
|
||||
name: string;
|
||||
remark: string;
|
||||
scopeId: string;
|
||||
enableThirdPart?: boolean; // 是否开启api字段名配置
|
||||
scene: SeneType;
|
||||
customFields: CustomField[];
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ const Setting: AppRouteRecordRaw = {
|
|||
isTopMenu: true,
|
||||
},
|
||||
},
|
||||
// 模版字段设置
|
||||
// 模板列表-模版字段设置
|
||||
{
|
||||
path: 'templateFiledSetting',
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_FILED_SETTING,
|
||||
|
@ -209,6 +209,52 @@ const Setting: AppRouteRecordRaw = {
|
|||
],
|
||||
},
|
||||
},
|
||||
// 模版管理-模版列表
|
||||
{
|
||||
path: 'templateManagement',
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
|
||||
component: () => import('@/views/setting/organization/template/components/templateManagement.vue'),
|
||||
meta: {
|
||||
locale: 'menu.settings.organization.templateManagementList',
|
||||
roles: ['*'],
|
||||
breadcrumbs: [
|
||||
{
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE,
|
||||
locale: 'menu.settings.organization.template',
|
||||
},
|
||||
{
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
|
||||
locale: 'menu.settings.organization.templateManagementList',
|
||||
editLocale: 'menu.settings.organization.templateManagementList',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
// 模板列表-模板管理-创建&编辑模版
|
||||
{
|
||||
path: 'templateManagementDetail',
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_DETAIL,
|
||||
component: () => import('@/views/setting/organization/template/components/templateDetail.vue'),
|
||||
meta: {
|
||||
locale: 'menu.settings.organization.templateManagementDetail',
|
||||
roles: ['*'],
|
||||
breadcrumbs: [
|
||||
{
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE,
|
||||
locale: 'menu.settings.organization.template',
|
||||
},
|
||||
{
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
|
||||
locale: 'menu.settings.organization.templateManagementList',
|
||||
},
|
||||
{
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
|
||||
locale: 'menu.settings.organization.templateManagementDetail',
|
||||
editLocale: 'menu.settings.organization.templateManagementEdit',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'log',
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_LOG,
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
import { defineStore } from 'pinia';
|
||||
|
||||
import { FieldTypeFormRules } from '@/components/pure/ms-form-create/form-create';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
const useFormCreateStore = defineStore('form-create', {
|
||||
persist: false,
|
||||
state: (): {
|
||||
formRuleMap: Map<FormCreateKeyEnum[keyof FormCreateKeyEnum], FormItem[]>;
|
||||
formCreateRuleMap: Map<FormCreateKeyEnum[keyof FormCreateKeyEnum], FormRuleItem[]>;
|
||||
} => ({
|
||||
formRuleMap: new Map(),
|
||||
formCreateRuleMap: new Map(),
|
||||
}),
|
||||
actions: {
|
||||
// 存储外边传递初始化数据格式存储form-item
|
||||
setInitFormCreate(key: FormCreateKeyEnum[keyof FormCreateKeyEnum], formRule: FormItem[]) {
|
||||
this.formRuleMap = new Map();
|
||||
this.formRuleMap.set(key, formRule);
|
||||
},
|
||||
// 根据不同的类型初始化数据
|
||||
initFormCreateFormRules(key: FormCreateKeyEnum[keyof FormCreateKeyEnum]) {
|
||||
const currentFormRule = this.formRuleMap.get(key);
|
||||
// 处理数据结构
|
||||
const result = currentFormRule?.map((item: FormItem) => {
|
||||
// 当前类型
|
||||
let fieldType;
|
||||
const currentTypeForm = Object.keys(FieldTypeFormRules).find(
|
||||
(formItemType: any) => item.type.toUpperCase() === formItemType
|
||||
);
|
||||
if (currentTypeForm) {
|
||||
fieldType = FieldTypeFormRules[currentTypeForm].type;
|
||||
const options = item?.options;
|
||||
const currentOptions = options?.map((optionsItem) => {
|
||||
return {
|
||||
label: optionsItem.text,
|
||||
value: optionsItem.value,
|
||||
};
|
||||
});
|
||||
return {
|
||||
type: fieldType, // 表单类型
|
||||
field: item.name, // 字段
|
||||
title: item.label, // label 表单标签
|
||||
value: FieldTypeFormRules[currentTypeForm].value, // 目前的值
|
||||
effect: {
|
||||
required: item.required, // 是否必填
|
||||
},
|
||||
// 级联关联到某一个form上 可能存在多个级联
|
||||
options: !item.optionMethod ? currentOptions : [],
|
||||
link: item.couplingConfig?.map((cascadeItem: any) => cascadeItem.cascade),
|
||||
rule: item.validate || [],
|
||||
// 梳理表单所需要属性
|
||||
props: {
|
||||
...FieldTypeFormRules[currentTypeForm].props,
|
||||
'tooltip': item.tooltip,
|
||||
// 表单后边展示图片
|
||||
'instructionsIcon': item.instructionsIcon,
|
||||
// 下拉选项请求 必须是开启远程搜索才有该方法
|
||||
'subDesc': item.subDesc,
|
||||
// 级联匹配规则
|
||||
'couplingConfig': { ...item.couplingConfig },
|
||||
'optionMethod': item.inputSearch && item.optionMethod ? item.optionMethod : '',
|
||||
'inputSearch': item.inputSearch,
|
||||
'allow-search': item.inputSearch,
|
||||
'keyword': '',
|
||||
'modelValue': item.value,
|
||||
'options': currentOptions,
|
||||
},
|
||||
};
|
||||
}
|
||||
return {};
|
||||
});
|
||||
if (result && result.length) {
|
||||
this.setInitdRules(key, result as FormRuleItem[]);
|
||||
}
|
||||
},
|
||||
// 初始化好了的格式给formCreate
|
||||
setInitdRules(key: FormCreateKeyEnum[keyof FormCreateKeyEnum], result: FormRuleItem[]) {
|
||||
this.formCreateRuleMap.set(key, result);
|
||||
},
|
||||
|
||||
/** **
|
||||
* @description 处理监视联动获取请求
|
||||
* @param key: 对应Map的Key
|
||||
* @param item: 当前对应关联项-请求改变options
|
||||
* @param formValueApi: 当前表单值实例可以获取表单的当前已经设置的值
|
||||
*/
|
||||
async getOptions(
|
||||
val: FormRuleItem,
|
||||
key: FormCreateKeyEnum[keyof FormCreateKeyEnum],
|
||||
cascadeItem: FormRuleItem,
|
||||
formValueApi: any
|
||||
) {
|
||||
const formValue = formValueApi.formData();
|
||||
// 设置自定义属性给到searchSelect
|
||||
const formCreateRuleArr = this.formCreateRuleMap.get(key);
|
||||
const formCreateItem = formCreateRuleArr?.find((items: FormRuleItem) => cascadeItem.field === items.field);
|
||||
if (formCreateItem) {
|
||||
formCreateItem.props.keyword = val.value;
|
||||
formCreateItem.props.formValue = formValue;
|
||||
}
|
||||
},
|
||||
},
|
||||
getters: {},
|
||||
});
|
||||
|
||||
export default useFormCreateStore;
|
|
@ -0,0 +1,38 @@
|
|||
import { defineStore } from 'pinia';
|
||||
|
||||
import { isEnableTemplate } from '@/api/modules/setting/template';
|
||||
|
||||
import type { DefinedFieldItem } from '@/models/setting/template';
|
||||
|
||||
import useAppStore from '../app';
|
||||
|
||||
const useTemplateStore = defineStore('template', {
|
||||
persist: true,
|
||||
state: (): { templateStatus: Record<string, boolean>; previewList: DefinedFieldItem[] } => ({
|
||||
templateStatus: {
|
||||
FUNCTIONAL: false,
|
||||
API: false,
|
||||
UI: false,
|
||||
TEST_PLAN: false,
|
||||
BUG: false,
|
||||
},
|
||||
previewList: [],
|
||||
}),
|
||||
actions: {
|
||||
// 模板列表的状态
|
||||
setStatus() {
|
||||
// 需要调整接口
|
||||
// const appStore = useAppStore();
|
||||
// Object.keys(this.templateStatus).forEach(async (item) => {
|
||||
// const sceneStatus = await isEnableTemplate(appStore.currentOrgId, item);
|
||||
// this.templateStatus[item] = sceneStatus;
|
||||
// });
|
||||
},
|
||||
// 预览存储表数据
|
||||
setPreviewHandler(filedData: DefinedFieldItem[]) {
|
||||
this.previewList = filedData;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default useTemplateStore;
|
|
@ -1,9 +1,165 @@
|
|||
<template>
|
||||
<div>项目版本 waiting for development </div>
|
||||
<MsFormCreate :form-rule="formRules" :form-create-key="FormCreateKeyEnum.ORGANIZE_TEMPLATE" />
|
||||
<br />
|
||||
<br />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
const formRules = ref<FormItem[]>([
|
||||
{
|
||||
type: 'INPUT',
|
||||
name: 'name',
|
||||
label: '姓名',
|
||||
value: '',
|
||||
subDesc: '请输入姓名',
|
||||
required: true,
|
||||
},
|
||||
|
||||
{
|
||||
type: 'MULTIPLE_SELECT',
|
||||
name: 'gender',
|
||||
label: '性别',
|
||||
value: [],
|
||||
subDesc: '请选择性别',
|
||||
optionMethod: 'getGenderOptions',
|
||||
inputSearch: true,
|
||||
required: true,
|
||||
couplingConfig: [
|
||||
{
|
||||
type: 'initOptions',
|
||||
cascade: 'name',
|
||||
matchRule: 'includes',
|
||||
},
|
||||
],
|
||||
options: [
|
||||
{
|
||||
value: '1',
|
||||
text: '单选',
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
text: '多选',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'INPUT',
|
||||
name: 'member',
|
||||
label: '成员',
|
||||
value: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 'MULTIPLE_MEMBER',
|
||||
name: 'multiple_member',
|
||||
label: '多选成员',
|
||||
value: [],
|
||||
required: true,
|
||||
options: [
|
||||
{
|
||||
value: '1',
|
||||
text: '单选',
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
text: '多选',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'INT',
|
||||
name: 'birthday',
|
||||
label: '出生日期',
|
||||
value: 0,
|
||||
subDesc: '请选择出生日期',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 'DATE',
|
||||
name: 'birthday',
|
||||
label: '出生日期',
|
||||
value: '',
|
||||
subDesc: '请选择出生日期',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 'MULTIPLE_MEMBER',
|
||||
name: 'radio',
|
||||
label: '单选',
|
||||
value: '',
|
||||
subDesc: '请选择出生日期',
|
||||
inputSearch: true,
|
||||
required: true,
|
||||
options: [
|
||||
{
|
||||
value: '1',
|
||||
text: '单选',
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
text: '多选',
|
||||
},
|
||||
],
|
||||
couplingConfig: [
|
||||
{
|
||||
type: 'initOptions',
|
||||
cascade: 'member',
|
||||
matchRule: 'includes',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'SELECT',
|
||||
name: 'selectName',
|
||||
label: '单选',
|
||||
value: '',
|
||||
subDesc: '请选择出生日期',
|
||||
inputSearch: true,
|
||||
required: true,
|
||||
options: [
|
||||
{
|
||||
value: '1',
|
||||
text: '单选',
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
text: '多选',
|
||||
},
|
||||
],
|
||||
couplingConfig: [
|
||||
{
|
||||
type: 'initOptions',
|
||||
cascade: 'member',
|
||||
matchRule: 'includes',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const options = ref({
|
||||
resetBtn: false,
|
||||
submitBtn: false,
|
||||
on: false,
|
||||
form: {
|
||||
layout: 'vertical',
|
||||
labelAlign: 'left',
|
||||
},
|
||||
row: {
|
||||
gutter: 0,
|
||||
},
|
||||
wrap: {
|
||||
'asterisk-position': 'end',
|
||||
'validate-trigger': ['change'],
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
<template>
|
||||
<MsDrawer
|
||||
v-model:visible="showAddDrawer"
|
||||
:title="t('system.orgTemplate.createField')"
|
||||
:ok-text="t('system.orgTemplate.save')"
|
||||
:ok-loading="drawerLoading"
|
||||
:width="800"
|
||||
unmount-on-close
|
||||
:show-continue="false"
|
||||
@confirm="handleDrawerConfirm"
|
||||
@cancel="handleDrawerCancel"
|
||||
>
|
||||
<div class="panel-wrapper">
|
||||
<div class="inner-wrapper">
|
||||
<div class="optional-field">
|
||||
<div class="optional-header">
|
||||
<div class="font-medium">{{ t('system.orgTemplate.optionalField') }}</div>
|
||||
<a-checkbox :model-value="checkedAll" :indeterminate="indeterminate" @change="handleChangeAll">
|
||||
<span class="font-medium text-[var(--color-text-3)]">{{ t('system.orgTemplate.selectAll') }}</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<div class="optional-panel p-4">
|
||||
<div class="mb-2 font-medium text-[var(--color-text-3)]">{{ t('system.orgTemplate.systemField') }}</div>
|
||||
<div>
|
||||
<a-checkbox-group v-model="selectSystemData">
|
||||
<a-grid :cols="4" :col-gap="16" :row-gap="4">
|
||||
<a-grid-item v-for="field in systemField" :key="field.id">
|
||||
<a-checkbox :value="field.id" :disabled="field.internal"
|
||||
><a-tooltip :content="field.name">
|
||||
<div class="checkbox">{{ field.name }}</div></a-tooltip
|
||||
></a-checkbox
|
||||
>
|
||||
</a-grid-item>
|
||||
</a-grid>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="my-2 mt-8 font-medium text-[var(--color-text-3)]">{{
|
||||
t('system.orgTemplate.customField')
|
||||
}}</div>
|
||||
<a-checkbox-group v-model="selectCustomField">
|
||||
<a-grid :cols="4" :col-gap="16" :row-gap="4">
|
||||
<a-grid-item v-for="field in customField" :key="field.id">
|
||||
<a-checkbox :value="field.id"
|
||||
><a-tooltip :content="field.name">
|
||||
<div class="checkbox">{{ field.name }}</div></a-tooltip
|
||||
></a-checkbox
|
||||
>
|
||||
</a-grid-item>
|
||||
</a-grid>
|
||||
</a-checkbox-group>
|
||||
<EditFieldDrawer ref="fieldDrawerRef" v-model:visible="showFieldDrawer" @success="okHandler" />
|
||||
<a-button class="mt-1 px-0" type="text" @click="createField">
|
||||
<template #icon>
|
||||
<icon-plus class="text-[14px]" />
|
||||
</template>
|
||||
{{ t('system.orgTemplate.addField') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="selected-field">
|
||||
<div class="optional-header">
|
||||
<div class="font-medium">{{ t('system.orgTemplate.selectedField') }}</div>
|
||||
<MsButton @click="clearHandler">{{ t('system.orgTemplate.clear') }}</MsButton>
|
||||
</div>
|
||||
<div class="selected-list p-4">
|
||||
<MsList
|
||||
:data="selectedFields"
|
||||
:bordered="false"
|
||||
:split="false"
|
||||
item-border
|
||||
no-hover
|
||||
:virtual-list-props="{
|
||||
height: 'calc(100vh - 226px)',
|
||||
}"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<div class="selected-item">
|
||||
<a-tooltip :content="item.name">
|
||||
<span class="one-line-text w-[270px]">{{ item.name }}</span>
|
||||
</a-tooltip>
|
||||
<icon-close
|
||||
v-if="!item.internal"
|
||||
:style="{ 'font-size': '14px' }"
|
||||
class="cursor-pointer text-[var(--color-text-3)]"
|
||||
@click="removeSelectedField(item.id)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</MsList>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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 MsList from '@/components/pure/ms-list/index.vue';
|
||||
import EditFieldDrawer from './editFieldDrawer.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import type { DefinedFieldItem } from '@/models/setting/template';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const showAddDrawer = ref<boolean>(false);
|
||||
const drawerLoading = ref<boolean>(false);
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
selectedData: DefinedFieldItem[]; // 已选字段
|
||||
systemData: DefinedFieldItem[]; // 所有系统字段
|
||||
customData: DefinedFieldItem[]; // 所有自定义字段
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['confirm', 'update:visible', 'update']);
|
||||
|
||||
// 模板系统字段
|
||||
const systemField = ref<DefinedFieldItem[]>([]);
|
||||
// 自定义字段
|
||||
const customField = ref<DefinedFieldItem[]>([]);
|
||||
// 所有模板总字段
|
||||
const totalTemplateField = ref<DefinedFieldItem[]>([]);
|
||||
// 可选系统字段
|
||||
const selectSystemData = ref<string[]>([]);
|
||||
// 可选自定义字段
|
||||
const selectCustomField = ref<string[]>([]);
|
||||
// 半选状态
|
||||
const indeterminate = ref<boolean>(false);
|
||||
|
||||
const checkedAll = ref<boolean>(false);
|
||||
|
||||
// 全选
|
||||
const handleChangeAll = (value: any) => {
|
||||
indeterminate.value = false;
|
||||
if (value) {
|
||||
checkedAll.value = true;
|
||||
selectSystemData.value = systemField.value.map((item) => item.id);
|
||||
selectCustomField.value = customField.value.map((item) => item.id);
|
||||
} else {
|
||||
checkedAll.value = false;
|
||||
selectSystemData.value = [];
|
||||
selectCustomField.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 已选择列表
|
||||
const selectedFields = ref<DefinedFieldItem[]>([]);
|
||||
const getSelectedField = () => {
|
||||
const totalSelectIds = [...selectSystemData.value, ...selectCustomField.value];
|
||||
selectedFields.value = totalTemplateField.value.filter((item) => totalSelectIds.indexOf(item.id) > -1);
|
||||
};
|
||||
|
||||
// 处理全选&半选&未选
|
||||
const isCheckedAll = () => {
|
||||
totalTemplateField.value = [...props.systemData, ...props.customData];
|
||||
systemField.value = props.systemData;
|
||||
customField.value = props.customData;
|
||||
const systemAll = selectSystemData.value.length === systemField.value.length;
|
||||
const customAll = selectCustomField.value.length === customField.value.length;
|
||||
if (systemAll && customAll) {
|
||||
checkedAll.value = true;
|
||||
indeterminate.value = false;
|
||||
} else if (selectCustomField.value.length === 0 || selectCustomField.value.length === 0) {
|
||||
checkedAll.value = false;
|
||||
indeterminate.value = false;
|
||||
} else {
|
||||
checkedAll.value = false;
|
||||
indeterminate.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
isCheckedAll();
|
||||
// 已经选择的列表
|
||||
getSelectedField();
|
||||
});
|
||||
|
||||
// 移除已选择字段
|
||||
const removeSelectedField = (id: string) => {
|
||||
selectSystemData.value = selectSystemData.value.filter((item) => item !== id);
|
||||
selectCustomField.value = selectCustomField.value.filter((item) => item !== id);
|
||||
};
|
||||
|
||||
// 新增字段
|
||||
const showFieldDrawer = ref<boolean>(false);
|
||||
const createField = () => {
|
||||
showFieldDrawer.value = true;
|
||||
};
|
||||
|
||||
// 清空
|
||||
const clearHandler = () => {
|
||||
selectSystemData.value = [];
|
||||
selectCustomField.value = [];
|
||||
};
|
||||
|
||||
const handleDrawerCancel = () => {
|
||||
showAddDrawer.value = false;
|
||||
};
|
||||
|
||||
const handleDrawerConfirm = () => {
|
||||
emit('confirm', selectedFields.value);
|
||||
showAddDrawer.value = false;
|
||||
};
|
||||
|
||||
const okHandler = () => {
|
||||
emit('update');
|
||||
};
|
||||
|
||||
// 针对外部操作的进行回显
|
||||
const showSelectField = () => {
|
||||
const selectIds = props.selectedData.map((item) => item.id);
|
||||
// 回显系统字段
|
||||
selectSystemData.value = systemField.value.filter((item) => selectIds.indexOf(item.id) > -1).map((item) => item.id);
|
||||
// 回显自定义字段
|
||||
selectCustomField.value = customField.value
|
||||
.filter((item) => selectIds.indexOf(item.id) > -1)
|
||||
.map((item) => item.id);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => showAddDrawer.value,
|
||||
(val) => {
|
||||
emit('update:visible', val);
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
showAddDrawer.value = val;
|
||||
}
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
removeSelectedField,
|
||||
showSelectField,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.panel-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.inner-wrapper {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid var(--color-text-n8);
|
||||
// 可选字段
|
||||
.optional-field {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
border-right: 1px solid var(--color-text-n8);
|
||||
.optional-header {
|
||||
padding: 0 16px;
|
||||
height: 54px;
|
||||
color: var(--color-text-3);
|
||||
background: var(--color-text-n9);
|
||||
@apply flex items-center justify-between;
|
||||
}
|
||||
.optional-panel {
|
||||
.checkbox {
|
||||
width: 74px;
|
||||
white-space: nowrap;
|
||||
@apply overflow-hidden text-ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 已选字段
|
||||
.selected-field {
|
||||
width: 272px;
|
||||
.optional-header {
|
||||
padding: 0 16px;
|
||||
height: 54px;
|
||||
color: var(--color-text-3);
|
||||
background: var(--color-text-n9);
|
||||
@apply flex items-center justify-between;
|
||||
}
|
||||
.selected-list {
|
||||
.selected-item {
|
||||
height: 36px;
|
||||
background: var(--color-bg-3);
|
||||
@apply mb-2 flex items-center justify-between rounded px-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -22,14 +22,14 @@
|
|||
<a-input
|
||||
v-model:model-value="fieldForm.name"
|
||||
:placeholder="t('system.orgTemplate.fieldNamePlaceholder')"
|
||||
:max-length="250"
|
||||
:max-length="255"
|
||||
show-word-limit
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item field="remark" :label="t('system.orgTemplate.description')" asterisk-position="end">
|
||||
<a-textarea
|
||||
v-model="fieldForm.remark"
|
||||
:max-length="250"
|
||||
:max-length="255"
|
||||
:placeholder="t('system.orgTemplate.resDescription')"
|
||||
:auto-size="{
|
||||
maxRows: 1,
|
||||
|
@ -42,11 +42,12 @@
|
|||
class="w-[260px]"
|
||||
:placeholder="t('system.orgTemplate.fieldTypePlaceholder')"
|
||||
allow-clear
|
||||
:disabled="isEdit"
|
||||
@change="fieldChangeHandler"
|
||||
>
|
||||
<a-option v-for="item of fieldOptions" :key="item.value" :value="item.id">
|
||||
<a-option v-for="item of fieldOptions" :key="item.key" :value="item.key">
|
||||
<div class="flex items-center"
|
||||
><MsIcon :type="item.value" class="mx-2" /> <span>{{ item.label }}</span></div
|
||||
><MsIcon :type="item.iconName" class="mx-2" /> <span>{{ item.label }}</span></div
|
||||
>
|
||||
</a-option>
|
||||
</a-select>
|
||||
|
@ -81,9 +82,7 @@
|
|||
<a-form-item
|
||||
v-if="showDateOrNumber"
|
||||
field="selectFormat"
|
||||
:label="
|
||||
fieldForm.type === 'NUMBER' ? t('system.orgTemplate.numberFormat') : t('system.orgTemplate.dateFormat')
|
||||
"
|
||||
:label="fieldType === 'NUMBER' ? t('system.orgTemplate.numberFormat') : t('system.orgTemplate.dateFormat')"
|
||||
asterisk-position="end"
|
||||
>
|
||||
<a-select
|
||||
|
@ -91,6 +90,7 @@
|
|||
class="w-[260px]"
|
||||
:placeholder="t('system.orgTemplate.formatPlaceholder')"
|
||||
allow-clear
|
||||
:disabled="isEdit"
|
||||
>
|
||||
<a-option v-for="item of showDateOrNumber" :key="item.value" :value="item.value">
|
||||
<div class="flex items-center">{{ item.label }}</div>
|
||||
|
@ -108,6 +108,7 @@
|
|||
import { FormInstance, Message, ValidatedError } from '@arco-design/web-vue';
|
||||
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import type { FormItemType } from '@/components/pure/ms-form-create/types';
|
||||
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
|
||||
import type { FormItemModel, MsBatchFormInstance } from '@/components/business/ms-batch-form/types';
|
||||
|
||||
|
@ -116,10 +117,9 @@
|
|||
import { useAppStore } from '@/store';
|
||||
import { getGenerateId } from '@/utils';
|
||||
|
||||
import type { AddOrUpdateField } from '@/models/setting/template';
|
||||
import { TemplateIconEnum } from '@/enums/templateEnum';
|
||||
import type { AddOrUpdateField, fieldIconAndNameModal } from '@/models/setting/template';
|
||||
|
||||
import { getFieldType } from './fieldSetting';
|
||||
import { fieldIconAndName, getFieldType } from './fieldSetting';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
|
@ -136,7 +136,7 @@
|
|||
const fieldFormRef = ref<FormInstance>();
|
||||
const initFieldForm: AddOrUpdateField = {
|
||||
name: '',
|
||||
type: '',
|
||||
type: 'INPUT',
|
||||
remark: '',
|
||||
scopeId: '',
|
||||
scene: 'FUNCTIONAL',
|
||||
|
@ -144,19 +144,19 @@
|
|||
};
|
||||
const fieldForm = ref<AddOrUpdateField>({ ...initFieldForm });
|
||||
const isEdit = computed(() => !!fieldForm.value.id);
|
||||
const selectFormat = ref(''); // 选择格式
|
||||
const selectFormat = ref<FormItemType>(); // 选择格式
|
||||
const isMultipleSelectMember = ref<boolean | undefined>(false); // 成员多选
|
||||
const fieldType = ref(''); // 整体字段类型
|
||||
const fieldType = ref<FormItemType>(); // 整体字段类型
|
||||
|
||||
// 是否展示选项添加面板
|
||||
const showOptionsSelect = computed(() => {
|
||||
const showOptionsType = ['RADIO', 'CHECKBOX', 'SELECT', 'MULTIPLE_SELECT'];
|
||||
return showOptionsType.includes(fieldType.value);
|
||||
const showOptionsType: FormItemType[] = ['RADIO', 'CHECKBOX', 'SELECT', 'MULTIPLE_SELECT'];
|
||||
return showOptionsType.includes(fieldType.value as FormItemType);
|
||||
});
|
||||
|
||||
// 是否展示日期或数值
|
||||
const showDateOrNumber = computed(() => {
|
||||
return getFieldType(fieldType.value);
|
||||
if (fieldType.value) return getFieldType(fieldType.value);
|
||||
});
|
||||
|
||||
// 批量表单-1.仅选项情况
|
||||
|
@ -174,9 +174,9 @@
|
|||
|
||||
const resetForm = () => {
|
||||
fieldForm.value = { ...initFieldForm };
|
||||
selectFormat.value = '';
|
||||
selectFormat.value = undefined;
|
||||
isMultipleSelectMember.value = false;
|
||||
fieldType.value = '';
|
||||
fieldType.value = undefined;
|
||||
batchFormRef.value?.resetForm();
|
||||
};
|
||||
|
||||
|
@ -190,20 +190,23 @@
|
|||
const confirmHandler = async (isContinue: boolean) => {
|
||||
try {
|
||||
drawerLoading.value = true;
|
||||
if (fieldType.value) {
|
||||
fieldForm.value.type = fieldType.value;
|
||||
}
|
||||
|
||||
fieldForm.value.scene = route.query.type;
|
||||
fieldForm.value = {
|
||||
...fieldForm.value,
|
||||
scopeId: appStore.currentOrgId,
|
||||
type: fieldType.value,
|
||||
};
|
||||
fieldForm.value.scopeId = appStore.currentOrgId;
|
||||
|
||||
// 如果选择是日期或者数值
|
||||
if (selectFormat.value) {
|
||||
fieldForm.value.type = selectFormat.value;
|
||||
}
|
||||
|
||||
// 如果选择是成员(单选||多选)
|
||||
if (isMultipleSelectMember.value) {
|
||||
fieldForm.value.type = isMultipleSelectMember.value ? 'MULTIPLE_MEMBER' : 'MEMBER';
|
||||
}
|
||||
|
||||
// 如果选择是日期或者是数值
|
||||
if (selectFormat.value) {
|
||||
fieldForm.value.type = selectFormat.value;
|
||||
|
@ -212,6 +215,7 @@
|
|||
// 处理参数
|
||||
const { id, name, options, scopeId, scene, type, remark } = fieldForm.value;
|
||||
const params: AddOrUpdateField = { name, options, scopeId, scene, type, remark };
|
||||
|
||||
if (isEdit) {
|
||||
params.id = id;
|
||||
}
|
||||
|
@ -247,59 +251,7 @@
|
|||
};
|
||||
|
||||
// 字段类型列表选项
|
||||
const fieldOptions = ref([
|
||||
{
|
||||
id: 'TEXTAREA',
|
||||
label: t('system.orgTemplate.textarea'),
|
||||
value: TemplateIconEnum.TEXTAREA,
|
||||
},
|
||||
{
|
||||
id: 'INPUT',
|
||||
label: t('system.orgTemplate.input'),
|
||||
value: TemplateIconEnum.INPUT,
|
||||
},
|
||||
{
|
||||
id: 'RADIO',
|
||||
label: t('system.orgTemplate.radio'),
|
||||
value: TemplateIconEnum.RADIO,
|
||||
},
|
||||
{
|
||||
id: 'CHECKBOX',
|
||||
label: t('system.orgTemplate.checkbox'),
|
||||
value: TemplateIconEnum.CHECKBOX,
|
||||
},
|
||||
{
|
||||
id: 'SELECT',
|
||||
label: t('system.orgTemplate.select'),
|
||||
value: TemplateIconEnum.SELECT,
|
||||
},
|
||||
{
|
||||
id: 'MULTIPLE_SELECT',
|
||||
label: t('system.orgTemplate.multipleSelect'),
|
||||
value: TemplateIconEnum.MULTIPLE_SELECT,
|
||||
},
|
||||
{
|
||||
id: 'MEMBER',
|
||||
label: t('system.orgTemplate.member'),
|
||||
value: TemplateIconEnum.MEMBER,
|
||||
},
|
||||
{
|
||||
id: 'DATE',
|
||||
label: t('system.orgTemplate.date'),
|
||||
value: TemplateIconEnum.DATE,
|
||||
},
|
||||
{
|
||||
id: 'NUMBER',
|
||||
label: t('system.orgTemplate.number'),
|
||||
value: TemplateIconEnum.NUMBER,
|
||||
},
|
||||
{
|
||||
id: 'MULTIPLE_INPUT',
|
||||
label: t('system.orgTemplate.multipleInput'),
|
||||
value: TemplateIconEnum.MULTIPLE_INPUT,
|
||||
},
|
||||
]);
|
||||
|
||||
const fieldOptions = ref<fieldIconAndNameModal[]>([]);
|
||||
const fieldDefaultValues = ref([]);
|
||||
|
||||
// 获取字段选项详情
|
||||
|
@ -317,7 +269,7 @@
|
|||
};
|
||||
|
||||
// 处理特殊情况编辑回显
|
||||
const getSpecialHandler = (itemType: string): string => {
|
||||
const getSpecialHandler = (itemType: FormItemType): FormItemType => {
|
||||
switch (itemType) {
|
||||
case 'INT':
|
||||
selectFormat.value = itemType;
|
||||
|
@ -336,7 +288,7 @@
|
|||
};
|
||||
|
||||
// 编辑
|
||||
const isEditHandler = (item: AddOrUpdateField) => {
|
||||
const editHandler = (item: AddOrUpdateField) => {
|
||||
showDrawer.value = true;
|
||||
isMultipleSelectMember.value = item.type === 'MULTIPLE_MEMBER';
|
||||
if (isEdit && item.id) {
|
||||
|
@ -345,7 +297,7 @@
|
|||
...item,
|
||||
type: getSpecialHandler(item.type),
|
||||
};
|
||||
fieldType.value = getSpecialHandler(item.type);
|
||||
fieldType.value = fieldForm.value.type;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -368,9 +320,13 @@
|
|||
showDrawer.value = val;
|
||||
}
|
||||
);
|
||||
onMounted(() => {
|
||||
const excludeOptions = ['MULTIPLE_MEMBER', 'DATETIME', 'SYSTEM', 'INT', 'FLOAT'];
|
||||
fieldOptions.value = fieldIconAndName.filter((item: any) => excludeOptions.indexOf(item.key) < 0);
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
isEditHandler,
|
||||
editHandler,
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
import { ref } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import type { FormItemType } from '@/components/pure/ms-form-create/types';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useTemplateStore from '@/store/modules/setting/template';
|
||||
|
||||
import type { fieldIconAndNameModal } from '@/models/setting/template';
|
||||
import { TemplateCardEnum, TemplateIconEnum } from '@/enums/templateEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
const templateStore = useTemplateStore();
|
||||
|
||||
// 字段类型-日期
|
||||
const dateOptions = ref([
|
||||
const dateOptions = [
|
||||
{
|
||||
label: dayjs().format('YYYY/MM/DD'),
|
||||
value: 'DATE',
|
||||
|
@ -11,10 +21,10 @@ const dateOptions = ref([
|
|||
label: dayjs().format('YYYY/MM/DD HH:mm:ss'),
|
||||
value: 'DATETIME',
|
||||
},
|
||||
]);
|
||||
];
|
||||
|
||||
// 字段类型- 数字
|
||||
const numberTypeOptions = ref([
|
||||
const numberTypeOptions = [
|
||||
{
|
||||
label: '整数',
|
||||
value: 'INT',
|
||||
|
@ -23,17 +33,141 @@ const numberTypeOptions = ref([
|
|||
label: '保留小数',
|
||||
value: 'FLOAT',
|
||||
},
|
||||
]);
|
||||
];
|
||||
|
||||
export const getFieldType = (selectFieldType: string) => {
|
||||
// 获取字段类型是数值 || 日期
|
||||
export const getFieldType = (selectFieldType: FormItemType) => {
|
||||
switch (selectFieldType) {
|
||||
case 'DATE':
|
||||
return dateOptions.value;
|
||||
return dateOptions;
|
||||
case 'NUMBER':
|
||||
return numberTypeOptions.value;
|
||||
return numberTypeOptions;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// 模板列表Icon
|
||||
export const cardList = [
|
||||
{
|
||||
id: 1001,
|
||||
key: 'FUNCTIONAL',
|
||||
value: TemplateCardEnum.FUNCTIONAL,
|
||||
name: t('system.orgTemplate.caseTemplates'),
|
||||
enable: templateStore.templateStatus.FUNCTIONAL,
|
||||
},
|
||||
{
|
||||
id: 1002,
|
||||
key: 'API',
|
||||
value: TemplateCardEnum.API,
|
||||
name: t('system.orgTemplate.APITemplates'),
|
||||
enable: templateStore.templateStatus.API,
|
||||
},
|
||||
{
|
||||
id: 1003,
|
||||
key: 'UI',
|
||||
value: TemplateCardEnum.UI,
|
||||
name: t('system.orgTemplate.UITemplates'),
|
||||
enable: templateStore.templateStatus.UI,
|
||||
},
|
||||
{
|
||||
id: 1004,
|
||||
key: 'TEST_PLAN',
|
||||
value: TemplateCardEnum.TEST_PLAN,
|
||||
name: t('system.orgTemplate.testPlanTemplates'),
|
||||
enable: templateStore.templateStatus.TEST_PLAN,
|
||||
},
|
||||
{
|
||||
id: 1005,
|
||||
key: 'BUG',
|
||||
value: TemplateCardEnum.BUG,
|
||||
name: t('system.orgTemplate.defectTemplates'),
|
||||
enable: templateStore.templateStatus.BUG,
|
||||
},
|
||||
];
|
||||
|
||||
// table名称展示图标类型表格展示类型
|
||||
export const fieldIconAndName: fieldIconAndNameModal[] = [
|
||||
{
|
||||
key: 'INPUT',
|
||||
iconName: TemplateIconEnum.INPUT,
|
||||
label: t('system.orgTemplate.input'),
|
||||
},
|
||||
{
|
||||
key: 'TEXTAREA',
|
||||
iconName: TemplateIconEnum.TEXTAREA,
|
||||
label: t('system.orgTemplate.textarea'),
|
||||
},
|
||||
{
|
||||
key: 'SELECT',
|
||||
iconName: TemplateIconEnum.SELECT,
|
||||
label: t('system.orgTemplate.select'),
|
||||
},
|
||||
{
|
||||
key: 'MULTIPLE_SELECT',
|
||||
iconName: TemplateIconEnum.MULTIPLE_SELECT,
|
||||
label: t('system.orgTemplate.multipleSelect'),
|
||||
},
|
||||
{
|
||||
key: 'RADIO',
|
||||
iconName: TemplateIconEnum.RADIO,
|
||||
label: t('system.orgTemplate.radio'),
|
||||
},
|
||||
{
|
||||
key: 'CHECKBOX',
|
||||
iconName: TemplateIconEnum.CHECKBOX,
|
||||
label: t('system.orgTemplate.checkbox'),
|
||||
},
|
||||
{
|
||||
key: 'MEMBER',
|
||||
iconName: TemplateIconEnum.MEMBER,
|
||||
label: t('system.orgTemplate.member'),
|
||||
},
|
||||
{
|
||||
key: 'MULTIPLE_MEMBER',
|
||||
iconName: TemplateIconEnum.MULTIPLE_MEMBER,
|
||||
label: t('system.orgTemplate.multipleMember'),
|
||||
},
|
||||
{
|
||||
key: 'DATE',
|
||||
iconName: TemplateIconEnum.DATE,
|
||||
label: t('system.orgTemplate.date'),
|
||||
},
|
||||
{
|
||||
key: 'DATETIME',
|
||||
iconName: TemplateIconEnum.DATETIME,
|
||||
label: t('system.orgTemplate.dateTime'),
|
||||
},
|
||||
{
|
||||
key: 'NUMBER',
|
||||
iconName: TemplateIconEnum.NUMBER,
|
||||
label: t('system.orgTemplate.number'),
|
||||
},
|
||||
{
|
||||
key: 'INT',
|
||||
iconName: TemplateIconEnum.INT,
|
||||
label: t('system.orgTemplate.number'),
|
||||
},
|
||||
{
|
||||
key: 'FLOAT',
|
||||
iconName: TemplateIconEnum.FLOAT,
|
||||
label: t('system.orgTemplate.number'),
|
||||
},
|
||||
{
|
||||
key: 'MULTIPLE_INPUT',
|
||||
iconName: TemplateIconEnum.MULTIPLE_INPUT,
|
||||
label: t('system.orgTemplate.multipleInput'),
|
||||
},
|
||||
{
|
||||
key: 'SYSTEM',
|
||||
iconName: TemplateIconEnum.SYSTEM,
|
||||
label: '',
|
||||
},
|
||||
];
|
||||
|
||||
// 获取图标类型
|
||||
export const getIconType = (iconType: FormItemType) => {
|
||||
return fieldIconAndName.find((item) => item.key === iconType);
|
||||
};
|
||||
|
||||
export default {};
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
<template>
|
||||
<MsCard :has-breadcrumb="true" simple>
|
||||
<a-alert class="mb-6" type="warning">{{ t('system.orgTemplate.enableDescription') }}</a-alert>
|
||||
<a-alert class="mb-6" :type="isEnable ? 'warning' : 'info'">{{
|
||||
isEnable ? t('system.orgTemplate.enableDescription') : t('system.orgTemplate.fieldLimit')
|
||||
}}</a-alert>
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<span v-if="isEnable" class="font-medium">{{ t('system.orgTemplate.fieldList') }}</span>
|
||||
<a-button v-else type="primary" :disabled="false" @click="fieldHandler('add')">
|
||||
<a-button v-else type="primary" :disabled="totalData.length > 20" @click="fieldHandler('add')">
|
||||
{{ t('system.orgTemplate.addField') }}
|
||||
</a-button>
|
||||
<a-input-search
|
||||
|
@ -17,13 +19,22 @@
|
|||
</div>
|
||||
<MsBaseTable v-bind="propsRes" ref="tableRef" v-on="propsEvent">
|
||||
<template #name="{ record }">
|
||||
<MsIcon v-if="getIconType(record.type).type !== 'system'" :type="getIconType(record.type).iconName" size="16" />
|
||||
<MsIcon v-if="!record.internal" :type="getIconType(record.type)?.iconName || ''" size="16" />
|
||||
<span class="ml-2">{{ record.name }}</span>
|
||||
<span v-if="record.internal" class="system-flag">{{ t('system.orgTemplate.isSystem') }}</span>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<div class="flex flex-row flex-nowrap">
|
||||
<MsButton class="!mr-0" @click="fieldHandler('edit', record)">{{ t('system.orgTemplate.edit') }}</MsButton>
|
||||
<MsPopConfirm
|
||||
type="error"
|
||||
:title="t('system.orgTemplate.updateTip', { name: characterLimit(record.name) })"
|
||||
:sub-title-tip="t('system.orgTemplate.updateDescription')"
|
||||
:ok-text="t('system.orgTemplate.confirm')"
|
||||
@confirm="handleOk(record)"
|
||||
>
|
||||
<MsButton class="!mr-0">{{ t('system.orgTemplate.edit') }}</MsButton></MsPopConfirm
|
||||
>
|
||||
|
||||
<a-divider v-if="!record.internal" direction="vertical" />
|
||||
<MsTableMoreAction
|
||||
v-if="!record.internal"
|
||||
|
@ -33,7 +44,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<template #fieldType="{ record }">
|
||||
<span>{{ getIconType(record.type)['type'] }}</span>
|
||||
<span>{{ getIconType(record.type)?.label }}</span>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<EditFieldDrawer ref="fieldDrawerRef" v-model:visible="showDrawer" @success="successHandler" />
|
||||
|
@ -41,12 +52,16 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* @description 系统管理-组织-模版-字段列表
|
||||
*/
|
||||
import { ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import MsPopConfirm from '@/components/pure/ms-popconfirm/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';
|
||||
|
@ -58,11 +73,15 @@
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import { useAppStore, useTableStore } from '@/store';
|
||||
import useTemplateStore from '@/store/modules/setting/template';
|
||||
import { characterLimit } from '@/utils';
|
||||
|
||||
import type { AddOrUpdateField } from '@/models/setting/template';
|
||||
import type { AddOrUpdateField, SeneType } from '@/models/setting/template';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { TemplateIconEnum } from '@/enums/templateEnum';
|
||||
|
||||
import { cardList, getIconType } from './fieldSetting';
|
||||
|
||||
const templateStore = useTemplateStore();
|
||||
|
||||
const { t } = useI18n();
|
||||
const tableStore = useTableStore();
|
||||
|
@ -109,11 +128,10 @@
|
|||
showDrag: false,
|
||||
},
|
||||
];
|
||||
|
||||
tableStore.initColumn(TableKeyEnum.ORGANIZATION_TEMPLATE, fieldColumns, 'drawer');
|
||||
tableStore.initColumn(TableKeyEnum.ORGANIZATION_TEMPLATE_FIELD_SETTING, fieldColumns, 'drawer');
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, setProps } = useTable(getFieldList, {
|
||||
tableKey: TableKeyEnum.ORGANIZATION_TEMPLATE,
|
||||
tableKey: TableKeyEnum.ORGANIZATION_TEMPLATE_FIELD_SETTING,
|
||||
scroll: { x: '1000px' },
|
||||
selectable: false,
|
||||
noDisable: true,
|
||||
|
@ -124,73 +142,40 @@
|
|||
});
|
||||
|
||||
const keyword = ref('');
|
||||
const totalData = ref([]);
|
||||
|
||||
// 查询字段
|
||||
// 查询模板字段
|
||||
const searchFiled = async () => {
|
||||
try {
|
||||
const totalData = await getFieldList({ organizationId: currentOrd, scene: route.query.type });
|
||||
const filterData = totalData.filter((item: AddOrUpdateField) => item.name.includes(keyword.value));
|
||||
totalData.value = await getFieldList({ organizationId: currentOrd, scene: route.query.type });
|
||||
const filterData = totalData.value.filter((item: AddOrUpdateField) => item.name.includes(keyword.value));
|
||||
setProps({ data: filterData });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
const scene = ref<SeneType>('');
|
||||
const fetchData = async () => {
|
||||
const scene = route.query.type;
|
||||
scene.value = route.query.type;
|
||||
setLoadListParams({ organizationId: currentOrd, scene });
|
||||
await loadList();
|
||||
};
|
||||
|
||||
const tableRef = ref();
|
||||
const isEnable = ref<boolean>(false); // 开始默认未启用
|
||||
const isEnable = ref<boolean>(templateStore.templateStatus[scene.value as string]); // 开始默认未启用
|
||||
|
||||
// 切换模版是否启用展示操作列
|
||||
const isEnableOperation = () => {
|
||||
if (isEnable.value) {
|
||||
const noOperationColumn = fieldColumns.slice(0, -1);
|
||||
tableStore.setColumns(TableKeyEnum.ORGANIZATION_TEMPLATE, noOperationColumn, 'drawer');
|
||||
tableStore.setColumns(TableKeyEnum.ORGANIZATION_TEMPLATE_FIELD_SETTING, noOperationColumn, 'drawer');
|
||||
tableRef.value.initColumn();
|
||||
} else {
|
||||
tableStore.setColumns(TableKeyEnum.ORGANIZATION_TEMPLATE, fieldColumns, 'drawer');
|
||||
tableStore.setColumns(TableKeyEnum.ORGANIZATION_TEMPLATE_FIELD_SETTING, fieldColumns, 'drawer');
|
||||
tableRef.value.initColumn();
|
||||
}
|
||||
};
|
||||
|
||||
// 获取当前字段类型
|
||||
const getIconType = (iconType: string) => {
|
||||
switch (iconType) {
|
||||
case 'INPUT':
|
||||
return { iconName: TemplateIconEnum.INPUT, type: t('system.orgTemplate.input') };
|
||||
case 'TEXTAREA':
|
||||
return { iconName: TemplateIconEnum.TEXTAREA, type: t('system.orgTemplate.textarea') };
|
||||
case 'SELECT':
|
||||
return { iconName: TemplateIconEnum.SELECT, type: t('system.orgTemplate.select') };
|
||||
case 'MULTIPLE_SELECT':
|
||||
return { iconName: TemplateIconEnum.MULTIPLE_SELECT, type: t('system.orgTemplate.multipleSelect') };
|
||||
case 'RADIO':
|
||||
return { iconName: TemplateIconEnum.RADIO, type: t('system.orgTemplate.radio') };
|
||||
case 'CHECKBOX':
|
||||
return { iconName: TemplateIconEnum.CHECKBOX, type: t('system.orgTemplate.checkbox') };
|
||||
case 'MEMBER':
|
||||
return { iconName: TemplateIconEnum.MEMBER, type: t('system.orgTemplate.member') };
|
||||
case 'MULTIPLE_MEMBER':
|
||||
return { iconName: TemplateIconEnum.MULTIPLE_MEMBER, type: t('system.orgTemplate.multipleMember') };
|
||||
case 'DATE':
|
||||
return { iconName: TemplateIconEnum.DATE, type: t('system.orgTemplate.date') };
|
||||
case 'DATETIME':
|
||||
return { iconName: TemplateIconEnum.DATE, type: t('system.orgTemplate.dateTime') };
|
||||
case 'INT':
|
||||
return { iconName: TemplateIconEnum.NUMBER, type: t('system.orgTemplate.number') };
|
||||
case 'FLOAT':
|
||||
return { iconName: TemplateIconEnum.NUMBER, type: t('system.orgTemplate.number') };
|
||||
case 'MULTIPLE_INPUT':
|
||||
return { iconName: TemplateIconEnum.MULTIPLE_INPUT, type: t('system.orgTemplate.multipleInput') };
|
||||
default:
|
||||
return { type: 'system', iconName: '' };
|
||||
}
|
||||
};
|
||||
|
||||
const moreActions: ActionsItem[] = [
|
||||
{
|
||||
label: 'system.userGroup.delete',
|
||||
|
@ -214,7 +199,7 @@
|
|||
try {
|
||||
if (record.id) await deleteOrdField(record.id);
|
||||
Message.success(t('system.user.deleteUserSuccess'));
|
||||
loadList();
|
||||
fetchData();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
@ -235,28 +220,21 @@
|
|||
const fieldDrawerRef = ref();
|
||||
const fieldHandler = (type: string, record?: AddOrUpdateField) => {
|
||||
showDrawer.value = true;
|
||||
if (type === 'edit' && record) fieldDrawerRef.value.isEditHandler(record);
|
||||
if (type === 'edit' && record) fieldDrawerRef.value.editHandler(record);
|
||||
};
|
||||
|
||||
const handleOk = (record: AddOrUpdateField) => {
|
||||
fieldHandler('edit', record);
|
||||
};
|
||||
|
||||
const successHandler = () => {
|
||||
loadList();
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const templateList = ref([
|
||||
{
|
||||
value: 'FUNCTIONAL',
|
||||
name: 'system.orgTemplate.caseTemplates',
|
||||
},
|
||||
{ value: 'API', name: 'system.orgTemplate.APITemplates' },
|
||||
{ value: 'UI', name: 'system.orgTemplate.UITemplates' },
|
||||
{ value: 'TEST_PLAN', name: 'system.orgTemplate.testPlanTemplates' },
|
||||
{ value: 'BUG', name: 'system.orgTemplate.defectTemplates' },
|
||||
]);
|
||||
|
||||
// 更新面包屑根据不同的模版
|
||||
const updateBreadcrumbList = () => {
|
||||
const { breadcrumbList } = appStore;
|
||||
const breadTitle = templateList.value.find((item) => item.value === route.query.type);
|
||||
const breadTitle = cardList.find((item) => item.key === route.query.type);
|
||||
if (breadTitle) {
|
||||
breadcrumbList[0].locale = breadTitle.name;
|
||||
appStore.setBreadcrumbList(breadcrumbList);
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
<template>
|
||||
<MsCard
|
||||
:loading="loading"
|
||||
:title="title"
|
||||
:is-edit="isEdit"
|
||||
has-breadcrumb
|
||||
@save="saveHandler"
|
||||
@save-and-continue="saveHandler(true)"
|
||||
>
|
||||
<template #headerRight>
|
||||
<div class="rightBtn">
|
||||
<a-button v-show="isPreview" type="outline" class="text-[var(--color-text-1)]" @click="togglePreview">{{
|
||||
t('system.orgTemplate.templatePreview')
|
||||
}}</a-button>
|
||||
<a-button v-show="!isPreview" type="outline" class="text-[var(--color-text-1)]" @click="togglePreview">{{
|
||||
t('system.orgTemplate.exitPreview')
|
||||
}}</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 非预览模式 -->
|
||||
<div v-if="isPreview" class="nonPreview">
|
||||
<a-form ref="formRef" :model="templateForm" layout="vertical">
|
||||
<a-form-item :label="t('system.orgTemplate.templateName')" field="name" asterisk-position="end" required>
|
||||
<a-input
|
||||
v-model:model-value="templateForm.name"
|
||||
:placeholder="t('system.orgTemplate.templateNamePlaceholder')"
|
||||
:max-length="255"
|
||||
show-word-limit
|
||||
class="max-w-[732px]"
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item field="remark" :label="t('system.orgTemplate.description')" asterisk-position="end">
|
||||
<a-textarea
|
||||
v-model="templateForm.remark"
|
||||
:max-length="255"
|
||||
:placeholder="t('system.orgTemplate.resDescription')"
|
||||
:auto-size="{
|
||||
maxRows: 1,
|
||||
}"
|
||||
class="max-w-[732px]"
|
||||
></a-textarea>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<!-- 已有字段表 -->
|
||||
<TemplateManagementTable ref="templateFieldTableRef" :custom-list="tableFiledDetailList" :is-edit="isEdit" />
|
||||
</div>
|
||||
<!-- 预览模式 -->
|
||||
<PreviewTemplate v-else :select-field="selectFiledToTem" />
|
||||
</MsCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* @description 系统管理-组织-模版-模版管理-创建&编辑
|
||||
*/
|
||||
import { ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { FormInstance, Message, ValidatedError } from '@arco-design/web-vue';
|
||||
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import TemplateManagementTable from './templateManagementTable.vue';
|
||||
import PreviewTemplate from './viewTemplate.vue';
|
||||
|
||||
import {
|
||||
createOrganizeTemplateInfo,
|
||||
getOrganizeTemplateInfo,
|
||||
updateOrganizeTemplateInfo,
|
||||
} from '@/api/modules/setting/template';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useLeaveUnSaveTip from '@/hooks/useLeaveUnSaveTip';
|
||||
import { useAppStore } from '@/store';
|
||||
import useTemplateStore from '@/store/modules/setting/template';
|
||||
import { sleep } from '@/utils';
|
||||
import { scrollIntoView } from '@/utils/dom';
|
||||
|
||||
import type { ActionTemplateManage, CustomField } from '@/models/setting/template';
|
||||
import { SettingRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const templateStore = useTemplateStore();
|
||||
useLeaveUnSaveTip();
|
||||
|
||||
const title = ref('');
|
||||
const loading = ref(false);
|
||||
|
||||
const initTemplateForm = {
|
||||
name: '',
|
||||
remark: '',
|
||||
};
|
||||
|
||||
const templateForm = ref({ ...initTemplateForm });
|
||||
|
||||
const tableFiledDetailList = ref([]);
|
||||
// 获取模板详情
|
||||
const getTemplateInfo = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await getOrganizeTemplateInfo(route.query.id as string);
|
||||
const { name, remark, customFields, scoped, enableThirdPart, scene } = res;
|
||||
templateForm.value.name = name;
|
||||
templateForm.value.remark = remark;
|
||||
// 处理 字段列表
|
||||
tableFiledDetailList.value = customFields;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const isEdit = ref(false);
|
||||
const templateFieldTableRef = ref();
|
||||
watchEffect(() => {
|
||||
if (route.query.id) {
|
||||
title.value = t('menu.settings.organization.templateManagementEdit');
|
||||
isEdit.value = true;
|
||||
getTemplateInfo();
|
||||
} else {
|
||||
title.value = t('menu.settings.organization.templateManagementDetail');
|
||||
isEdit.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
// 获取模板参数
|
||||
function getTemplateParams(): ActionTemplateManage {
|
||||
const result: CustomField[] = templateFieldTableRef.value.getCustomFields();
|
||||
const { name, remark } = templateForm.value;
|
||||
return {
|
||||
name,
|
||||
remark,
|
||||
customFields: result,
|
||||
scopeId: appStore.currentOrgId,
|
||||
scene: route.query.type,
|
||||
};
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
templateForm.value = { ...initTemplateForm };
|
||||
}
|
||||
|
||||
const isContinueFlag = ref(false);
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
loading.value = true;
|
||||
const params = getTemplateParams();
|
||||
if (isEdit.value) {
|
||||
await updateOrganizeTemplateInfo(params);
|
||||
Message.success(t('system.resourcePool.updateSuccess'));
|
||||
} else {
|
||||
await createOrganizeTemplateInfo(params);
|
||||
Message.success(t('system.orgTemplate.addSuccess'));
|
||||
}
|
||||
if (isContinueFlag.value) {
|
||||
resetForm();
|
||||
} else {
|
||||
await sleep(300);
|
||||
router.push({ name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_DETAIL });
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 保存
|
||||
async function saveHandler(isContinue = false) {
|
||||
isContinueFlag.value = isContinue;
|
||||
formRef.value?.validate(async (errors: Record<string, ValidatedError> | undefined) => {
|
||||
if (!errors) {
|
||||
save();
|
||||
} else {
|
||||
return scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const selectFiledToTem = ref([]); // 非预览模式模板已选择字段
|
||||
// 是否预览模式
|
||||
const isPreview = ref<boolean>(true); // 默认非预览模式
|
||||
function togglePreview() {
|
||||
isPreview.value = !isPreview.value;
|
||||
if (!isPreview.value) {
|
||||
selectFiledToTem.value = templateFieldTableRef.value.getSelectFiled();
|
||||
templateStore.setPreviewHandler(selectFiledToTem.value);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
templateFieldTableRef.value.setDefaultField();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.rightBtn {
|
||||
:deep(.arco-btn-outline) {
|
||||
border-color: var(--color-text-input-border) !important;
|
||||
color: var(--color-text-1) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -3,7 +3,7 @@
|
|||
<div class="innerWrapper">
|
||||
<div class="content">
|
||||
<div class="logo-img h-[48px] w-[48px]">
|
||||
<svg-icon width="36px" height="36px" :name="svgList[props.cardItem.value]"></svg-icon>
|
||||
<svg-icon width="36px" height="36px" :name="props.cardItem.value"></svg-icon>
|
||||
</div>
|
||||
<div class="template-operation">
|
||||
<div class="flex items-center">
|
||||
|
@ -16,12 +16,14 @@
|
|||
<a-divider direction="vertical" />
|
||||
</span>
|
||||
<span class="operation hover:text-[rgb(var(--primary-5))]">
|
||||
<span>{{ t('system.orgTemplate.TemplateManagement') }}</span> <a-divider direction="vertical" />
|
||||
<span @click="templateManagement">{{ t('system.orgTemplate.TemplateManagement') }}</span>
|
||||
<a-divider v-if="props.cardItem.key == 'BUG'" direction="vertical" />
|
||||
</span>
|
||||
<span v-if="props.cardItem.value === 'BUG'" class="operation hover:text-[rgb(var(--primary-5))]">
|
||||
<span>{{ t('system.orgTemplate.workflowSetup') }}</span> <a-divider direction="vertical" />
|
||||
<span v-if="props.cardItem.key === 'BUG'" class="operation hover:text-[rgb(var(--primary-5))]">
|
||||
<span>{{ t('system.orgTemplate.workflowSetup') }}</span>
|
||||
<a-divider v-if="!props.cardItem.enable" direction="vertical" />
|
||||
</span>
|
||||
<span class="rounded p-[2px] hover:bg-[rgb(var(--primary-9))]">
|
||||
<span v-if="!props.cardItem.enable" class="rounded p-[2px] hover:bg-[rgb(var(--primary-9))]">
|
||||
<MsTableMoreAction :list="moreActions" @select="handleMoreActionSelect"
|
||||
/></span>
|
||||
</div>
|
||||
|
@ -58,14 +60,6 @@
|
|||
},
|
||||
]);
|
||||
|
||||
const svgList = ref<Record<string, any>>({
|
||||
FUNCTIONAL: 'caseTemplate',
|
||||
API: 'api_ui_Template',
|
||||
UI: 'api_ui_Template',
|
||||
TEST_PLAN: 'testPlanTemplate',
|
||||
BUG: 'defectTemplate',
|
||||
});
|
||||
|
||||
const handleMoreActionSelect = (item: ActionsItem) => {};
|
||||
|
||||
// 字段设置
|
||||
|
@ -73,7 +67,16 @@
|
|||
router.push({
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_FILED_SETTING,
|
||||
query: {
|
||||
type: props.cardItem.value,
|
||||
type: props.cardItem.key,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const templateManagement = () => {
|
||||
router.push({
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT,
|
||||
query: {
|
||||
type: props.cardItem.key,
|
||||
},
|
||||
});
|
||||
};
|
|
@ -0,0 +1,210 @@
|
|||
<template>
|
||||
<MsCard has-breadcrumb simple>
|
||||
<a-alert v-if="isEnable" class="mb-6" type="warning">{{ t('system.orgTemplate.enableTemplateTip') }}</a-alert>
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<span v-if="isEnable" class="font-medium">{{ t('system.orgTemplate.templateList') }}</span>
|
||||
<a-button v-else type="primary" :disabled="false" @click="createTemplate">
|
||||
{{ t('system.orgTemplate.createTemplate') }}
|
||||
</a-button>
|
||||
<a-input-search
|
||||
v-model:model-value="keyword"
|
||||
:placeholder="t('system.orgTemplate.searchTip')"
|
||||
class="w-[230px]"
|
||||
allow-clear
|
||||
@search="searchFiled"
|
||||
@press-enter="searchFiled"
|
||||
></a-input-search>
|
||||
</div>
|
||||
<MsBaseTable v-bind="propsRes" ref="tableRef" v-on="propsEvent">
|
||||
<template #name="{ record }">
|
||||
<span class="ml-2">{{ record.name }}</span>
|
||||
<span v-if="record.internal" class="system-flag">{{ t('system.orgTemplate.isSystem') }}</span>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<div class="flex flex-row flex-nowrap">
|
||||
<MsButton @click="editTemplate(record.id)">{{ t('system.orgTemplate.edit') }}</MsButton>
|
||||
<MsButton class="!mr-0">{{ t('system.orgTemplate.copy') }}</MsButton>
|
||||
<a-divider v-if="!record.internal" direction="vertical" />
|
||||
<MsTableMoreAction
|
||||
v-if="!record.internal"
|
||||
:list="moreActions"
|
||||
@select="(item) => handleMoreActionSelect(item, record)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
</MsCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* @description 系统管理-组织-模版-模版管理列表
|
||||
*/
|
||||
import { ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
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 MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
|
||||
import { deleteOrdField, getOrganizeTemplateList } from '@/api/modules/setting/template';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import router from '@/router';
|
||||
import { useAppStore, useTableStore } from '@/store';
|
||||
import useTemplateStore from '@/store/modules/setting/template';
|
||||
import { characterLimit } from '@/utils';
|
||||
|
||||
import type { OrdTemplateManagement } from '@/models/setting/template';
|
||||
import { SettingRouteEnum } from '@/enums/routeEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const tableStore = useTableStore();
|
||||
const appStore = useAppStore();
|
||||
const templateStore = useTemplateStore();
|
||||
const { openModal } = useModal();
|
||||
|
||||
const isEnable = ref<boolean>(false);
|
||||
|
||||
const keyword = ref('');
|
||||
const currentOrd = appStore.currentOrgId;
|
||||
|
||||
const fieldColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'system.orgTemplate.columnTemplateName',
|
||||
slotName: 'name',
|
||||
dataIndex: 'name',
|
||||
width: 300,
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.description',
|
||||
dataIndex: 'remark',
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.columnFieldUpdatedTime',
|
||||
dataIndex: 'updateTime',
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.operation',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
},
|
||||
];
|
||||
|
||||
tableStore.initColumn(TableKeyEnum.ORGANIZATION_TEMPLATE_MANAGEMENT, fieldColumns, 'drawer');
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, setProps } = useTable(getOrganizeTemplateList, {
|
||||
tableKey: TableKeyEnum.ORGANIZATION_TEMPLATE_MANAGEMENT,
|
||||
scroll: { x: '1000px' },
|
||||
selectable: false,
|
||||
noDisable: true,
|
||||
size: 'default',
|
||||
showSetting: true,
|
||||
showPagination: false,
|
||||
heightUsed: 380,
|
||||
});
|
||||
|
||||
const totalList = ref<OrdTemplateManagement[]>([]);
|
||||
// 查询字段
|
||||
const searchFiled = async () => {
|
||||
try {
|
||||
totalList.value = await getOrganizeTemplateList({ organizationId: currentOrd, scene: route.query.type });
|
||||
const filterData = totalList.value.filter((item: OrdTemplateManagement) => item.name.includes(keyword.value));
|
||||
setProps({ data: filterData });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
const moreActions: ActionsItem[] = [
|
||||
{
|
||||
label: 'system.userGroup.delete',
|
||||
danger: true,
|
||||
eventTag: 'delete',
|
||||
},
|
||||
];
|
||||
// 删除模板
|
||||
const handlerDelete = (record: any) => {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('system.orgTemplate.deleteTitle', { name: characterLimit(record.name) }),
|
||||
content: t('system.userGroup.beforeDeleteUserGroup'),
|
||||
okText: t('system.userGroup.confirmDelete'),
|
||||
cancelText: t('system.userGroup.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
if (record.id) await deleteOrdField(record.id);
|
||||
Message.success(t('system.user.deleteUserSuccess'));
|
||||
loadList();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
};
|
||||
|
||||
// 更多操作
|
||||
const handleMoreActionSelect = (item: ActionsItem, record: any) => {
|
||||
if (item.eventTag === 'delete') {
|
||||
handlerDelete(record);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchData = async () => {
|
||||
const scene = route.query.type;
|
||||
setLoadListParams({ organizationId: currentOrd, scene });
|
||||
await loadList();
|
||||
};
|
||||
|
||||
// 创建模板
|
||||
const createTemplate = () => {
|
||||
templateStore.setPreviewHandler([]);
|
||||
router.push({
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_DETAIL,
|
||||
query: {
|
||||
type: route.query.type,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑模板
|
||||
const editTemplate = (id: string) => {
|
||||
router.push({
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE_MANAGEMENT_DETAIL,
|
||||
query: {
|
||||
type: route.query.type,
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.system-flag {
|
||||
background: var(--color-text-n8);
|
||||
@apply ml-2 rounded p-1 text-xs;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,290 @@
|
|||
<template>
|
||||
<MsBaseTable v-bind="propsRes" ref="tableRef" v-on="propsEvent">
|
||||
<template #name="{ record }">
|
||||
<MsIcon v-if="!record.internal" :type="getIconType(record.type)?.iconName || ''" size="16" />
|
||||
<span class="ml-2">{{ record.name }}</span>
|
||||
<span v-if="record.internal" class="system-flag">{{ t('system.orgTemplate.isSystem') }}</span>
|
||||
</template>
|
||||
<template #defaultValue="{ record }">
|
||||
<div class="form-create-wrapper w-full">
|
||||
<MsFormCreate v-model:api="record.fApi" :rule="record.formRules" :option="configOptions" />
|
||||
</div>
|
||||
</template>
|
||||
<template #required="{ record }">
|
||||
<a-checkbox v-model="record.required"></a-checkbox>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<div class="flex flex-row flex-nowrap">
|
||||
<MsButton class="!mr-0" @click="editField(record)">{{ t('system.orgTemplate.edit') }}</MsButton>
|
||||
<a-divider v-if="!record.internal" direction="vertical" />
|
||||
<MsButton v-if="!record.internal" class="!mr-0" @click="deleteSelectedField(record)">{{
|
||||
t('system.orgTemplate.delete')
|
||||
}}</MsButton>
|
||||
</div>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<!-- 添加字段到模版抽屉 -->
|
||||
<AddFieldToTemplateDrawer
|
||||
ref="fieldSelectRef"
|
||||
v-model:visible="showDrawer"
|
||||
:system-data="(systemData as DefinedFieldItem[])"
|
||||
:custom-data="(customData as DefinedFieldItem[])"
|
||||
:selected-data="(templateStore.previewList as DefinedFieldItem[])"
|
||||
@confirm="confirmHandler"
|
||||
@update="updateFieldHandler"
|
||||
/>
|
||||
<a-button class="mt-3 px-0" type="text" @click="addField">
|
||||
<template #icon>
|
||||
<icon-plus class="text-[14px]" />
|
||||
</template>
|
||||
{{ t('system.orgTemplate.createField') }}
|
||||
</a-button>
|
||||
<EditFieldDrawer ref="fieldDrawerRef" v-model:visible="showFieldDrawer" @success="updateFieldHandler" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import { FieldTypeFormRules } from '@/components/pure/ms-form-create/form-create';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/formCreate.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 AddFieldToTemplateDrawer from './addFieldToTemplateDrawer.vue';
|
||||
import EditFieldDrawer from './editFieldDrawer.vue';
|
||||
|
||||
import { getFieldList } from '@/api/modules/setting/template';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore, useTableStore } from '@/store';
|
||||
import useTemplateStore from '@/store/modules/setting/template';
|
||||
|
||||
import type { CustomField, DefinedFieldItem } from '@/models/setting/template';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
import { getIconType } from './fieldSetting';
|
||||
|
||||
const tableStore = useTableStore();
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
const templateStore = useTemplateStore();
|
||||
const route = useRoute();
|
||||
|
||||
const props = defineProps<{
|
||||
customList: CustomField[]; // 用于回显表格当前选择字段
|
||||
isEdit: boolean; // 是否编辑
|
||||
}>();
|
||||
|
||||
const templateFieldColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'system.orgTemplate.name',
|
||||
slotName: 'name',
|
||||
dataIndex: 'name',
|
||||
width: 300,
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.defaultValue',
|
||||
dataIndex: 'defaultValue',
|
||||
slotName: 'defaultValue',
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.required',
|
||||
dataIndex: 'required',
|
||||
slotName: 'required',
|
||||
width: 180,
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.description',
|
||||
dataIndex: 'remark',
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.operation',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
},
|
||||
];
|
||||
|
||||
tableStore.initColumn(TableKeyEnum.ORGANIZATION_TEMPLATE_MANAGEMENT_FIELD, templateFieldColumns, 'drawer');
|
||||
const { propsRes, propsEvent, setProps } = useTable(undefined, {
|
||||
tableKey: TableKeyEnum.ORGANIZATION_TEMPLATE_MANAGEMENT_FIELD,
|
||||
scroll: { x: '1000px' },
|
||||
selectable: false,
|
||||
noDisable: true,
|
||||
size: 'default',
|
||||
showSetting: true,
|
||||
showPagination: false,
|
||||
heightUsed: 560,
|
||||
enableDrag: true,
|
||||
});
|
||||
|
||||
const configOptions = ref({
|
||||
resetBtn: false,
|
||||
submitBtn: false,
|
||||
on: false,
|
||||
form: {
|
||||
layout: 'vertical',
|
||||
labelAlign: 'left',
|
||||
},
|
||||
row: {
|
||||
gutter: 0,
|
||||
},
|
||||
wrap: {
|
||||
'asterisk-position': 'end',
|
||||
'validate-trigger': ['change'],
|
||||
'hide-label': true,
|
||||
'hide-asterisk': true,
|
||||
},
|
||||
});
|
||||
const showDrawer = ref<boolean>(false);
|
||||
|
||||
const data = ref<DefinedFieldItem[]>([]);
|
||||
const systemData = ref<DefinedFieldItem[]>([]);
|
||||
const customData = ref<DefinedFieldItem[]>([]);
|
||||
const totalTemplateField = ref<DefinedFieldItem[]>([]);
|
||||
const currentOrd = appStore.currentOrgId;
|
||||
|
||||
// 处理表单数据格式
|
||||
const getFieldOptionList = () => {
|
||||
totalTemplateField.value = totalTemplateField.value.map((item: any) => {
|
||||
const currentFormRules = FieldTypeFormRules[item.type];
|
||||
let selectOptions: any = [];
|
||||
if (item.options && item.options.length) {
|
||||
selectOptions = item.options.map((optionItem: any) => {
|
||||
return {
|
||||
label: optionItem.text,
|
||||
value: optionItem.value,
|
||||
};
|
||||
});
|
||||
currentFormRules.options = selectOptions;
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
formRules: [{ ...currentFormRules, value: item.value, props: { options: selectOptions } }],
|
||||
fApi: null,
|
||||
required: item.internal,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// 获取当前用例模版下所有已存在字段
|
||||
const getClassifyField = async () => {
|
||||
try {
|
||||
totalTemplateField.value = await getFieldList({ organizationId: currentOrd, scene: route.query.type });
|
||||
getFieldOptionList();
|
||||
systemData.value = totalTemplateField.value.filter((item: any) => item.internal);
|
||||
customData.value = totalTemplateField.value.filter((item: any) => !item.internal);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 确定处理字段表单数据
|
||||
const confirmHandler = (dataList: DefinedFieldItem[]) => {
|
||||
data.value = dataList;
|
||||
setProps({ data: data.value });
|
||||
};
|
||||
|
||||
const showFieldDrawer = ref<boolean>(false);
|
||||
const fieldDrawerRef = ref();
|
||||
|
||||
// 编辑字段
|
||||
const editField = (record: DefinedFieldItem) => {
|
||||
showFieldDrawer.value = true;
|
||||
fieldDrawerRef.value.editHandler(record);
|
||||
};
|
||||
|
||||
const fieldSelectRef = ref();
|
||||
// 添加字段
|
||||
const addField = async () => {
|
||||
showDrawer.value = true;
|
||||
await getClassifyField();
|
||||
fieldSelectRef.value.showSelectField();
|
||||
};
|
||||
|
||||
// 编辑更新已选择字段
|
||||
const updateFieldHandler = async () => {
|
||||
await getClassifyField();
|
||||
data.value =
|
||||
totalTemplateField.value.filter((item) => data.value.some((dataItem) => item.id === dataItem.id)) || [];
|
||||
if (data.value.length > 0) {
|
||||
setProps({ data: data.value });
|
||||
}
|
||||
};
|
||||
|
||||
// 删除已选择字段
|
||||
const deleteSelectedField = (record: DefinedFieldItem) => {
|
||||
data.value = data.value.filter((item) => item.id !== record.id);
|
||||
setProps({ data: data.value });
|
||||
};
|
||||
|
||||
// 获取table内字段customFields
|
||||
const getCustomFields = () => {
|
||||
return data.value.map((item) => {
|
||||
return {
|
||||
fieldId: item.id,
|
||||
fieldName: item.name,
|
||||
required: item.required,
|
||||
apiFieldId: '',
|
||||
defaultValue: item.fApi.formData().fieldName,
|
||||
};
|
||||
});
|
||||
};
|
||||
// 外界获取表格字段进行存储
|
||||
const getSelectFiled = () => {
|
||||
return data.value;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => data.value,
|
||||
(val) => {
|
||||
templateStore.setPreviewHandler(val as DefinedFieldItem[]);
|
||||
setProps({ data: templateStore.previewList });
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const setDefaultField = async () => {
|
||||
await getClassifyField();
|
||||
data.value = systemData.value;
|
||||
};
|
||||
|
||||
const showDetailFields = () => {};
|
||||
|
||||
onMounted(() => {
|
||||
if (props.isEdit) {
|
||||
showDetailFields();
|
||||
} else {
|
||||
data.value = templateStore.previewList;
|
||||
setProps({ data: templateStore.previewList });
|
||||
}
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
getCustomFields,
|
||||
getSelectFiled,
|
||||
setDefaultField,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.form-create-wrapper {
|
||||
:deep(.arco-form-item) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
:deep(.arco-picker) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,250 @@
|
|||
<template>
|
||||
<div class="wrapper-preview">
|
||||
<div class="preview-left pr-4">
|
||||
<a-form ref="viewFormRef" class="rounded-[4px]" :model="viewForm" layout="vertical">
|
||||
<a-form-item
|
||||
field="caseName"
|
||||
:label="t('system.orgTemplate.caseName')"
|
||||
:rules="[{ required: true, message: t('system.orgTemplate.caseNamePlaceholder') }]"
|
||||
required
|
||||
asterisk-position="end"
|
||||
>
|
||||
<a-input
|
||||
v-model="viewForm.name"
|
||||
:max-length="255"
|
||||
:placeholder="t('system.orgTemplate.caseNamePlaceholder')"
|
||||
show-word-limit
|
||||
allow-clear
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item field="precondition" :label="t('system.orgTemplate.precondition')" asterisk-position="end">
|
||||
<MsRichText v-model="viewForm.precondition" />
|
||||
</a-form-item>
|
||||
<a-form-item field="step" :label="t('system.orgTemplate.stepDescription')" class="relative">
|
||||
<div class="absolute left-16 top-0">
|
||||
<a-divider direction="vertical" />
|
||||
<a-dropdown :popup-max-height="false" @select="handleSelectType">
|
||||
<span class="text-[14px] text-[var(--color-text-4)]"
|
||||
>{{ t('system.orgTemplate.changeType') }} <icon-down
|
||||
/></span>
|
||||
<template #content>
|
||||
<a-doption> {{ t('system.orgTemplate.stepDescription') }}</a-doption>
|
||||
<a-doption>{{ t('system.orgTemplate.textDescription') }}</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
<!-- 步骤描述 -->
|
||||
<div class="w-full">
|
||||
<MsBaseTable v-bind="propsRes" ref="stepTableRef" v-on="propsEvent">
|
||||
<template #index="{ rowIndex }">
|
||||
{{ rowIndex + 1 }}
|
||||
</template>
|
||||
<template #caseStep="{ record }">
|
||||
<a-input v-if="record.showStep" v-model="record.caseStep" class="w-max-[267px]" />
|
||||
<span v-else-if="record.caseStep && !record.showStep">{{ record.caseStep }}</span>
|
||||
<span
|
||||
v-else-if="!record.caseStep && !record.showStep"
|
||||
class="placeholder text-[var(--color-text-brand)]"
|
||||
>{{ t('system.orgTemplate.stepTip') }}</span
|
||||
>
|
||||
</template>
|
||||
<template #expectedResult="{ record }">
|
||||
<a-input v-if="record.showExpected" v-model="record.expectedResult" class="w-max-[267px]" />
|
||||
<span v-else-if="record.expectedResult && !record.showExpected">{{ record.caseStep }}</span>
|
||||
<span
|
||||
v-else-if="!record.expectedResult && !record.showExpected"
|
||||
class="placeholder text-[var(--color-text-brand)]"
|
||||
>{{ t('system.orgTemplate.expectationTip') }}</span
|
||||
>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<MsTableMoreAction
|
||||
v-if="!record.internal"
|
||||
:list="moreActions"
|
||||
@select="(item) => handleMoreActionSelect(item)"
|
||||
/>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
</div>
|
||||
<a-button class="mt-2 px-0" type="text" @click="addStep">
|
||||
<template #icon>
|
||||
<icon-plus class="text-[14px]" />
|
||||
</template>
|
||||
{{ t('system.orgTemplate.addStep') }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
<a-form-item field="remark" label="备注"> <MsRichText v-model="viewForm.remark" /> </a-form-item>
|
||||
<a-form-item field="attachment" label="添加附件">
|
||||
<div class="flex flex-col">
|
||||
<div class="mb-1"
|
||||
><a-button type="outline">
|
||||
<template #icon> <icon-plus class="text-[14px]" /> </template
|
||||
>{{ t('system.orgTemplate.addAttachment') }}</a-button
|
||||
>
|
||||
</div>
|
||||
<div class="text-[var(--color-text-4)]">{{ t('system.orgTemplate.addAttachmentTip') }}</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<div class="preview-right px-4">
|
||||
<MsFormCreate :form-rule="formRules" :form-create-key="FormCreateKeyEnum.ORGANIZE_TEMPLATE_PREVIEW_TEMPLATE" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.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 MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useTableStore } from '@/store';
|
||||
|
||||
import type { DefinedFieldItem } from '@/models/setting/template';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
const tableStore = useTableStore();
|
||||
|
||||
const props = defineProps<{
|
||||
selectField: DefinedFieldItem[];
|
||||
}>();
|
||||
|
||||
const templateFieldColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'system.orgTemplate.numberIndex',
|
||||
dataIndex: 'index',
|
||||
slotName: 'index',
|
||||
width: 100,
|
||||
showDrag: false,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.useCaseStep',
|
||||
slotName: 'caseStep',
|
||||
dataIndex: 'caseStep',
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.expectedResult',
|
||||
dataIndex: 'expectedResult',
|
||||
slotName: 'expectedResult',
|
||||
showDrag: true,
|
||||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.orgTemplate.operation',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
},
|
||||
];
|
||||
tableStore.initColumn(TableKeyEnum.ORGANIZATION_TEMPLATE_MANAGEMENT_STEP, templateFieldColumns, 'drawer');
|
||||
const { propsRes, propsEvent, setProps } = useTable(undefined, {
|
||||
tableKey: TableKeyEnum.ORGANIZATION_TEMPLATE_MANAGEMENT_STEP,
|
||||
scroll: { x: '800px' },
|
||||
selectable: false,
|
||||
noDisable: true,
|
||||
size: 'default',
|
||||
showSetting: true,
|
||||
showPagination: false,
|
||||
enableDrag: false,
|
||||
});
|
||||
|
||||
const viewForm = ref({
|
||||
name: '',
|
||||
precondition: '',
|
||||
value: '',
|
||||
remark: '',
|
||||
});
|
||||
|
||||
const handleSelectType = () => {};
|
||||
|
||||
const stepTableRef = ref();
|
||||
|
||||
const moreActions: ActionsItem[] = [
|
||||
{
|
||||
label: 'system.orgTemplate.copy',
|
||||
danger: true,
|
||||
eventTag: 'copy',
|
||||
},
|
||||
{
|
||||
label: 'system.orgTemplate.delete',
|
||||
danger: true,
|
||||
eventTag: 'delete',
|
||||
},
|
||||
];
|
||||
|
||||
const handlerDelete = () => {};
|
||||
// 更多操作
|
||||
const handleMoreActionSelect = (item: ActionsItem) => {
|
||||
if (item.eventTag === 'delete') {
|
||||
handlerDelete();
|
||||
}
|
||||
};
|
||||
|
||||
const addStep = () => {};
|
||||
|
||||
const formRuleField = ref<FormItem[][]>([]);
|
||||
const formRules = ref<FormItem[]>([]);
|
||||
// 处理表单格式
|
||||
const getFormRules = () => {
|
||||
if (props.selectField && props.selectField.length) {
|
||||
props.selectField.forEach((item: DefinedFieldItem) => {
|
||||
const currentFormItem = item.formRules?.map((rule: any) => {
|
||||
const optionsItem = rule.options.map((opt: any) => {
|
||||
return {
|
||||
text: opt.label,
|
||||
value: opt.value,
|
||||
};
|
||||
});
|
||||
return {
|
||||
type: item.type,
|
||||
name: rule.field,
|
||||
label: item.name,
|
||||
value: rule.value,
|
||||
options: optionsItem,
|
||||
required: item.required,
|
||||
};
|
||||
});
|
||||
formRuleField.value.push(currentFormItem as FormItem[]);
|
||||
});
|
||||
const result = formRuleField.value.flatMap((item) => item);
|
||||
formRules.value = result;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
setProps({ data: [{ id: 1, showStep: false, showExpected: false }] });
|
||||
getFormRules();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
getFormRules,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.wrapper-preview {
|
||||
display: flex;
|
||||
.preview-left {
|
||||
width: 100%;
|
||||
border-right: 1px solid var(--color-text-n8);
|
||||
}
|
||||
.preview-right {
|
||||
width: 428px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -35,25 +35,18 @@
|
|||
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import MsCardList from '@/components/business/ms-card-list/index.vue';
|
||||
import TemplateItem from '@/components/business/ms-template-card/index.vue';
|
||||
import TemplateItem from './components/templateItem.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useVisit from '@/hooks/useVisit';
|
||||
import useTemplateStore from '@/store/modules/setting/template';
|
||||
|
||||
import { cardList } from './components/fieldSetting';
|
||||
|
||||
const templateStore = useTemplateStore();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const cardList = ref([
|
||||
{
|
||||
id: 1001,
|
||||
value: 'FUNCTIONAL',
|
||||
name: t('system.orgTemplate.caseTemplates'),
|
||||
},
|
||||
{ id: 1002, value: 'API', name: t('system.orgTemplate.APITemplates') },
|
||||
{ id: 1003, value: 'UI', name: t('system.orgTemplate.UITemplates') },
|
||||
{ id: 1004, value: 'TEST_PLAN', name: t('system.orgTemplate.testPlanTemplates') },
|
||||
{ id: 1005, value: 'BUG', name: t('system.orgTemplate.defectTemplates') },
|
||||
]);
|
||||
|
||||
const visitedKey = 'notRemind';
|
||||
const { addVisited } = useVisit(visitedKey);
|
||||
const { getIsVisited } = useVisit(visitedKey);
|
||||
|
@ -68,6 +61,9 @@
|
|||
const doCheckIsTip = () => {
|
||||
isShowTip.value = !getIsVisited();
|
||||
};
|
||||
onBeforeMount(() => {
|
||||
templateStore.setStatus();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
doCheckIsTip();
|
||||
|
|
|
@ -22,9 +22,11 @@ export default {
|
|||
'system.orgTemplate.TemplateManagement': 'Management',
|
||||
'system.orgTemplate.workflowSetup': 'Workflow',
|
||||
'system.orgTemplate.enable': 'Enable',
|
||||
'system.orgTemplate.update': 'Update',
|
||||
'system.orgTemplate.addField': 'Add Field',
|
||||
'system.orgTemplate.update': 'Update Field',
|
||||
'system.orgTemplate.addField': 'Create Field',
|
||||
'system.orgTemplate.createField': 'Add Field',
|
||||
'system.orgTemplate.enableDescription': 'The project template is enabled. Field Settings are inoperable',
|
||||
'system.orgTemplate.fieldLimit': 'You can add a maximum of 20 fields',
|
||||
'system.orgTemplate.isSystem': 'System',
|
||||
'system.orgTemplate.fieldList': 'Field list',
|
||||
'system.orgTemplate.addOptions': 'Add an option',
|
||||
|
@ -57,4 +59,37 @@ export default {
|
|||
'system.orgTemplate.dateFormat': 'Date format',
|
||||
'system.orgTemplate.formatPlaceholder': 'Please select a format',
|
||||
'system.orgTemplate.optionsPlaceholder': 'Please enter options',
|
||||
'system.orgTemplate.columnTemplateName': 'Template name',
|
||||
'system.orgTemplate.copy': 'Copy',
|
||||
'system.orgTemplate.defaultValue': 'Default value',
|
||||
'system.orgTemplate.required': 'Required',
|
||||
'system.orgTemplate.enableTemplateTip': 'The project template is enabled. The organization template is unavailable',
|
||||
'system.orgTemplate.templateList': 'Template list',
|
||||
'system.orgTemplate.createTemplate': 'Create',
|
||||
'system.orgTemplate.templatePreview': 'Template preview',
|
||||
'system.orgTemplate.templateName': 'Template name',
|
||||
'system.orgTemplate.templateNamePlaceholder': 'Please enter a template name',
|
||||
'system.orgTemplate.optionalField': 'Optional Field',
|
||||
'system.orgTemplate.selectAll': 'select All',
|
||||
'system.orgTemplate.systemField': 'System Field',
|
||||
'system.orgTemplate.customField': 'Custom Field',
|
||||
'system.orgTemplate.selectedField': 'Selected Field',
|
||||
'system.orgTemplate.clear': 'Clear',
|
||||
'system.orgTemplate.addSuccess': 'create successfully',
|
||||
'system.orgTemplate.updateSuccess': 'update successfully',
|
||||
'system.orgTemplate.exitPreview': 'Exit Preview',
|
||||
'system.orgTemplate.useCaseStep': 'useCase Step',
|
||||
'system.orgTemplate.expectedResult': 'Expected Result',
|
||||
'system.orgTemplate.numberIndex': 'Index',
|
||||
'system.orgTemplate.addStep': 'Add Step',
|
||||
'system.orgTemplate.caseName': 'Use case name',
|
||||
'system.orgTemplate.caseNamePlaceholder': 'Please enter a use case name',
|
||||
'system.orgTemplate.precondition': 'precondition',
|
||||
'system.orgTemplate.stepDescription': 'Step description',
|
||||
'system.orgTemplate.changeType': 'Change type',
|
||||
'system.orgTemplate.textDescription': 'Text description',
|
||||
'system.orgTemplate.stepTip': 'Please enter steps',
|
||||
'system.orgTemplate.expectationTip': 'Please enter expectations',
|
||||
'system.orgTemplate.addAttachment': 'Add attachment',
|
||||
'system.orgTemplate.addAttachmentTip': 'Support any type of file, the file size does not exceed 500MB',
|
||||
};
|
||||
|
|
|
@ -22,9 +22,11 @@ export default {
|
|||
'system.orgTemplate.TemplateManagement': '模版管理',
|
||||
'system.orgTemplate.workflowSetup': '工作流设置',
|
||||
'system.orgTemplate.enable': '启用项目模版',
|
||||
'system.orgTemplate.update': '更新',
|
||||
'system.orgTemplate.update': '更新字段',
|
||||
'system.orgTemplate.addField': '新增字段',
|
||||
'system.orgTemplate.createField': '添加字段',
|
||||
'system.orgTemplate.enableDescription': '已启用项目模版,字段设置不可操作',
|
||||
'system.orgTemplate.fieldLimit': '最多可新增 20 个字段',
|
||||
'system.orgTemplate.isSystem': '系统',
|
||||
'system.orgTemplate.fieldList': '字段列表',
|
||||
'system.orgTemplate.addOptions': '添加一个选项',
|
||||
|
@ -56,4 +58,40 @@ export default {
|
|||
'system.orgTemplate.dateFormat': '日期格式',
|
||||
'system.orgTemplate.formatPlaceholder': '请选择格式',
|
||||
'system.orgTemplate.optionsPlaceholder': '请输入选项',
|
||||
'system.orgTemplate.updateTip': '确认更新 `{name}` 吗?',
|
||||
'system.orgTemplate.updateDescription': '更新后,所使用该字段模版将一起修改',
|
||||
'system.orgTemplate.confirm': '确定',
|
||||
'system.orgTemplate.columnTemplateName': '模版名称',
|
||||
'system.orgTemplate.copy': '复制',
|
||||
'system.orgTemplate.defaultValue': '默认值',
|
||||
'system.orgTemplate.required': '是否必填',
|
||||
'system.orgTemplate.enableTemplateTip': '已启用项目模版,组织模版不可操作',
|
||||
'system.orgTemplate.templateList': '模板列表',
|
||||
'system.orgTemplate.createTemplate': '创建模版',
|
||||
'system.orgTemplate.templatePreview': '模板预览',
|
||||
'system.orgTemplate.templateName': '模板名称',
|
||||
'system.orgTemplate.templateNamePlaceholder': '请输入模版名称',
|
||||
'system.orgTemplate.optionalField': '可选字段',
|
||||
'system.orgTemplate.selectAll': '全选',
|
||||
'system.orgTemplate.systemField': '系统字段',
|
||||
'system.orgTemplate.customField': '自定义字段',
|
||||
'system.orgTemplate.selectedField': '已选字段',
|
||||
'system.orgTemplate.clear': '清空',
|
||||
'system.orgTemplate.addSuccess': '新增成功',
|
||||
'system.orgTemplate.updateSuccess': '更新成功',
|
||||
'system.orgTemplate.exitPreview': '退出预览',
|
||||
'system.orgTemplate.useCaseStep': '用例步骤',
|
||||
'system.orgTemplate.expectedResult': '预期结果',
|
||||
'system.orgTemplate.numberIndex': '序号',
|
||||
'system.orgTemplate.addStep': '添加步骤',
|
||||
'system.orgTemplate.caseName': '用例名称',
|
||||
'system.orgTemplate.caseNamePlaceholder': '请输入用例名称',
|
||||
'system.orgTemplate.precondition': '前置条件',
|
||||
'system.orgTemplate.stepDescription': '步骤描述',
|
||||
'system.orgTemplate.changeType': '更改类型',
|
||||
'system.orgTemplate.textDescription': '文本描述',
|
||||
'system.orgTemplate.stepTip': '请输入步骤',
|
||||
'system.orgTemplate.expectationTip': '请输入预期',
|
||||
'system.orgTemplate.addAttachment': '添加附件',
|
||||
'system.orgTemplate.addAttachmentTip': '支持任意类型文件,文件大小不超过 500MB',
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<div class="ms-scroll">
|
||||
<div v-for="(item, index) in recordItem.pluginForms" :key="item.id" class="ms-self">
|
||||
<span class="circle text-xs leading-[16px]"> {{ index + 1 }} </span>
|
||||
<span class="cursor-pointer text-[rgb(var(--primary-5))]" @click="emit('MessageEvent', recordItem, item)">{{
|
||||
<span class="cursor-pointer text-[rgb(var(--primary-5))]" @click="getScriptEmit(recordItem, item)">{{
|
||||
item.name
|
||||
}}</span>
|
||||
</div>
|
||||
|
@ -24,8 +24,16 @@
|
|||
recordItem: PluginItem;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'MessageEvent', record: PluginItem, item: PluginForms): void;
|
||||
(e: 'messageEvent', record: PluginItem, item: PluginForms): void;
|
||||
}>();
|
||||
|
||||
const originPluginId = ref('');
|
||||
const getScriptEmit = (record: PluginItem, item: PluginForms) => {
|
||||
if (originPluginId.value !== item.id) {
|
||||
emit('messageEvent', record, item);
|
||||
originPluginId.value = item.id;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -35,6 +35,7 @@ export default {
|
|||
'system.resourcePool.disablePoolCancel': 'Cancel',
|
||||
'system.plugin.deletePluginSuccess': 'Delete successfully',
|
||||
'system.plugin.disablePluginSuccess': 'Disabled successfully',
|
||||
'system.plugin.enablePluginSuccess': 'Enabled successfully',
|
||||
'system.plugin.disablePluginContent':
|
||||
'The project can not integrate with the platform and the default template of the platform is not available, be careful!',
|
||||
'system.plugin.alertDescribe':
|
||||
|
|
|
@ -58,6 +58,7 @@ export default {
|
|||
'system.plugin.currentScene': '当前场景',
|
||||
'system.plugin.deletePluginSuccess': '删除成功',
|
||||
'system.plugin.disablePluginSuccess': '禁用成功',
|
||||
'system.plugin.enablePluginSuccess': '启用成功',
|
||||
'system.plugin.disablePluginContent': '项目无法与该平台集成且该平台默认模版不可用,谨慎操作!',
|
||||
'system.plugin.alertDescribe':
|
||||
'MeterSphereV2.10LTS 版本支持 DevOps、API 导入、请求、项目管理、协议类型的插件,具体支持插件请',
|
||||
|
|
Loading…
Reference in New Issue