feat(公共): 重构扩展formCreate控制器功能和修改相关
This commit is contained in:
parent
a1c76847aa
commit
f6eeb1150e
|
@ -13,7 +13,7 @@
|
|||
<MsRichText v-model="currentContent" class="w-full" />
|
||||
<div class="mt-4 flex flex-row justify-end gap-[12px]">
|
||||
<a-button @click="cancelClick">{{ t('common.cancel') }}</a-button>
|
||||
<a-button type="primary" :disabled="!content" @click="publish">{{ t('common.publish') }}</a-button>
|
||||
<a-button type="primary" :disabled="!currentContent" @click="publish">{{ t('common.publish') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -163,6 +163,17 @@ export const JIRAKEY = {
|
|||
},
|
||||
};
|
||||
|
||||
export const PASSWORD = {
|
||||
type: 'PassWord',
|
||||
field: 'fieldName',
|
||||
title: '',
|
||||
value: '',
|
||||
props: {
|
||||
modelValue: '',
|
||||
instructionsIcon: '',
|
||||
},
|
||||
};
|
||||
|
||||
export const FieldTypeFormRules: Record<string, FormRule> = {
|
||||
INPUT,
|
||||
SELECT,
|
||||
|
@ -178,4 +189,5 @@ export const FieldTypeFormRules: Record<string, FormRule> = {
|
|||
MULTIPLE_INPUT,
|
||||
TEXTAREA,
|
||||
JIRAKEY,
|
||||
PASSWORD,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
<template>
|
||||
<FormCreate v-model:api="fApi" :rule="formRuleList" :option="props.options || option"></FormCreate>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import { FieldTypeFormRules } from '@/components/pure/ms-form-create/form-create';
|
||||
import JiraKey from './comp/jiraKey.vue';
|
||||
import PassWord from './formcreate-password.vue';
|
||||
import SearchSelect from './searchSelect.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import type { FormItem } from './types';
|
||||
import { FormRuleItem } from './types';
|
||||
import formCreate, { Rule } from '@form-create/arco-design';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
formCreate.component('PassWord', PassWord);
|
||||
formCreate.component('SearchSelect', SearchSelect);
|
||||
formCreate.component('JiraKey', JiraKey);
|
||||
|
||||
const FormCreate = formCreate.$form();
|
||||
// 处理配置项
|
||||
const props = defineProps<{
|
||||
options?: any; // 自定义配置
|
||||
formRule: FormItem[]; // 表单的规则
|
||||
formItem: FormRuleItem[]; // 处理后的表单
|
||||
api: any; // 表单对象
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:api', 'update', 'update:form-item']);
|
||||
|
||||
const fApi = computed({
|
||||
get() {
|
||||
return props.api;
|
||||
},
|
||||
set(val) {
|
||||
emit('update:api', val);
|
||||
},
|
||||
});
|
||||
|
||||
// 规定好的字段格式
|
||||
const formItems = ref<FormItem[]>([...props.formRule]);
|
||||
// 控制器的选项
|
||||
const controlFormItemsMaps = ref<Record<string, FormItem[]>>({});
|
||||
// 级联项需要绑定change事件的选项 key对应name value 对应级联需要远程请求的那一项
|
||||
const cascadeItemsMaps = ref<Record<string, FormItem[]>>({});
|
||||
|
||||
const formRuleList = ref<FormRuleItem[]>([]);
|
||||
|
||||
function getUpdateFun(val: any, rule: any, api: any, key: string) {
|
||||
api.getRule(cascadeItemsMaps.value[key][0].name).value = '';
|
||||
api.getRule(cascadeItemsMaps.value[key][0].name).props.keyword = val;
|
||||
api.getRule(cascadeItemsMaps.value[key][0].name).props.modelValue = val;
|
||||
api.getRule(cascadeItemsMaps.value[key][0].name).props.formValue = api.formData();
|
||||
}
|
||||
|
||||
// 处理级联项添加change事件
|
||||
function initCascadeItemsMaps() {
|
||||
const cascadeItemName = formItems.value
|
||||
.filter((item) => item.couplingConfig && item.couplingConfig.cascade)
|
||||
.map((item) => item.couplingConfig && item.couplingConfig.cascade);
|
||||
// 将级联项单独映射
|
||||
formItems.value.forEach((it: FormItem) => {
|
||||
const cascadeName = it?.couplingConfig?.cascade;
|
||||
if (cascadeName && cascadeItemName.indexOf(cascadeName) > -1) {
|
||||
if (!cascadeItemsMaps.value[cascadeName]) {
|
||||
cascadeItemsMaps.value[cascadeName] = [it];
|
||||
} else {
|
||||
cascadeItemsMaps.value[cascadeName].push(it);
|
||||
}
|
||||
}
|
||||
});
|
||||
// 级联改变项添加update事件
|
||||
formItems.value = formItems.value.map((item: FormItem) => {
|
||||
if (cascadeItemName.indexOf(item.name) > -1) {
|
||||
return {
|
||||
...item,
|
||||
update(val: any, rule: any, api: any) {
|
||||
getUpdateFun(val, rule, api, item.name);
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 处理控制器项
|
||||
function getControlFormItemsMaps() {
|
||||
const parentControlsItems = [];
|
||||
formItems.value.forEach((item: FormItem) => {
|
||||
if (!item.displayConditions) {
|
||||
parentControlsItems.push(item);
|
||||
} else {
|
||||
const displayConditions = item?.displayConditions;
|
||||
if (controlFormItemsMaps.value[displayConditions.field]) {
|
||||
controlFormItemsMaps.value[displayConditions.field].push(item);
|
||||
} else {
|
||||
controlFormItemsMaps.value[displayConditions.field] = [item];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 将传进来的数据进行map映射
|
||||
function getFormCreateItem() {
|
||||
formItems.value = formItems.value.map((item: FormItem) => {
|
||||
if (controlFormItemsMaps.value[item.name]) {
|
||||
// 处理控制器
|
||||
const controlArr = controlFormItemsMaps.value[item.name];
|
||||
const conTrolMap: Record<string, FormItem[]> = {};
|
||||
controlArr.forEach((controlled: FormItem) => {
|
||||
if (conTrolMap[controlled.displayConditions?.value]) {
|
||||
conTrolMap[controlled.displayConditions?.value].push(controlled);
|
||||
} else {
|
||||
conTrolMap[controlled.displayConditions?.value] = [controlled];
|
||||
}
|
||||
});
|
||||
const controlList: any = [];
|
||||
Object.keys(conTrolMap).forEach((controlKeys: string) => {
|
||||
const controlItem = {
|
||||
value: controlKeys,
|
||||
rule: conTrolMap[controlKeys],
|
||||
};
|
||||
controlList.push(controlItem);
|
||||
});
|
||||
return {
|
||||
...item,
|
||||
control: controlList,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
};
|
||||
});
|
||||
formItems.value = formItems.value.filter((item: FormItem) => !item.displayConditions?.field);
|
||||
}
|
||||
|
||||
function convertItem(item: FormItem) {
|
||||
// 当前类型
|
||||
let fieldType;
|
||||
// 从总form类型里边配置:参考form-create.ts里边配置
|
||||
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: any) => {
|
||||
return {
|
||||
label: optionsItem.text,
|
||||
value: optionsItem.value,
|
||||
};
|
||||
});
|
||||
const ruleItem: any = {
|
||||
type: fieldType, // 表单类型
|
||||
field: item.name, // 字段
|
||||
title: t(item.label), // label 表单标签
|
||||
value: item.value || FieldTypeFormRules[currentTypeForm].value, // 目前的值
|
||||
effect: {
|
||||
required: item.required, // 是否必填
|
||||
},
|
||||
// 级联关联到某一个form上 可能存在多个级联
|
||||
options: !item.optionMethod ? currentOptions : [],
|
||||
link: [item.couplingConfig?.cascade ? item.couplingConfig?.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': '', // SearchSelect组件变化值
|
||||
'modelValue': item.value,
|
||||
'options': currentOptions, // 当前已经存在的options
|
||||
'disabled': item?.props?.disabled,
|
||||
'type': item.control?.length && item.type === 'RADIO' ? 'button' : '',
|
||||
},
|
||||
control: [],
|
||||
update: item.update,
|
||||
};
|
||||
// 如果不存在关联name删除link关联属性
|
||||
if (!ruleItem.link.filter((ink: string) => ink).length) {
|
||||
delete ruleItem.link;
|
||||
}
|
||||
// 如果不是等于下拉多选或者单选等
|
||||
if (ruleItem.type !== 'SearchSelect') {
|
||||
delete ruleItem.props.inputSearch;
|
||||
}
|
||||
let controlItem;
|
||||
if (item?.control) {
|
||||
controlItem = item.control.map((control: { value: string; rule: FormItem[] }) => {
|
||||
return {
|
||||
value: control.value,
|
||||
rule: control.rule.map((itemRule: FormItem) => {
|
||||
return convertItem(itemRule);
|
||||
}),
|
||||
};
|
||||
});
|
||||
ruleItem.control = controlItem;
|
||||
}
|
||||
return ruleItem;
|
||||
}
|
||||
}
|
||||
|
||||
function getControlFormItems() {
|
||||
const convertedData = formItems.value.map((item: FormItem) => convertItem(item));
|
||||
formRuleList.value = convertedData;
|
||||
}
|
||||
|
||||
// 初始化表单值
|
||||
function initFormItem() {
|
||||
initCascadeItemsMaps();
|
||||
getControlFormItemsMaps();
|
||||
getFormCreateItem();
|
||||
getControlFormItems();
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
formItems.value = props.formRule;
|
||||
initFormItem();
|
||||
});
|
||||
|
||||
const option = {
|
||||
resetBtn: false, // 不展示默认配置的重置和提交
|
||||
submitBtn: false,
|
||||
on: false, // 取消绑定on事件
|
||||
form: {
|
||||
layout: 'vertical',
|
||||
labelAlign: 'left',
|
||||
},
|
||||
// 暂时默认
|
||||
row: {
|
||||
gutter: 0,
|
||||
},
|
||||
wrap: {
|
||||
'asterisk-position': 'end',
|
||||
'validate-trigger': ['change'],
|
||||
},
|
||||
};
|
||||
|
||||
watch(
|
||||
() => formRuleList.value,
|
||||
(val) => {
|
||||
if (val) emit('update:form-item', formRuleList.value);
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
formRuleList,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -54,9 +54,7 @@
|
|||
const params = ref<OptionsParams>();
|
||||
const pluginId = (sessionStorage.getItem('platformKey') as string) || 'jira';
|
||||
async function getLinksItem() {
|
||||
const { formKey } = attrs;
|
||||
const formRulesList = formCreateStore.formRuleMap.get(formKey as FormCreateKeyEnum[keyof FormCreateKeyEnum]);
|
||||
if (formRulesList && props.optionMethod) {
|
||||
if (props.optionMethod) {
|
||||
params.value = {
|
||||
pluginId,
|
||||
organizationId: organizationId.value,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { FieldRule } from '@arco-design/web-vue';
|
||||
|
||||
import { Rule } from '@form-create/arco-design';
|
||||
import { FormRule, Rule } from '@form-create/arco-design';
|
||||
|
||||
export type FormItemType =
|
||||
| 'INPUT'
|
||||
|
@ -19,6 +19,7 @@ export type FormItemType =
|
|||
| 'INT'
|
||||
| 'FLOAT'
|
||||
| 'NUMBER'
|
||||
| 'PassWord'
|
||||
| undefined;
|
||||
|
||||
// 表单选项
|
||||
|
@ -35,10 +36,25 @@ export interface PropsRecord {
|
|||
}
|
||||
|
||||
// 内置formCreateRule所有配置的项
|
||||
export type FormRuleItem = Rule & {
|
||||
export interface FormRuleItem {
|
||||
type: string; // 表单类型
|
||||
field: string; // 字段
|
||||
title: string; // label 表单标签
|
||||
value: string | string[] | number | number[]; // 目前的值
|
||||
effect: {
|
||||
required: boolean; // 是否必填
|
||||
};
|
||||
// 级联关联到某一个form上 可能存在多个级联
|
||||
options: {
|
||||
label: string;
|
||||
value: string;
|
||||
}[];
|
||||
link: string[];
|
||||
// 梳理表单所需要属性
|
||||
control: { value: string; rule: FormRuleItem[] };
|
||||
props: Record<string, any>;
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
// 表单配置项
|
||||
export interface FormItem {
|
||||
type: FormItemType;
|
||||
|
@ -54,16 +70,27 @@ export interface FormItem {
|
|||
options?: FormItemDefaultOptions[];
|
||||
required: boolean;
|
||||
validate?: FieldRule[];
|
||||
control?: {
|
||||
value: string;
|
||||
rule: FormItem[];
|
||||
}[];
|
||||
// 表单联动配置
|
||||
couplingConfig?: {
|
||||
// 联动类型,visible:显示隐藏,disabled:禁用启用,filterOptions:过滤选项,disabledOptions:禁用选项,initOptions:初始化选项。都由联动的表单项触发
|
||||
type?: 'initOptions'; // 目前初始化选项
|
||||
cascade?: string; // 联动表单项名称
|
||||
matchRule?: 'same' | 'includes' | 'excludes' | RegExp; // 联动匹配规则,same:值相同,includes:值包含,excludes:值不包含, RegExp:自定义匹配正则表达式 // 场景 目前只考虑等于情况
|
||||
[key: string]: any;
|
||||
};
|
||||
// 表单控制器
|
||||
displayConditions?: {
|
||||
field: string;
|
||||
value: any;
|
||||
};
|
||||
// 表单布局
|
||||
wrap?: Record<string, any>;
|
||||
props?: Record<string, any>;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface FomItemSelect extends FormItemComplexCommonConfig {
|
||||
|
|
|
@ -103,10 +103,11 @@
|
|||
<MsFormCreate
|
||||
v-if="formRules.length"
|
||||
ref="formCreateRef"
|
||||
v-model:form-item="formItem"
|
||||
v-model:api="fApi"
|
||||
:form-rule="formRules"
|
||||
class="w-full"
|
||||
:option="options"
|
||||
:form-rule="formRules"
|
||||
:form-create-key="FormCreateKeyEnum.CASE_CUSTOM_ATTRS_DETAIL"
|
||||
/>
|
||||
<!-- 自定义字段结束 -->
|
||||
<div class="baseItem">
|
||||
|
@ -133,8 +134,8 @@
|
|||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
||||
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
||||
|
@ -278,6 +279,7 @@
|
|||
}
|
||||
|
||||
const formRules = ref<FormItem[]>([]);
|
||||
const formItem = ref<FormRuleItem[]>([]);
|
||||
|
||||
const isDisabled = ref<boolean>(false);
|
||||
|
||||
|
@ -307,6 +309,7 @@
|
|||
},
|
||||
};
|
||||
|
||||
const fApi = ref(null);
|
||||
// 初始化表单
|
||||
function initForm() {
|
||||
formRules.value = customFields.value.map((item: any) => {
|
||||
|
|
|
@ -42,13 +42,7 @@
|
|||
/>
|
||||
</a-form-item>
|
||||
|
||||
<MsFormCreate
|
||||
v-if="formRules.length && form.selectedAttrsId !== 'systemTags'"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
:form-rule="formRules"
|
||||
:form-create-key="FormCreateKeyEnum.CASE_CUSTOM_ATTRS"
|
||||
/>
|
||||
<MsFormCreate ref="formCreateRef" v-model:api="fApi" v-model:form-item="formItem" :form-rule="formRules" />
|
||||
</a-form>
|
||||
</div>
|
||||
</MsDialog>
|
||||
|
@ -59,23 +53,20 @@
|
|||
import { FormInstance } from '@arco-design/web-vue';
|
||||
|
||||
import MsDialog from '@/components/pure/ms-dialog/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import type { BatchActionQueryParams } from '@/components/pure/ms-table/type';
|
||||
|
||||
import { batchEditAttrs, getCaseDefaultFields } from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useFormCreateStore from '@/store/modules/form-create/form-create';
|
||||
|
||||
import type { BatchEditCaseType, CustomAttributes } from '@/models/caseManagement/featureCase';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
import Message from '@arco-design/web-vue/es/message';
|
||||
|
||||
const isVisible = ref<boolean>(false);
|
||||
const appStore = useAppStore();
|
||||
const formCreateStore = useFormCreateStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -127,34 +118,34 @@
|
|||
}
|
||||
|
||||
const formRules = ref<FormItem[]>([{ ...initDefaultForm }]);
|
||||
|
||||
const formItem = ref<FormRuleItem[]>([]);
|
||||
|
||||
const fApi = ref<any>({});
|
||||
const formCreateValue = computed(() => formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.CASE_CUSTOM_ATTRS));
|
||||
|
||||
const updateType = computed(() => {
|
||||
return totalAttrs.value.find((item: any) => item.fieldId === form.value.selectedAttrsId)?.type;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => updateType.value,
|
||||
(val) => {
|
||||
const currentAttrs = totalAttrs.value.filter((item: any) => item.fieldId === form.value.selectedAttrsId);
|
||||
if (val) {
|
||||
formRules.value = currentAttrs.map((item: CustomAttributes) => {
|
||||
return {
|
||||
type: val,
|
||||
name: item.fieldId,
|
||||
label: 'caseManagement.featureCase.batchUpdate',
|
||||
value: item.defaultValue,
|
||||
formRules.value = [];
|
||||
formRules.value = currentAttrs.map((item: CustomAttributes) => {
|
||||
return {
|
||||
type: val,
|
||||
name: item.fieldId,
|
||||
label: 'caseManagement.featureCase.batchUpdate',
|
||||
value: item.defaultValue,
|
||||
options: item.options,
|
||||
props: {
|
||||
modelValue: item.defaultValue,
|
||||
options: item.options,
|
||||
props: {
|
||||
modelValue: item.defaultValue,
|
||||
options: item.options,
|
||||
disabled: !form.value.selectedAttrsId,
|
||||
},
|
||||
required: item.required,
|
||||
};
|
||||
}) as FormItem[];
|
||||
}
|
||||
disabled: !form.value.selectedAttrsId,
|
||||
},
|
||||
required: item.required,
|
||||
};
|
||||
}) as FormItem[];
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -173,7 +164,7 @@
|
|||
fieldId: '',
|
||||
value: '',
|
||||
};
|
||||
formCreateValue.value?.forEach((item: any) => {
|
||||
formItem.value?.forEach((item: any) => {
|
||||
customField.fieldId = item.field;
|
||||
customField.value = JSON.stringify(item.value);
|
||||
});
|
||||
|
|
|
@ -83,10 +83,10 @@
|
|||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<div ref="wrapperRef" class="h-full bg-white">
|
||||
<div ref="wrapperRef" class="wrapperRef bg-white">
|
||||
<MsSplitBox ref="wrapperRef" expand-direction="right" :max="0.7" :min="0.7" :size="900">
|
||||
<template #first>
|
||||
<div class="leftWrapper h-full">
|
||||
<div class="leftWrapper">
|
||||
<div class="header h-[50px]">
|
||||
<a-menu mode="horizontal" :default-selected-keys="[activeTab]" @menu-item-click="clickMenu">
|
||||
<a-menu-item key="detail">{{ t('caseManagement.featureCase.detail') }} </a-menu-item>
|
||||
|
@ -106,23 +106,24 @@
|
|||
}}</span></a-menu-item
|
||||
>
|
||||
</a-menu>
|
||||
<div class="mt-4">
|
||||
<TabDetail
|
||||
v-if="activeTab === 'detail'"
|
||||
ref="tabDetailRef"
|
||||
:form="detailInfo"
|
||||
:allow-edit="true"
|
||||
@update-success="updateSuccess"
|
||||
/>
|
||||
<TabDemand v-else-if="activeTab === 'requirement'" :case-id="props.detailId" />
|
||||
<TabCaseTable v-else-if="activeTab === 'case'" />
|
||||
<TabDefect v-else-if="activeTab === 'bug'" />
|
||||
<TabDependency v-else-if="activeTab === 'dependency'" />
|
||||
<TabCaseReview v-else-if="activeTab === 'caseReview'" :case-id="props.detailId" />
|
||||
<TabTestPlan v-else-if="activeTab === 'testPlan'" />
|
||||
<TabComment v-else-if="activeTab === 'comments'" :case-id="props.detailId" />
|
||||
<TabChangeHistory v-else-if="activeTab === 'changeHistory'" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="leftContent mt-4 px-4">
|
||||
<TabDetail
|
||||
v-if="activeTab === 'detail'"
|
||||
ref="tabDetailRef"
|
||||
:form="detailInfo"
|
||||
:allow-edit="true"
|
||||
:form-rules="formItem"
|
||||
@update-success="updateSuccess"
|
||||
/>
|
||||
<TabDemand v-else-if="activeTab === 'requirement'" :case-id="props.detailId" />
|
||||
<TabCaseTable v-else-if="activeTab === 'case'" />
|
||||
<TabDefect v-else-if="activeTab === 'bug'" />
|
||||
<TabDependency v-else-if="activeTab === 'dependency'" />
|
||||
<TabCaseReview v-else-if="activeTab === 'caseReview'" :case-id="props.detailId" />
|
||||
<TabTestPlan v-else-if="activeTab === 'testPlan'" />
|
||||
<TabComment v-else-if="activeTab === 'comments'" :case-id="props.detailId" />
|
||||
<TabChangeHistory v-else-if="activeTab === 'changeHistory'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -155,10 +156,11 @@
|
|||
<MsFormCreate
|
||||
v-if="formRules.length"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
v-model:form-item="formItem"
|
||||
:form-rule="formRules"
|
||||
class="w-full"
|
||||
:option="options"
|
||||
:form-rule="formRules"
|
||||
:form-create-key="FormCreateKeyEnum.CASE_CUSTOM_ATTRS_DETAIL"
|
||||
/>
|
||||
<!-- 自定义字段结束 -->
|
||||
<div class="baseItem">
|
||||
|
@ -173,7 +175,7 @@
|
|||
</template>
|
||||
</MsSplitBox>
|
||||
</div>
|
||||
<!-- <inputComment :content="content" is-show-avatar is-use-bottom @publish="publishHandler" /> -->
|
||||
<inputComment :content="content" is-show-avatar is-use-bottom @publish="publishHandler" />
|
||||
</template>
|
||||
</MsDetailDrawer>
|
||||
<SettingDrawer v-model:visible="showSettingDrawer" />
|
||||
|
@ -187,8 +189,8 @@
|
|||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
||||
import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||
|
@ -206,7 +208,12 @@
|
|||
import TabDetail from './tabContent/tabDetail.vue';
|
||||
import TabTestPlan from './tabContent/tabTestPlan.vue';
|
||||
|
||||
import { deleteCaseRequest, followerCaseRequest, getCaseDetail } from '@/api/modules/case-management/featureCase';
|
||||
import {
|
||||
CreateCommentList,
|
||||
deleteCaseRequest,
|
||||
followerCaseRequest,
|
||||
getCaseDetail,
|
||||
} from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import { useAppStore } from '@/store';
|
||||
|
@ -214,14 +221,7 @@
|
|||
import useUserStore from '@/store/modules/user';
|
||||
import { characterLimit, findNodeByKey } from '@/utils';
|
||||
|
||||
import type {
|
||||
CaseManagementTable,
|
||||
CreateOrUpdateCase,
|
||||
CustomAttributes,
|
||||
DetailCase,
|
||||
TabItemType,
|
||||
} from '@/models/caseManagement/featureCase';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
import type { CustomAttributes, DetailCase, TabItemType } from '@/models/caseManagement/featureCase';
|
||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
import { LabelValue } from '@arco-design/web-vue/es/tree-select/interface';
|
||||
|
@ -386,6 +386,7 @@
|
|||
}
|
||||
|
||||
const formRules = ref<FormItem[]>([]);
|
||||
const formItem = ref<FormRuleItem[]>([]);
|
||||
|
||||
const isDisabled = ref<boolean>(false);
|
||||
|
||||
|
@ -415,6 +416,7 @@
|
|||
},
|
||||
};
|
||||
|
||||
const fApi = ref(null);
|
||||
// 初始化表单
|
||||
function initForm() {
|
||||
formRules.value = customFields.value.map((item: any) => {
|
||||
|
@ -472,10 +474,27 @@
|
|||
|
||||
const content = ref('');
|
||||
|
||||
function publishHandler() {}
|
||||
async function publishHandler(currentContent: string) {
|
||||
try {
|
||||
const params = {
|
||||
caseId: detailInfo.value.id,
|
||||
notifier: '',
|
||||
replyUser: '',
|
||||
parentId: '',
|
||||
content: currentContent,
|
||||
event: 'COMMENT', // 任务事件(仅评论: ’COMMENT‘; 评论并@: ’AT‘; 回复评论/回复并@: ’REPLAY‘;)
|
||||
};
|
||||
await CreateCommentList(params);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.wrapperRef {
|
||||
height: calc(100% - 78px);
|
||||
}
|
||||
:deep(.arco-menu-light) {
|
||||
height: 50px;
|
||||
background: none !important;
|
||||
|
|
|
@ -216,8 +216,8 @@
|
|||
v-if="formRules.length"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
v-model:form-item="formItem"
|
||||
:form-rule="formRules"
|
||||
:form-create-key="FormCreateKeyEnum.CASE_MANAGEMENT_FIELD"
|
||||
/>
|
||||
<a-form-item field="tags" :label="t('system.orgTemplate.tags')">
|
||||
<a-input-tag v-model="form.tags" :placeholder="t('formCreate.PleaseEnter')" allow-clear />
|
||||
|
@ -258,8 +258,8 @@
|
|||
import { FormInstance, Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||
|
@ -283,7 +283,6 @@
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||
import useFormCreateStore from '@/store/modules/form-create/form-create';
|
||||
import { downloadByteFile, getGenerateId } from '@/utils';
|
||||
|
||||
import type {
|
||||
|
@ -294,7 +293,6 @@
|
|||
StepList,
|
||||
} from '@/models/caseManagement/featureCase';
|
||||
import type { CustomField, DefinedFieldItem } from '@/models/setting/template';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
import { convertToFile } from './utils';
|
||||
import {
|
||||
|
@ -305,7 +303,6 @@
|
|||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const appStore = useAppStore();
|
||||
const formCreateStore = useFormCreateStore();
|
||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -648,8 +645,8 @@
|
|||
const rowLength = ref<number>(0);
|
||||
const formRuleField = ref<FormItem[][]>([]);
|
||||
const formRules = ref<FormItem[]>([]);
|
||||
const fApi = ref<any>({});
|
||||
const formRuleList = computed(() => formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.CASE_MANAGEMENT_FIELD));
|
||||
const formItem = ref<FormRuleItem[]>([]);
|
||||
const fApi = ref<any>(null);
|
||||
|
||||
// 处理表单格式
|
||||
const getFormRules = () => {
|
||||
|
@ -688,13 +685,15 @@
|
|||
|
||||
// 监视表单右侧自定义字段改变收集自定义字段参数
|
||||
watch(
|
||||
() => formRuleList.value,
|
||||
() => {
|
||||
const customFieldsMaps: Record<string, any> = {};
|
||||
formRuleList.value?.forEach((item) => {
|
||||
customFieldsMaps[item.field as string] = item.value;
|
||||
});
|
||||
form.value.customFields = customFieldsMaps;
|
||||
() => formItem.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
const customFieldsMaps: Record<string, any> = {};
|
||||
formItem.value?.forEach((item: any) => {
|
||||
customFieldsMaps[item.field as string] = item.value;
|
||||
});
|
||||
form.value.customFields = customFieldsMaps;
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
|
|
@ -222,6 +222,7 @@
|
|||
import { FormInstance, Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import type { FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
||||
import type { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||
|
@ -243,18 +244,14 @@
|
|||
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useFormCreateStore from '@/store/modules/form-create/form-create';
|
||||
import { downloadByteFile, getGenerateId } from '@/utils';
|
||||
import { scrollIntoView } from '@/utils/dom';
|
||||
|
||||
import type { AssociatedList, DetailCase, StepList } from '@/models/caseManagement/featureCase';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
import { convertToFile } from '../utils';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
|
||||
const formCreateStore = useFormCreateStore();
|
||||
|
||||
const caseFormRef = ref<FormInstance>();
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
@ -266,6 +263,7 @@
|
|||
defineProps<{
|
||||
form: DetailCase;
|
||||
allowEdit?: boolean; // 是否允许编辑
|
||||
formRules?: FormRuleItem[]; // 编辑表单
|
||||
}>(),
|
||||
{
|
||||
allowEdit: true, // 是否允许编辑
|
||||
|
@ -383,10 +381,6 @@
|
|||
);
|
||||
});
|
||||
|
||||
const formRuleList = computed(() =>
|
||||
formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.CASE_CUSTOM_ATTRS_DETAIL)
|
||||
);
|
||||
|
||||
// 处理编辑详情参数
|
||||
function getParams() {
|
||||
const steps = stepData.value.map((item, index) => {
|
||||
|
@ -398,7 +392,7 @@
|
|||
});
|
||||
|
||||
const customFieldsMaps: Record<string, any> = {};
|
||||
formRuleList.value?.forEach((item: any) => {
|
||||
props.formRules?.forEach((item: any) => {
|
||||
customFieldsMaps[item.field as string] = item.value;
|
||||
});
|
||||
|
||||
|
@ -566,7 +560,7 @@
|
|||
// 单独更新字段
|
||||
const updateCustomFields = debounce(() => {
|
||||
const customFieldsMaps: Record<string, any> = {};
|
||||
formRuleList.value?.forEach((item: any) => {
|
||||
props.formRules?.forEach((item: any) => {
|
||||
customFieldsMaps[item.field as string] = item.value;
|
||||
});
|
||||
detailForm.value.customFields = customFieldsMaps as Record<string, any>;
|
||||
|
@ -574,14 +568,16 @@
|
|||
|
||||
// 监视收集自定义字段参数
|
||||
watch(
|
||||
() => formRuleList.value,
|
||||
() => {
|
||||
const customFieldsValues = props.form.customFields.map((item: any) => JSON.parse(item.defaultValue));
|
||||
// 如果和起始值不一致更新某个字段
|
||||
const isChange = formRuleList.value?.every((item: any) => customFieldsValues.includes(item.value));
|
||||
if (!isChange) {
|
||||
updateCustomFields();
|
||||
handleOK();
|
||||
() => props.formRules,
|
||||
(val) => {
|
||||
if (val) {
|
||||
const customFieldsValues = props.form.customFields.map((item: any) => JSON.parse(item.defaultValue));
|
||||
// 如果和起始值不一致更新某个字段
|
||||
const isChange = val?.every((item: any) => customFieldsValues.includes(item.value));
|
||||
if (!isChange) {
|
||||
updateCustomFields();
|
||||
handleOK();
|
||||
}
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
|
|
|
@ -198,6 +198,7 @@
|
|||
tableKey: TableKeyEnum.PROJECT_MEMBER,
|
||||
selectable: true,
|
||||
showSetting: true,
|
||||
heightUsed: 288,
|
||||
columns,
|
||||
scroll: {
|
||||
x: 1200,
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<MsFormCreate
|
||||
v-if="platformRules && platformRules.length"
|
||||
v-model:api="fApi"
|
||||
v-model:form-item="platformItem"
|
||||
:form-rule="platformRules"
|
||||
:form-create-key="FormCreateKeyEnum.PROJECT_DEFECT_SYNC_TEMPLATE"
|
||||
/>
|
||||
<!-- 同步机制 -->
|
||||
<a-form-item field="MECHANISM" :label="t('project.menu.syncMechanism')">
|
||||
|
@ -106,8 +106,8 @@
|
|||
import { FormInstance, Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
|
||||
import {
|
||||
getPlatformInfo,
|
||||
|
@ -119,7 +119,6 @@
|
|||
|
||||
import { PoolOption, SelectValue } from '@/models/projectManagement/menuManagement';
|
||||
import { MenuEnum } from '@/enums/commonEnum';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
|
@ -142,6 +141,7 @@
|
|||
|
||||
const formRef = ref<FormInstance>();
|
||||
const platformRules = ref<FormItem[]>([]);
|
||||
const platformItem = ref<FormRuleItem[]>([]);
|
||||
|
||||
const form = reactive({
|
||||
PLATFORM_KEY: '',
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<MsFormCreate
|
||||
v-if="platformRules && platformRules.length"
|
||||
v-model:api="fApi"
|
||||
v-model:form-item="platformItem"
|
||||
:form-rule="platformRules"
|
||||
:form-create-key="FormCreateKeyEnum.PROJECT_DEFECT_SYNC_TEMPLATE"
|
||||
/>
|
||||
</a-form>
|
||||
<template v-if="platformOption.length" #footerLeft>
|
||||
|
@ -63,8 +63,8 @@
|
|||
import { FormInstance, Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue';
|
||||
import type { FormItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
|
||||
import {
|
||||
getPlatformInfo,
|
||||
|
@ -76,7 +76,6 @@
|
|||
|
||||
import { PoolOption, SelectValue } from '@/models/projectManagement/menuManagement';
|
||||
import { MenuEnum } from '@/enums/commonEnum';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
|
@ -94,6 +93,7 @@
|
|||
|
||||
const formRef = ref<FormInstance>();
|
||||
const platformRules = ref<FormItem[]>([]);
|
||||
const platformItem = ref<FormRuleItem[]>([]);
|
||||
|
||||
const form = reactive({
|
||||
PLATFORM_KEY: '',
|
||||
|
|
|
@ -224,6 +224,7 @@
|
|||
tableKey: TableKeyEnum.ORGANIZATION_MEMBER,
|
||||
scroll: { x: 1800 },
|
||||
selectable: true,
|
||||
heightUsed: 288,
|
||||
showSetting: true,
|
||||
size: 'default',
|
||||
});
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
<MsFormCreate
|
||||
v-if="formRules.length"
|
||||
ref="formCreateRef"
|
||||
v-model:api="fApi"
|
||||
v-model:form-item="formItem"
|
||||
:form-rule="formRules"
|
||||
:form-create-key="FormCreateKeyEnum.ORGANIZE_TEMPLATE_PREVIEW_TEMPLATE"
|
||||
/>
|
||||
<a-empty v-else />
|
||||
</div>
|
||||
|
@ -22,13 +23,12 @@
|
|||
*/
|
||||
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 MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import CaseTemplateLeftContent from './caseTemplateLeftContent.vue';
|
||||
import DefectTemplateLeftContent from './defectTemplateLeftContent.vue';
|
||||
|
||||
import type { DefinedFieldItem, SeneType } from '@/models/setting/template';
|
||||
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
|
||||
|
||||
const props = defineProps<{
|
||||
templateType: SeneType; // 模板场景
|
||||
|
@ -38,6 +38,8 @@
|
|||
|
||||
const formRuleField = ref<FormItem[][]>([]);
|
||||
const formRules = ref<FormItem[]>([]);
|
||||
const formItem = ref<FormRuleItem[]>([]);
|
||||
const fApi = ref(null);
|
||||
const formCreateRef = ref();
|
||||
|
||||
// 处理表单格式
|
||||
|
|
Loading…
Reference in New Issue