feat(公共): 重构扩展formCreate控制器功能和修改相关

This commit is contained in:
xinxin.wu 2023-12-22 17:59:11 +08:00 committed by Craftsman
parent a1c76847aa
commit f6eeb1150e
15 changed files with 439 additions and 121 deletions

View File

@ -13,7 +13,7 @@
<MsRichText v-model="currentContent" class="w-full" /> <MsRichText v-model="currentContent" class="w-full" />
<div class="mt-4 flex flex-row justify-end gap-[12px]"> <div class="mt-4 flex flex-row justify-end gap-[12px]">
<a-button @click="cancelClick">{{ t('common.cancel') }}</a-button> <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> </div>
</div> </div>

View File

@ -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> = { export const FieldTypeFormRules: Record<string, FormRule> = {
INPUT, INPUT,
SELECT, SELECT,
@ -178,4 +189,5 @@ export const FieldTypeFormRules: Record<string, FormRule> = {
MULTIPLE_INPUT, MULTIPLE_INPUT,
TEXTAREA, TEXTAREA,
JIRAKEY, JIRAKEY,
PASSWORD,
}; };

View File

@ -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 keyname 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;
// formform-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,
};
// namelink
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>

View File

@ -54,9 +54,7 @@
const params = ref<OptionsParams>(); const params = ref<OptionsParams>();
const pluginId = (sessionStorage.getItem('platformKey') as string) || 'jira'; const pluginId = (sessionStorage.getItem('platformKey') as string) || 'jira';
async function getLinksItem() { async function getLinksItem() {
const { formKey } = attrs; if (props.optionMethod) {
const formRulesList = formCreateStore.formRuleMap.get(formKey as FormCreateKeyEnum[keyof FormCreateKeyEnum]);
if (formRulesList && props.optionMethod) {
params.value = { params.value = {
pluginId, pluginId,
organizationId: organizationId.value, organizationId: organizationId.value,

View File

@ -1,6 +1,6 @@
import { FieldRule } from '@arco-design/web-vue'; 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 = export type FormItemType =
| 'INPUT' | 'INPUT'
@ -19,6 +19,7 @@ export type FormItemType =
| 'INT' | 'INT'
| 'FLOAT' | 'FLOAT'
| 'NUMBER' | 'NUMBER'
| 'PassWord'
| undefined; | undefined;
// 表单选项 // 表单选项
@ -35,10 +36,25 @@ export interface PropsRecord {
} }
// 内置formCreateRule所有配置的项 // 内置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>; props: Record<string, any>;
[key: string]: any; [key: string]: any;
}; }
// 表单配置项 // 表单配置项
export interface FormItem { export interface FormItem {
type: FormItemType; type: FormItemType;
@ -54,16 +70,27 @@ export interface FormItem {
options?: FormItemDefaultOptions[]; options?: FormItemDefaultOptions[];
required: boolean; required: boolean;
validate?: FieldRule[]; validate?: FieldRule[];
control?: {
value: string;
rule: FormItem[];
}[];
// 表单联动配置 // 表单联动配置
couplingConfig?: { couplingConfig?: {
// 联动类型visible显示隐藏disabled禁用启用filterOptions过滤选项disabledOptions禁用选项initOptions初始化选项。都由联动的表单项触发 // 联动类型visible显示隐藏disabled禁用启用filterOptions过滤选项disabledOptions禁用选项initOptions初始化选项。都由联动的表单项触发
type?: 'initOptions'; // 目前初始化选项 type?: 'initOptions'; // 目前初始化选项
cascade?: string; // 联动表单项名称 cascade?: string; // 联动表单项名称
matchRule?: 'same' | 'includes' | 'excludes' | RegExp; // 联动匹配规则same值相同includes值包含excludes值不包含 RegExp自定义匹配正则表达式 // 场景 目前只考虑等于情况 matchRule?: 'same' | 'includes' | 'excludes' | RegExp; // 联动匹配规则same值相同includes值包含excludes值不包含 RegExp自定义匹配正则表达式 // 场景 目前只考虑等于情况
[key: string]: any;
};
// 表单控制器
displayConditions?: {
field: string;
value: any;
}; };
// 表单布局 // 表单布局
wrap?: Record<string, any>; wrap?: Record<string, any>;
props?: Record<string, any>; props?: Record<string, any>;
[key: string]: any;
} }
interface FomItemSelect extends FormItemComplexCommonConfig { interface FomItemSelect extends FormItemComplexCommonConfig {

View File

@ -103,10 +103,11 @@
<MsFormCreate <MsFormCreate
v-if="formRules.length" v-if="formRules.length"
ref="formCreateRef" ref="formCreateRef"
v-model:form-item="formItem"
v-model:api="fApi"
:form-rule="formRules"
class="w-full" class="w-full"
:option="options" :option="options"
:form-rule="formRules"
:form-create-key="FormCreateKeyEnum.CASE_CUSTOM_ATTRS_DETAIL"
/> />
<!-- 自定义字段结束 --> <!-- 自定义字段结束 -->
<div class="baseItem"> <div class="baseItem">
@ -133,8 +134,8 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue'; import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
import type { FormItem } from '@/components/pure/ms-form-create/types'; import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue'; import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import type { MsPaginationI } from '@/components/pure/ms-table/type'; import type { MsPaginationI } from '@/components/pure/ms-table/type';
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue'; import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
@ -278,6 +279,7 @@
} }
const formRules = ref<FormItem[]>([]); const formRules = ref<FormItem[]>([]);
const formItem = ref<FormRuleItem[]>([]);
const isDisabled = ref<boolean>(false); const isDisabled = ref<boolean>(false);
@ -307,6 +309,7 @@
}, },
}; };
const fApi = ref(null);
// //
function initForm() { function initForm() {
formRules.value = customFields.value.map((item: any) => { formRules.value = customFields.value.map((item: any) => {

View File

@ -42,13 +42,7 @@
/> />
</a-form-item> </a-form-item>
<MsFormCreate <MsFormCreate ref="formCreateRef" v-model:api="fApi" v-model:form-item="formItem" :form-rule="formRules" />
v-if="formRules.length && form.selectedAttrsId !== 'systemTags'"
ref="formCreateRef"
v-model:api="fApi"
:form-rule="formRules"
:form-create-key="FormCreateKeyEnum.CASE_CUSTOM_ATTRS"
/>
</a-form> </a-form>
</div> </div>
</MsDialog> </MsDialog>
@ -59,23 +53,20 @@
import { FormInstance } from '@arco-design/web-vue'; import { FormInstance } from '@arco-design/web-vue';
import MsDialog from '@/components/pure/ms-dialog/index.vue'; import MsDialog from '@/components/pure/ms-dialog/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue'; import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
import type { FormItem } from '@/components/pure/ms-form-create/types'; import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
import type { BatchActionQueryParams } from '@/components/pure/ms-table/type'; import type { BatchActionQueryParams } from '@/components/pure/ms-table/type';
import { batchEditAttrs, getCaseDefaultFields } from '@/api/modules/case-management/featureCase'; import { batchEditAttrs, getCaseDefaultFields } from '@/api/modules/case-management/featureCase';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useFormCreateStore from '@/store/modules/form-create/form-create';
import type { BatchEditCaseType, CustomAttributes } from '@/models/caseManagement/featureCase'; import type { BatchEditCaseType, CustomAttributes } from '@/models/caseManagement/featureCase';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
import Message from '@arco-design/web-vue/es/message'; import Message from '@arco-design/web-vue/es/message';
const isVisible = ref<boolean>(false); const isVisible = ref<boolean>(false);
const appStore = useAppStore(); const appStore = useAppStore();
const formCreateStore = useFormCreateStore();
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps<{ const props = defineProps<{
@ -127,34 +118,34 @@
} }
const formRules = ref<FormItem[]>([{ ...initDefaultForm }]); const formRules = ref<FormItem[]>([{ ...initDefaultForm }]);
const formItem = ref<FormRuleItem[]>([]);
const fApi = ref<any>({}); const fApi = ref<any>({});
const formCreateValue = computed(() => formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.CASE_CUSTOM_ATTRS));
const updateType = computed(() => { const updateType = computed(() => {
return totalAttrs.value.find((item: any) => item.fieldId === form.value.selectedAttrsId)?.type; return totalAttrs.value.find((item: any) => item.fieldId === form.value.selectedAttrsId)?.type;
}); });
watch( watch(
() => updateType.value, () => updateType.value,
(val) => { (val) => {
const currentAttrs = totalAttrs.value.filter((item: any) => item.fieldId === form.value.selectedAttrsId); const currentAttrs = totalAttrs.value.filter((item: any) => item.fieldId === form.value.selectedAttrsId);
if (val) { formRules.value = [];
formRules.value = currentAttrs.map((item: CustomAttributes) => { formRules.value = currentAttrs.map((item: CustomAttributes) => {
return { return {
type: val, type: val,
name: item.fieldId, name: item.fieldId,
label: 'caseManagement.featureCase.batchUpdate', label: 'caseManagement.featureCase.batchUpdate',
value: item.defaultValue, value: item.defaultValue,
options: item.options,
props: {
modelValue: item.defaultValue,
options: item.options, options: item.options,
props: { disabled: !form.value.selectedAttrsId,
modelValue: item.defaultValue, },
options: item.options, required: item.required,
disabled: !form.value.selectedAttrsId, };
}, }) as FormItem[];
required: item.required,
};
}) as FormItem[];
}
} }
); );
@ -173,7 +164,7 @@
fieldId: '', fieldId: '',
value: '', value: '',
}; };
formCreateValue.value?.forEach((item: any) => { formItem.value?.forEach((item: any) => {
customField.fieldId = item.field; customField.fieldId = item.field;
customField.value = JSON.stringify(item.value); customField.value = JSON.stringify(item.value);
}); });

View File

@ -83,10 +83,10 @@
</div> </div>
</template> </template>
<template #default> <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"> <MsSplitBox ref="wrapperRef" expand-direction="right" :max="0.7" :min="0.7" :size="900">
<template #first> <template #first>
<div class="leftWrapper h-full"> <div class="leftWrapper">
<div class="header h-[50px]"> <div class="header h-[50px]">
<a-menu mode="horizontal" :default-selected-keys="[activeTab]" @menu-item-click="clickMenu"> <a-menu mode="horizontal" :default-selected-keys="[activeTab]" @menu-item-click="clickMenu">
<a-menu-item key="detail">{{ t('caseManagement.featureCase.detail') }} </a-menu-item> <a-menu-item key="detail">{{ t('caseManagement.featureCase.detail') }} </a-menu-item>
@ -106,23 +106,24 @@
}}</span></a-menu-item }}</span></a-menu-item
> >
</a-menu> </a-menu>
<div class="mt-4"> </div>
<TabDetail <div class="leftContent mt-4 px-4">
v-if="activeTab === 'detail'" <TabDetail
ref="tabDetailRef" v-if="activeTab === 'detail'"
:form="detailInfo" ref="tabDetailRef"
:allow-edit="true" :form="detailInfo"
@update-success="updateSuccess" :allow-edit="true"
/> :form-rules="formItem"
<TabDemand v-else-if="activeTab === 'requirement'" :case-id="props.detailId" /> @update-success="updateSuccess"
<TabCaseTable v-else-if="activeTab === 'case'" /> />
<TabDefect v-else-if="activeTab === 'bug'" /> <TabDemand v-else-if="activeTab === 'requirement'" :case-id="props.detailId" />
<TabDependency v-else-if="activeTab === 'dependency'" /> <TabCaseTable v-else-if="activeTab === 'case'" />
<TabCaseReview v-else-if="activeTab === 'caseReview'" :case-id="props.detailId" /> <TabDefect v-else-if="activeTab === 'bug'" />
<TabTestPlan v-else-if="activeTab === 'testPlan'" /> <TabDependency v-else-if="activeTab === 'dependency'" />
<TabComment v-else-if="activeTab === 'comments'" :case-id="props.detailId" /> <TabCaseReview v-else-if="activeTab === 'caseReview'" :case-id="props.detailId" />
<TabChangeHistory v-else-if="activeTab === 'changeHistory'" /> <TabTestPlan v-else-if="activeTab === 'testPlan'" />
</div> <TabComment v-else-if="activeTab === 'comments'" :case-id="props.detailId" />
<TabChangeHistory v-else-if="activeTab === 'changeHistory'" />
</div> </div>
</div> </div>
</template> </template>
@ -155,10 +156,11 @@
<MsFormCreate <MsFormCreate
v-if="formRules.length" v-if="formRules.length"
ref="formCreateRef" ref="formCreateRef"
v-model:api="fApi"
v-model:form-item="formItem"
:form-rule="formRules"
class="w-full" class="w-full"
:option="options" :option="options"
:form-rule="formRules"
:form-create-key="FormCreateKeyEnum.CASE_CUSTOM_ATTRS_DETAIL"
/> />
<!-- 自定义字段结束 --> <!-- 自定义字段结束 -->
<div class="baseItem"> <div class="baseItem">
@ -173,7 +175,7 @@
</template> </template>
</MsSplitBox> </MsSplitBox>
</div> </div>
<!-- <inputComment :content="content" is-show-avatar is-use-bottom @publish="publishHandler" /> --> <inputComment :content="content" is-show-avatar is-use-bottom @publish="publishHandler" />
</template> </template>
</MsDetailDrawer> </MsDetailDrawer>
<SettingDrawer v-model:visible="showSettingDrawer" /> <SettingDrawer v-model:visible="showSettingDrawer" />
@ -187,8 +189,8 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue'; import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
import type { FormItem } from '@/components/pure/ms-form-create/types'; import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue'; import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import type { MsPaginationI } from '@/components/pure/ms-table/type'; import type { MsPaginationI } from '@/components/pure/ms-table/type';
import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue'; import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
@ -206,7 +208,12 @@
import TabDetail from './tabContent/tabDetail.vue'; import TabDetail from './tabContent/tabDetail.vue';
import TabTestPlan from './tabContent/tabTestPlan.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 { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
@ -214,14 +221,7 @@
import useUserStore from '@/store/modules/user'; import useUserStore from '@/store/modules/user';
import { characterLimit, findNodeByKey } from '@/utils'; import { characterLimit, findNodeByKey } from '@/utils';
import type { import type { CustomAttributes, DetailCase, TabItemType } from '@/models/caseManagement/featureCase';
CaseManagementTable,
CreateOrUpdateCase,
CustomAttributes,
DetailCase,
TabItemType,
} from '@/models/caseManagement/featureCase';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
import { CaseManagementRouteEnum } from '@/enums/routeEnum'; import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import { LabelValue } from '@arco-design/web-vue/es/tree-select/interface'; import { LabelValue } from '@arco-design/web-vue/es/tree-select/interface';
@ -386,6 +386,7 @@
} }
const formRules = ref<FormItem[]>([]); const formRules = ref<FormItem[]>([]);
const formItem = ref<FormRuleItem[]>([]);
const isDisabled = ref<boolean>(false); const isDisabled = ref<boolean>(false);
@ -415,6 +416,7 @@
}, },
}; };
const fApi = ref(null);
// //
function initForm() { function initForm() {
formRules.value = customFields.value.map((item: any) => { formRules.value = customFields.value.map((item: any) => {
@ -472,10 +474,27 @@
const content = ref(''); 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> </script>
<style scoped lang="less"> <style scoped lang="less">
.wrapperRef {
height: calc(100% - 78px);
}
:deep(.arco-menu-light) { :deep(.arco-menu-light) {
height: 50px; height: 50px;
background: none !important; background: none !important;

View File

@ -216,8 +216,8 @@
v-if="formRules.length" v-if="formRules.length"
ref="formCreateRef" ref="formCreateRef"
v-model:api="fApi" v-model:api="fApi"
v-model:form-item="formItem"
:form-rule="formRules" :form-rule="formRules"
:form-create-key="FormCreateKeyEnum.CASE_MANAGEMENT_FIELD"
/> />
<a-form-item field="tags" :label="t('system.orgTemplate.tags')"> <a-form-item field="tags" :label="t('system.orgTemplate.tags')">
<a-input-tag v-model="form.tags" :placeholder="t('formCreate.PleaseEnter')" allow-clear /> <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 { FormInstance, Message } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue'; import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
import type { FormItem } from '@/components/pure/ms-form-create/types'; import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue'; import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
import MsFileList from '@/components/pure/ms-upload/fileList.vue'; import MsFileList from '@/components/pure/ms-upload/fileList.vue';
import MsUpload from '@/components/pure/ms-upload/index.vue'; import MsUpload from '@/components/pure/ms-upload/index.vue';
@ -283,7 +283,6 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useFeatureCaseStore from '@/store/modules/case/featureCase'; import useFeatureCaseStore from '@/store/modules/case/featureCase';
import useFormCreateStore from '@/store/modules/form-create/form-create';
import { downloadByteFile, getGenerateId } from '@/utils'; import { downloadByteFile, getGenerateId } from '@/utils';
import type { import type {
@ -294,7 +293,6 @@
StepList, StepList,
} from '@/models/caseManagement/featureCase'; } from '@/models/caseManagement/featureCase';
import type { CustomField, DefinedFieldItem } from '@/models/setting/template'; import type { CustomField, DefinedFieldItem } from '@/models/setting/template';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
import { convertToFile } from './utils'; import { convertToFile } from './utils';
import { import {
@ -305,7 +303,6 @@
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const appStore = useAppStore(); const appStore = useAppStore();
const formCreateStore = useFormCreateStore();
const currentProjectId = computed(() => appStore.currentProjectId); const currentProjectId = computed(() => appStore.currentProjectId);
const props = defineProps<{ const props = defineProps<{
@ -648,8 +645,8 @@
const rowLength = ref<number>(0); const rowLength = ref<number>(0);
const formRuleField = ref<FormItem[][]>([]); const formRuleField = ref<FormItem[][]>([]);
const formRules = ref<FormItem[]>([]); const formRules = ref<FormItem[]>([]);
const fApi = ref<any>({}); const formItem = ref<FormRuleItem[]>([]);
const formRuleList = computed(() => formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.CASE_MANAGEMENT_FIELD)); const fApi = ref<any>(null);
// //
const getFormRules = () => { const getFormRules = () => {
@ -688,13 +685,15 @@
// //
watch( watch(
() => formRuleList.value, () => formItem.value,
() => { (val) => {
const customFieldsMaps: Record<string, any> = {}; if (val) {
formRuleList.value?.forEach((item) => { const customFieldsMaps: Record<string, any> = {};
customFieldsMaps[item.field as string] = item.value; formItem.value?.forEach((item: any) => {
}); customFieldsMaps[item.field as string] = item.value;
form.value.customFields = customFieldsMaps; });
form.value.customFields = customFieldsMaps;
}
}, },
{ deep: true } { deep: true }
); );

View File

@ -222,6 +222,7 @@
import { FormInstance, Message } from '@arco-design/web-vue'; import { FormInstance, Message } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.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 MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
import MsFileList from '@/components/pure/ms-upload/fileList.vue'; import MsFileList from '@/components/pure/ms-upload/fileList.vue';
import type { MsFileItem } from '@/components/pure/ms-upload/types'; import type { MsFileItem } from '@/components/pure/ms-upload/types';
@ -243,18 +244,14 @@
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement'; import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useFormCreateStore from '@/store/modules/form-create/form-create';
import { downloadByteFile, getGenerateId } from '@/utils'; import { downloadByteFile, getGenerateId } from '@/utils';
import { scrollIntoView } from '@/utils/dom'; import { scrollIntoView } from '@/utils/dom';
import type { AssociatedList, DetailCase, StepList } from '@/models/caseManagement/featureCase'; import type { AssociatedList, DetailCase, StepList } from '@/models/caseManagement/featureCase';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
import { convertToFile } from '../utils'; import { convertToFile } from '../utils';
import debounce from 'lodash-es/debounce'; import debounce from 'lodash-es/debounce';
const formCreateStore = useFormCreateStore();
const caseFormRef = ref<FormInstance>(); const caseFormRef = ref<FormInstance>();
const appStore = useAppStore(); const appStore = useAppStore();
@ -266,6 +263,7 @@
defineProps<{ defineProps<{
form: DetailCase; form: DetailCase;
allowEdit?: boolean; // allowEdit?: boolean; //
formRules?: FormRuleItem[]; //
}>(), }>(),
{ {
allowEdit: true, // allowEdit: true, //
@ -383,10 +381,6 @@
); );
}); });
const formRuleList = computed(() =>
formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.CASE_CUSTOM_ATTRS_DETAIL)
);
// //
function getParams() { function getParams() {
const steps = stepData.value.map((item, index) => { const steps = stepData.value.map((item, index) => {
@ -398,7 +392,7 @@
}); });
const customFieldsMaps: Record<string, any> = {}; const customFieldsMaps: Record<string, any> = {};
formRuleList.value?.forEach((item: any) => { props.formRules?.forEach((item: any) => {
customFieldsMaps[item.field as string] = item.value; customFieldsMaps[item.field as string] = item.value;
}); });
@ -566,7 +560,7 @@
// //
const updateCustomFields = debounce(() => { const updateCustomFields = debounce(() => {
const customFieldsMaps: Record<string, any> = {}; const customFieldsMaps: Record<string, any> = {};
formRuleList.value?.forEach((item: any) => { props.formRules?.forEach((item: any) => {
customFieldsMaps[item.field as string] = item.value; customFieldsMaps[item.field as string] = item.value;
}); });
detailForm.value.customFields = customFieldsMaps as Record<string, any>; detailForm.value.customFields = customFieldsMaps as Record<string, any>;
@ -574,14 +568,16 @@
// //
watch( watch(
() => formRuleList.value, () => props.formRules,
() => { (val) => {
const customFieldsValues = props.form.customFields.map((item: any) => JSON.parse(item.defaultValue)); if (val) {
// 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) { const isChange = val?.every((item: any) => customFieldsValues.includes(item.value));
updateCustomFields(); if (!isChange) {
handleOK(); updateCustomFields();
handleOK();
}
} }
}, },
{ deep: true } { deep: true }

View File

@ -198,6 +198,7 @@
tableKey: TableKeyEnum.PROJECT_MEMBER, tableKey: TableKeyEnum.PROJECT_MEMBER,
selectable: true, selectable: true,
showSetting: true, showSetting: true,
heightUsed: 288,
columns, columns,
scroll: { scroll: {
x: 1200, x: 1200,

View File

@ -30,8 +30,8 @@
<MsFormCreate <MsFormCreate
v-if="platformRules && platformRules.length" v-if="platformRules && platformRules.length"
v-model:api="fApi" v-model:api="fApi"
v-model:form-item="platformItem"
:form-rule="platformRules" :form-rule="platformRules"
:form-create-key="FormCreateKeyEnum.PROJECT_DEFECT_SYNC_TEMPLATE"
/> />
<!-- 同步机制 --> <!-- 同步机制 -->
<a-form-item field="MECHANISM" :label="t('project.menu.syncMechanism')"> <a-form-item field="MECHANISM" :label="t('project.menu.syncMechanism')">
@ -106,8 +106,8 @@
import { FormInstance, Message } from '@arco-design/web-vue'; import { FormInstance, Message } from '@arco-design/web-vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue'; import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue'; import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
import type { FormItem } from '@/components/pure/ms-form-create/types'; import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
import { import {
getPlatformInfo, getPlatformInfo,
@ -119,7 +119,6 @@
import { PoolOption, SelectValue } from '@/models/projectManagement/menuManagement'; import { PoolOption, SelectValue } from '@/models/projectManagement/menuManagement';
import { MenuEnum } from '@/enums/commonEnum'; import { MenuEnum } from '@/enums/commonEnum';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps<{ const props = defineProps<{
@ -142,6 +141,7 @@
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
const platformRules = ref<FormItem[]>([]); const platformRules = ref<FormItem[]>([]);
const platformItem = ref<FormRuleItem[]>([]);
const form = reactive({ const form = reactive({
PLATFORM_KEY: '', PLATFORM_KEY: '',

View File

@ -30,8 +30,8 @@
<MsFormCreate <MsFormCreate
v-if="platformRules && platformRules.length" v-if="platformRules && platformRules.length"
v-model:api="fApi" v-model:api="fApi"
v-model:form-item="platformItem"
:form-rule="platformRules" :form-rule="platformRules"
:form-create-key="FormCreateKeyEnum.PROJECT_DEFECT_SYNC_TEMPLATE"
/> />
</a-form> </a-form>
<template v-if="platformOption.length" #footerLeft> <template v-if="platformOption.length" #footerLeft>
@ -63,8 +63,8 @@
import { FormInstance, Message } from '@arco-design/web-vue'; import { FormInstance, Message } from '@arco-design/web-vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue'; import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue'; import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
import type { FormItem } from '@/components/pure/ms-form-create/types'; import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
import { import {
getPlatformInfo, getPlatformInfo,
@ -76,7 +76,6 @@
import { PoolOption, SelectValue } from '@/models/projectManagement/menuManagement'; import { PoolOption, SelectValue } from '@/models/projectManagement/menuManagement';
import { MenuEnum } from '@/enums/commonEnum'; import { MenuEnum } from '@/enums/commonEnum';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps<{ const props = defineProps<{
@ -94,6 +93,7 @@
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
const platformRules = ref<FormItem[]>([]); const platformRules = ref<FormItem[]>([]);
const platformItem = ref<FormRuleItem[]>([]);
const form = reactive({ const form = reactive({
PLATFORM_KEY: '', PLATFORM_KEY: '',

View File

@ -224,6 +224,7 @@
tableKey: TableKeyEnum.ORGANIZATION_MEMBER, tableKey: TableKeyEnum.ORGANIZATION_MEMBER,
scroll: { x: 1800 }, scroll: { x: 1800 },
selectable: true, selectable: true,
heightUsed: 288,
showSetting: true, showSetting: true,
size: 'default', size: 'default',
}); });

View File

@ -8,8 +8,9 @@
<MsFormCreate <MsFormCreate
v-if="formRules.length" v-if="formRules.length"
ref="formCreateRef" ref="formCreateRef"
v-model:api="fApi"
v-model:form-item="formItem"
:form-rule="formRules" :form-rule="formRules"
:form-create-key="FormCreateKeyEnum.ORGANIZE_TEMPLATE_PREVIEW_TEMPLATE"
/> />
<a-empty v-else /> <a-empty v-else />
</div> </div>
@ -22,13 +23,12 @@
*/ */
import { ref } from 'vue'; import { ref } from 'vue';
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue'; import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
import type { FormItem } from '@/components/pure/ms-form-create/types'; import type { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
import CaseTemplateLeftContent from './caseTemplateLeftContent.vue'; import CaseTemplateLeftContent from './caseTemplateLeftContent.vue';
import DefectTemplateLeftContent from './defectTemplateLeftContent.vue'; import DefectTemplateLeftContent from './defectTemplateLeftContent.vue';
import type { DefinedFieldItem, SeneType } from '@/models/setting/template'; import type { DefinedFieldItem, SeneType } from '@/models/setting/template';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
const props = defineProps<{ const props = defineProps<{
templateType: SeneType; // templateType: SeneType; //
@ -38,6 +38,8 @@
const formRuleField = ref<FormItem[][]>([]); const formRuleField = ref<FormItem[][]>([]);
const formRules = ref<FormItem[]>([]); const formRules = ref<FormItem[]>([]);
const formItem = ref<FormRuleItem[]>([]);
const fApi = ref(null);
const formCreateRef = ref(); const formCreateRef = ref();
// //