fix(公共): 调整公共组件和去掉多余未使用文件

This commit is contained in:
xinxin.wu 2023-12-25 15:58:01 +08:00 committed by rubylliu
parent 29dcd4d422
commit c0ade8e3aa
16 changed files with 74 additions and 1057 deletions

View File

@ -1,81 +0,0 @@
import { OPERATORS } from './operator';
import type { SearchKeyType } from './type';
// eslint-disable-next-line no-shadow
export enum CaseKeyEnum {
NAME = 'name',
UPDATE_TIME = 'updateTime',
MODULES = 'modules',
CREATE_TIME = 'createTime',
CREATOR = 'creator',
TAGS = 'tags',
REVIEW_RESULT = 'reviewResults',
FOLLOW_PEOPLE = 'followPeople',
ASSOCIATED_REQUIREMENTS = 'associated_requirements',
CASE_LEVEL = 'caseLevel',
CASE_STATUS = 'caseStatus',
PRINCIPAL = 'principal', // 责任人
}
// 名称
export const NAME: SearchKeyType = {
key: CaseKeyEnum.NAME, // 对应字段key
type: 'a-input', // Vue控件名称
label: '显示名称', // 显示名称
operator: {
value: OPERATORS.LIKE.value, // 如果未设置value初始值则value初始值为options[0]
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE], // 运算符选项
},
};
// 标签
export const TAGS: SearchKeyType = {
key: CaseKeyEnum.TAGS,
type: 'a-input',
label: '标签',
operator: {
value: OPERATORS.LIKE.value,
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE],
},
};
// 所属模块
export const MODULE: SearchKeyType = {
key: 'module',
type: 'a-tree-select',
label: '所属模块',
operator: {
value: OPERATORS.LIKE.value,
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE],
},
};
// 创建时间
export const CREATE_TIME: SearchKeyType = {
key: CaseKeyEnum.CREATE_TIME,
type: 'time-select', // 时间选择器
label: '创建时间',
rules: [{ required: true, message: '请选择创建时间!' }],
props: {},
operator: {
value: '',
options: [OPERATORS.BETWEEN, OPERATORS.GT, OPERATORS.LT],
},
};
// 更新时间
export const UPDATE_TIME: SearchKeyType = {
key: CaseKeyEnum.UPDATE_TIME,
type: 'time-select',
label: '更新时间',
rules: [{ required: true, message: '请选择更新时间!' }],
props: {},
operator: {
value: '',
options: [OPERATORS.BETWEEN, OPERATORS.GT, OPERATORS.LT],
},
};
// 功能用例所需要列表
export const TEST_PLAN_TEST_CASE = [NAME, TAGS, MODULE, CREATE_TIME, UPDATE_TIME];
export default {};

View File

@ -1,28 +0,0 @@
export default {
operators: {
is_empty: 'Is empty',
is_not_empty: 'Is not empty',
like: 'Contains',
not_like: 'Not included',
in: 'Belong to',
not_in: 'Not belonging',
gt: 'Greater than',
ge: 'Greater than or equal to',
lt: 'Less than',
le: 'Less than or equal to',
equals: 'Equal to',
not_equals: 'Not Equal to',
between: 'Between',
current_user: 'Current user',
},
condition: {
all: 'all',
oneOf: 'or',
},
searchPanel: {
addCondition: 'Add Conditions',
reset: 'reset',
filter: 'filter',
selectTip: 'Please select the query field',
},
};

View File

@ -1,29 +0,0 @@
export default {
// 操作符号
operators: {
is_empty: '空',
is_not_empty: '非空',
like: '包含',
not_like: '不包含',
in: '属于',
not_in: '不属于',
gt: '大于',
ge: '大于等于',
lt: '小于',
le: '小于等于',
equals: '等于',
not_equals: '不等于',
between: '之间',
current_user: '是当前用户',
},
condition: {
all: '所有',
oneOf: '任一',
},
searchPanel: {
addCondition: '添加条件',
reset: '重置',
filter: '筛选',
selectTip: '请选择查询字段',
},
};

View File

@ -1,49 +0,0 @@
// 运算符号
export const OPERATORS = {
LIKE: {
label: 'operators.like',
value: 'like',
},
NOT_LIKE: {
label: 'operators.not_like',
value: 'not like',
},
IN: {
label: 'operators.in',
value: 'in',
},
NOT_IN: {
label: 'operators.not_in',
value: 'not in',
},
GT: {
label: 'operators.gt',
value: 'gt',
},
GE: {
label: 'operators.ge',
value: 'ge',
},
LT: {
label: 'operators.lt',
value: 'lt',
},
LE: {
label: 'operators.le',
value: 'le',
},
EQ: {
label: 'operators.equals',
value: 'eq',
},
BETWEEN: {
label: 'operators.between',
value: 'between',
},
CURRENT_USER: {
label: 'operators.current_user',
value: 'current user',
},
};
export default {};

View File

@ -1,172 +0,0 @@
<template>
<div class="overflow-y-auto">
<div class="flex flex-wrap items-start gap-[8px]">
<div class="flex-1">
<component
:is="form.searchKey.type"
v-bind="form.searchKey.props"
v-model="form.searchKey.value"
@change="searchKeyChange"
>
<a-optgroup
v-for="(group, i) of props.selectGroupList"
:key="`${group.label as string}-${i}`"
:label="group.label"
>
<a-option
v-for="groupOptions of group.options"
:key="groupOptions.value"
:value="groupOptions.value"
:disabled="isDisabledList.indexOf(groupOptions.value) > -1"
>{{ groupOptions.label }}</a-option
>
</a-optgroup>
</component>
</div>
<div class="w-[100px]">
<component
:is="form.operatorCondition.type"
v-bind="form.operatorCondition.props"
v-model="form.operatorCondition.value"
@change="operatorChangeHandler"
>
<a-option v-for="operator of form.operatorCondition.options" :key="operator.value" :value="operator.value">
{{ t(operator.label) }}
</a-option>
</component>
</div>
<div class="flex flex-1">
<a-form ref="queryContentFormRef" :model="form.queryContent">
<a-form-item
required
field="value"
:rules="form.queryContent.rules || [{ required: true, message: '请输入筛选内容' }]"
hide-label
hide-asterisk
class="mb-0"
>
<TimerSelect
v-if="form.queryContent.type === 'time-select'"
:model-value="form.queryContent.value"
v-bind="form.queryContent.props"
:operation-type="form.operatorCondition.value"
@update-time="updateTimeValue"
/>
<component
:is="form.queryContent.type"
v-else
v-bind="form.queryContent.props"
v-model="form.queryContent.value"
@change="filterKeyChange"
>
<template v-if="form.queryContent.type === 'a-select'">
<a-option v-for="opt of form.queryContent.options" :key="opt.value" :value="opt.value">{{
opt.label
}}</a-option>
</template>
<template v-else-if="form.queryContent.type === 'a-select-group'">
<a-select v-model="form.queryContent.value" v-bind="form.queryContent.props">
<a-optgroup v-for="group of form.searchKey.options" :key="group.id" :label="group.label">
<a-option v-for="groupOptions of group.options" :key="groupOptions.id" :value="groupOptions.id">{{
groupOptions.label
}}</a-option>
</a-optgroup>
</a-select>
</template>
</component>
</a-form-item>
</a-form>
<div class="minus"> <slot></slot></div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref, watchEffect } from 'vue';
import { SelectOptionData } from '@arco-design/web-vue';
import { cloneDeep } from 'lodash-es';
import TimerSelect from './time-select.vue';
import { useI18n } from '@/hooks/useI18n';
import { TEST_PLAN_TEST_CASE } from './caseUtils';
import type { FormInstance } from '@arco-design/web-vue';
const { t } = useI18n();
const props = defineProps<{
formItem: Record<string, any>; //
index: number; //
formList: Record<string, any>[]; //
selectGroupList: SelectOptionData[]; //
}>();
const emits = defineEmits(['dataUpdated']);
const form = ref({ ...cloneDeep(props.formItem) });
watchEffect(() => {
form.value = { ...cloneDeep(props.formItem) };
});
//
const searchKeyChange = (value: string) => {
const { operatorCondition, queryContent } = form.value;
operatorCondition.value = '';
operatorCondition.options = [];
queryContent.value = '';
// Key
const currentKeysConfig = TEST_PLAN_TEST_CASE.find((item: any) => item.key === value);
if (currentKeysConfig) {
operatorCondition.options = currentKeysConfig.operator.options;
operatorCondition.value = currentKeysConfig.operator.options[0].value;
queryContent.type = currentKeysConfig.type;
if (currentKeysConfig.rules) {
queryContent.rules = currentKeysConfig.rules;
}
}
emits('dataUpdated', form.value, props.index);
};
//
const isDisabledList = computed(() => {
return props.formList.map((item) => item.searchKey.value) || [];
});
//
const operatorChangeHandler = (value: string) => {
form.value.queryContent.value = value === 'between' ? [] : '';
emits('dataUpdated', form.value, props.index);
};
//
const filterKeyChange = () => {
emits('dataUpdated', form.value, props.index);
};
//
const updateTimeValue = (time: string | []) => {
form.value.queryContent.value = time;
emits('dataUpdated', form.value, props.index);
};
const queryContentFormRef = ref<FormInstance>();
//
const validateQueryContent = (callBack: (isSuccess: string) => void) => {
queryContentFormRef.value?.validate((errors) => {
if (!errors) {
callBack('ok');
} else {
callBack('no');
}
});
};
defineExpose({
validateQueryContent,
});
</script>
<style scoped></style>

View File

@ -1,257 +0,0 @@
<template>
<div class="filter-panel">
<div class="mb-4 flex items-center justify-between">
<div class="condition-text">{{ t('caseManagement.featureCase.setFilterCondition') }}</div>
<div>
<span class="condition-text">{{ t('caseManagement.featureCase.followingCondition') }}</span>
<a-select v-model="filterConditions.unit" class="mx-4 w-[68px]" size="small">
<a-option v-for="version of conditionOptions" :key="version.id" :value="version.value">{{
version.name
}}</a-option>
</a-select>
<span class="condition-text">{{ t('caseManagement.featureCase.condition') }}</span>
</div>
</div>
<div v-for="(formItem, index) in formModels" :key="index" class="mb-[8px]">
<a-scrollbar class="overflow-y-auto" :style="{ 'max-height': props.maxHeight || '300px' }">
<QueryFromItem
ref="queryFromRef"
:form-item="formItem"
:form-list="formModels"
:select-group-list="selectGroupList"
:index="index"
@data-updated="handleDataUpdated"
>
<div
v-show="formModels.length > 1"
class="remove-button ml-[8px] h-[32px] w-[32px] p-[2px]"
@click="removeField(index)"
>
<icon-minus-circle />
</div>
</QueryFromItem>
</a-scrollbar>
</div>
<div class="flex w-full items-center justify-between">
<a-button class="px-0" type="text" :disabled="isDisabledAdd" @click="addField">
<template #icon>
<icon-plus class="text-[14px]" />
</template>
{{ t('searchPanel.addCondition') }}
</a-button>
<div>
<a-button type="secondary" @click="resetField">{{ t('searchPanel.reset') }}</a-button>
<a-button class="ml-3" type="primary">{{ t('searchPanel.filter') }}</a-button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { Message } from '@arco-design/web-vue';
import QueryFromItem from './query-form-item.vue';
import { useI18n } from '@/hooks/useI18n';
import type { ConditionOptions, QueryTemplate } from './type';
const { t } = useI18n();
const props = defineProps<{
maxHeight?: string; // 300px
}>();
const filterConditions = ref({
unit: '',
});
const conditionOptions = ref<ConditionOptions[]>([
{
id: '1001',
name: t('condition.all'),
value: '',
},
{
id: '1002',
name: t('condition.oneOf'),
value: 'oneOf',
},
]);
//
const selectGroupList = ref([
{
label: '系统字段',
options: [
{
value: 'name',
label: '名称',
},
{
value: 'updateTime',
label: '更新时间',
},
],
},
{
label: '模版字段',
options: [
{
value: 'tags',
label: '标签',
},
{
value: 'module',
label: '模块',
},
],
},
]);
//
const deaultTemplate: QueryTemplate = {
//
searchKey: {
label: '',
type: 'a-select',
value: '',
field: 'nameKey',
props: {
placeholder: '请选择字段',
},
options: [
{
label: '系统字段',
options: [
{
value: 'name',
label: '名称',
},
{
value: 'updateTime',
label: '更新时间',
},
],
},
{
label: '模版字段',
options: [
{
value: 'tags',
label: '标签',
},
{
value: 'module',
label: '模块',
},
],
},
],
},
//
operatorCondition: {
label: '',
type: 'a-select',
value: '',
field: 'operator',
props: {
placeholder: '请选择条件',
},
options: [],
},
//
queryContent: {
label: '',
type: 'a-input',
value: '',
field: 'condition',
props: {
'max-length': 60,
'show-word-limit': true,
'allow-clear': true,
},
},
};
const formModels = ref<QueryTemplate[]>([{ ...deaultTemplate }]);
//
const removeField = (index: number) => {
formModels.value.splice(index, 1);
};
//
const allValidateResult = ref<string[]>([]);
const queryFromRef = ref();
//
const addField = async () => {
allValidateResult.value = [];
//
await Promise.all(
queryFromRef.value.map((item: any) => {
return new Promise<void>((resolve) => {
item.validateQueryContent(async (isValidated: string) => {
allValidateResult.value.push(isValidated);
resolve();
});
});
})
);
const isValidateSuccess = allValidateResult.value.every((item: string) => item === 'ok');
const ishasCondition = formModels.value.some((item) => !item.searchKey.value);
if (ishasCondition) {
Message.warning(t('searchPanel.selectTip'));
}
if (isValidateSuccess && !ishasCondition) {
formModels.value.push(deaultTemplate);
}
};
//
const handleDataUpdated = (newFromData: any, index: number) => {
formModels.value.splice(index, 1, newFromData);
};
//
const isDisabledAdd = computed(() => {
const isSelectValueKeys = formModels.value.map((item) => item.searchKey.value).filter((item) => item);
const allOptions = selectGroupList.value.flatMap((group) => group.options).map((item) => item.value);
const isAllExistValue = allOptions.every((item) => isSelectValueKeys.indexOf(item) > -1);
return isAllExistValue;
});
//
const resetField = () => {
formModels.value = formModels.value.map((item) => ({
...item,
queryContent: {
...item.queryContent,
value: '',
},
}));
};
</script>
<style scoped lang="less">
.filter-panel {
background: var(--color-text-n9);
@apply mt-1 rounded-md p-3;
.condition-text {
color: var(--color-text-2);
}
}
.remove-button {
color: var(--color-text-4);
@apply flex cursor-pointer items-center justify-center rounded;
&:hover {
color: rgb(var(--primary-5));
background: rgb(var(--primary-9));
}
}
:deep(.arco-scrollbar-track-direction-vertical .arco-scrollbar-thumb-bar) {
margin: 7px;
}
</style>

View File

@ -1,67 +0,0 @@
<template>
<a-date-picker
v-if="props.operationType !== 'between'"
v-model:model-value="timeValue"
class="w-[100%]"
show-time
:time-picker-props="{ defaultValue: '00:00:00' }"
format="YYYY-MM-DD HH:mm:ss"
position="br"
@change="changeHandler"
/>
<a-range-picker
v-else
v-model:model-value="timeRangeValue"
position="br"
show-time
:allow-clear="false"
class="w-[100%]"
format="YYYY-MM-DD HH:mm"
:time-picker-props="{
defaultValue: ['00:00:00', '00:00:00'],
}"
@change="changeHandler"
></a-range-picker>
</template>
<script setup lang="ts">
import { ref, watch, watchEffect } from 'vue';
import { CalendarValue } from '@arco-design/web-vue/es/date-picker/interface';
type PickerType = 'between' | 'gt' | 'lt'; // | |
const props = defineProps<{
modelValue: string[] | string; //
operationType: PickerType; //
}>();
const emits = defineEmits(['updateTime']);
const timeValue = ref<string>('');
const timeRangeValue = ref<string[]>([]);
const changeHandler = (value: Date | string | number | undefined | (CalendarValue | undefined)[] | undefined) => {
emits('updateTime', value);
};
watchEffect(() => {
if (props.operationType === 'between') {
timeRangeValue.value = props.modelValue as string[];
}
timeValue.value = props.modelValue as string;
});
watch(
() => props.modelValue,
(val) => {
if (!val) {
if (props.operationType === 'between') timeRangeValue.value = [];
timeValue.value = '';
}
}
);
</script>
<style scoped></style>

View File

@ -1,52 +0,0 @@
import { FieldRule, SelectOptionData } from '@arco-design/web-vue';
export interface ConditionOptions {
id: string;
name: string;
value: string;
}
// 选项组下拉options
export interface Option {
value: string;
label: string;
}
export interface QueryField {
label: string;
type: 'a-select' | 'a-input' | 'a-input-number' | 'time-select' | 'a-tree-select';
value: string;
field: string;
rules?: FieldRule[];
props?: {
[key: string]: string | number | boolean;
};
options?: SelectOptionData[];
}
export interface QueryTemplate {
searchKey: QueryField;
operatorCondition: QueryField;
queryContent: QueryField;
}
export interface OptionsType {
label: string;
value: string;
}
export interface OperatorValue {
value: string; // 如果未设置value初始值则value初始值为options[0]
options: OptionsType[]; // 运算符选项
}
export interface SearchKeyType {
key: string; // 对应字段key
type: string; // Vue控件名称
label: string; // 显示名称
rules?: FieldRule[];
request?: any;
props?: {
[key: string]: string | number | boolean;
};
operator: OperatorValue;
}

View File

@ -1,157 +0,0 @@
<template>
<FormCreate v-model:api="formApi" :rule="formRuleList" :option="props.options || option"></FormCreate>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import { debounce } from 'lodash-es';
import JiraKey from './comp/jiraKey.vue';
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, { Rule } from '@form-create/arco-design';
const formCreateStore = useFormCreateStore();
formCreate.component('PassWord', PassWord);
formCreate.component('SearchSelect', SearchSelect);
formCreate.component('JiraKey', JiraKey);
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 emit = defineEmits(['update:form-rule']);
const formApi = ref<any>({});
//
const cascadeItem = computed(() => {
const currentFormCreateRules = formCreateStore.formCreateRuleMap.get(props.formCreateKey);
// cascadeitem
if (currentFormCreateRules) {
const cascade = currentFormCreateRules
.map((item) => item.link)
.filter((item) => item)
.flatMap((flatItem: any) => flatItem);
// linkitem
return currentFormCreateRules.filter((item) => {
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: any) => item.link && (item.link as string[]).indexOf(val.field as string) > -1
);
if (resultItem) {
formCreateStore.getOptions(val, props.formCreateKey, resultItem as FormRuleItem, formApi.value);
}
}
}, 300);
watch(
cascadeItem,
(val) => {
// options
if (val) {
val.forEach((item) => {
if (item.value) {
getOptionsRequest(item as FormRuleItem);
}
});
}
},
{ deep: true, immediate: false }
);
const formRuleList = ref<FormRuleItem[]>([]); //
const formRules = ref<FormItem[]>([]);
watch(
() => props.formRule,
() => {
formRules.value = props.formRule;
formCreateStore.setInitFormCreate(props.formCreateKey, props.formRule);
formCreateStore.initFormCreateFormRules(props.formCreateKey);
formRuleList.value = formCreateStore.formCreateRuleMap.get(props.formCreateKey) as FormRuleItem[];
},
{ deep: true, immediate: true }
);
const formData = computed(() => {
return formCreateStore.formRuleMap.get(props.formCreateKey);
});
watch(
() => formData.value,
() => {
formRuleList.value = formCreateStore.formCreateRuleMap.get(props.formCreateKey) as FormRuleItem[];
}
);
watch(
() => formRuleList.value,
() => {
//
const result = formRuleList.value.map((item: any) => {
const type = props.formRule.find((it: any) => it.name === item.field)?.type;
const formItemRule = {
name: item.field,
type,
label: item.title,
value: item.value,
required: item?.effect?.required,
inputSearch: item.props.inputSearch || false,
instructionsIcon: item.props.instructionsIcon || '',
optionMethod: item.props.optionMethod || '',
couplingConfig: {
...item.props.couplingConfig,
},
sourceType: item.sourceType || '',
};
return formItemRule;
});
formCreateStore.setInitFormCreate(props.formCreateKey, result as FormItem[]);
},
{ deep: true }
);
defineExpose({
formApi, // form-createAPI
});
</script>
<style scoped></style>

View File

@ -3,6 +3,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
/**
* @description 用于原生字段form-create
*/
import { ref, watch, watchEffect } from 'vue'; import { ref, watch, watchEffect } from 'vue';
import JiraKey from './comp/jiraKey.vue'; import JiraKey from './comp/jiraKey.vue';

View File

@ -3,6 +3,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
/**
* @description 用于自己扩展功能的form-create
*/
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { FieldTypeFormRules } from '@/components/pure/ms-form-create/form-create'; import { FieldTypeFormRules } from '@/components/pure/ms-form-create/form-create';
@ -149,7 +152,12 @@
(formItemType: any) => item.type?.toUpperCase() === formItemType (formItemType: any) => item.type?.toUpperCase() === formItemType
); );
if (currentTypeForm) { if (currentTypeForm) {
fieldType = FieldTypeFormRules[currentTypeForm].type; if (currentTypeForm === 'INPUT' && item.subDesc) {
// inputsubDescJiraKey
fieldType = 'JiraKey';
} else {
fieldType = FieldTypeFormRules[currentTypeForm].type;
}
const options = item?.options; const options = item?.options;
const currentOptions = options?.map((optionsItem: any) => { const currentOptions = options?.map((optionsItem: any) => {
return { return {
@ -188,6 +196,7 @@
'disabled': item?.props?.disabled, 'disabled': item?.props?.disabled,
'type': item.control?.length && item.type === 'RADIO' ? 'button' : '', 'type': item.control?.length && item.type === 'RADIO' ? 'button' : '',
}, },
sourceType: item.type || '',
control: [], control: [],
update: item.update, update: item.update,
}; };

View File

@ -17,16 +17,13 @@
import { getPluginOptions } from '@/api/modules/setting/pluginManger'; import { getPluginOptions } from '@/api/modules/setting/pluginManger';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import useFormCreateStore from '@/store/modules/form-create/form-create';
import type { OptionsParams } from '@/models/setting/plugin'; import type { OptionsParams } from '@/models/setting/plugin';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
const appStore = useAppStore(); const appStore = useAppStore();
const organizationId = computed(() => appStore.currentOrgId); const organizationId = computed(() => appStore.currentOrgId);
const attrs = useAttrs(); const attrs = useAttrs();
const formCreateStore = useFormCreateStore();
const { t } = useI18n(); const { t } = useI18n();
const props = withDefaults( const props = withDefaults(

View File

@ -1,128 +0,0 @@
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 { useI18n } from '@/hooks/useI18n';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
const { t } = useI18n();
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;
// 从总form类型里边配置参考form-create.ts里边配置
const currentTypeForm = Object.keys(FieldTypeFormRules).find(
(formItemType: any) => item.type?.toUpperCase() === formItemType
);
if (currentTypeForm) {
if (currentTypeForm === 'INPUT' && item.subDesc) {
// 如果是input类型并且有subDesc说明是JiraKey 类型
fieldType = 'JiraKey';
} else {
fieldType = FieldTypeFormRules[currentTypeForm].type;
}
const options = item?.options;
const currentOptions = options?.map((optionsItem) => {
return {
label: optionsItem.text,
value: optionsItem.value,
};
});
const ruleItem = {
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,
rule: item.validate || [],
sourceType: item.type, // 原始表单类型
// 梳理表单所需要属性
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
'formKey': key, // 对应pinia-form-create里边初始化的KEY
'disabled': item?.props?.disabled,
},
};
// 如果不存在关联name删除link关联属性
if (ruleItem.link === '') {
delete ruleItem.link;
}
// 如果不是等于下拉多选或者单选等
if (ruleItem.type !== 'SearchSelect') {
delete ruleItem.props.inputSearch;
}
return ruleItem;
}
return {};
});
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) => cascadeItem.field === items.field);
if (formCreateItem) {
formCreateItem.props.keyword = val.value;
formCreateItem.props.formValue = formValue;
}
},
},
getters: {},
});
export default useFormCreateStore;

View File

@ -94,8 +94,9 @@
<MsFormCreate <MsFormCreate
v-if="formRules.length" v-if="formRules.length"
ref="formCreateRef" ref="formCreateRef"
v-model:formItem="formItem"
v-model:api="fApi"
:form-rule="formRules" :form-rule="formRules"
:form-create-key="FormCreateKeyEnum.BUG_DETAIL"
/> />
<a-form-item field="tag" :label="t('bugManagement.tag')"> <a-form-item field="tag" :label="t('bugManagement.tag')">
<a-input-tag <a-input-tag
@ -137,8 +138,8 @@
import { FileItem, Message } from '@arco-design/web-vue'; import { FileItem, Message } from '@arco-design/web-vue';
import MsCard from '@/components/pure/ms-card/index.vue'; import MsCard from '@/components/pure/ms-card/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/form-create.vue'; import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
import { FormItem } from '@/components/pure/ms-form-create/types'; import { 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 FileList from '@/components/pure/ms-upload/fileList.vue'; import FileList from '@/components/pure/ms-upload/fileList.vue';
import MsUpload from '@/components/pure/ms-upload/index.vue'; import MsUpload from '@/components/pure/ms-upload/index.vue';
@ -157,7 +158,6 @@
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'; import { useAppStore } from '@/store';
import useFormCreateStore from '@/store/modules/form-create/form-create';
import { scrollIntoView } from '@/utils/dom'; import { scrollIntoView } from '@/utils/dom';
import { BugEditCustomField, BugEditCustomFieldItem, BugEditFormObject } from '@/models/bug-management'; import { BugEditCustomField, BugEditCustomFieldItem, BugEditFormObject } from '@/models/bug-management';
@ -175,7 +175,7 @@
} }
const appStore = useAppStore(); const appStore = useAppStore();
const formCreateStore = useFormCreateStore(); // const formCreateStore = useFormCreateStore();
const route = useRoute(); const route = useRoute();
const templateOption = ref<TemplateOption[]>([]); const templateOption = ref<TemplateOption[]>([]);
@ -191,6 +191,8 @@
const fileList = ref<FileItem[]>([]); const fileList = ref<FileItem[]>([]);
const formRules = ref<FormItem[]>([]); const formRules = ref<FormItem[]>([]);
const formItem = ref<FormRuleItem[]>([]);
const fApi = ref({});
const associatedDrawer = ref(false); const associatedDrawer = ref(false);
const loading = ref(false); const loading = ref(false);
const acceptType = ref('none'); // - const acceptType = ref('none'); // -
@ -324,9 +326,8 @@
try { try {
loading.value = true; loading.value = true;
const customFields: BugEditCustomFieldItem[] = []; const customFields: BugEditCustomFieldItem[] = [];
const formRuleList = formCreateStore.formCreateRuleMap.get(FormCreateKeyEnum.BUG_DETAIL); if (formItem.value && formItem.value.length) {
if (formRuleList && formRuleList.length) { formItem.value.forEach((item: FormRuleItem) => {
formRuleList.forEach((item) => {
customFields.push({ customFields.push({
id: item.field as string, id: item.field as string,
name: item.title as string, name: item.title as string,

View File

@ -178,7 +178,7 @@
<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 ref="settingDrawerRef" v-model:visible="showSettingDrawer" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -268,6 +268,7 @@
activeTab.value = key; activeTab.value = key;
switch (activeTab.value) { switch (activeTab.value) {
case 'setting': case 'setting':
activeTab.value = 'detail';
showMenuSetting(); showMenuSetting();
break; break;
default: default:
@ -449,11 +450,14 @@
}, },
{ deep: true } { deep: true }
); );
const settingDrawerRef = ref();
watch( watch(
() => props.visible, () => props.visible,
(val) => { (val) => {
showDrawerVisible.value = val; showDrawerVisible.value = val;
if (val) {
settingDrawerRef.value.getTabModule();
}
} }
); );
@ -500,7 +504,6 @@
background: none !important; background: none !important;
.arco-menu-inner { .arco-menu-inner {
overflow: hidden; overflow: hidden;
padding: 14px 2px;
height: 50px; height: 50px;
} }
} }

View File

@ -49,7 +49,9 @@
import MsDrawer from '@/components/pure/ms-drawer/index.vue'; import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import { postTabletList } from '@/api/modules/project-management/menuManagement';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import useFeatureCaseStore from '@/store/modules/case/featureCase'; import useFeatureCaseStore from '@/store/modules/case/featureCase';
import type { TabItemType } from '@/models/caseManagement/featureCase'; import type { TabItemType } from '@/models/caseManagement/featureCase';
@ -58,6 +60,9 @@
const featureCaseStore = useFeatureCaseStore(); const featureCaseStore = useFeatureCaseStore();
const appStore = useAppStore();
const currentProjectId = computed(() => appStore.currentProjectId);
const props = defineProps<{ const props = defineProps<{
visible: boolean; visible: boolean;
}>(); }>();
@ -69,22 +74,36 @@
const showSettingVisible = ref<boolean>(false); const showSettingVisible = ref<boolean>(false);
const detailEnable = ref<boolean>(true); const detailEnable = ref<boolean>(true);
const moduleTab = ref<Record<string, TabItemType[]>>({
bugManagement: [
{
key: 'requirement',
title: 'caseManagement.featureCase.requirement',
enable: true,
},
{
key: 'bug',
title: 'caseManagement.featureCase.bug',
enable: true,
},
],
testPlan: [
{
key: 'testPlan',
title: 'caseManagement.featureCase.testPlan',
enable: true,
},
],
});
const buggerTab: TabItemType[] = [];
const testPlanTab: TabItemType[] = [];
const tabDefaultSettingList = ref<TabItemType[]>([ const tabDefaultSettingList = ref<TabItemType[]>([
{ {
key: 'case', key: 'case',
title: 'caseManagement.featureCase.case', title: 'caseManagement.featureCase.case',
enable: true, enable: true,
}, },
{
key: 'requirement',
title: 'caseManagement.featureCase.requirement',
enable: true,
},
{
key: 'bug',
title: 'caseManagement.featureCase.bug',
enable: true,
},
{ {
key: 'dependency', key: 'dependency',
title: 'caseManagement.featureCase.dependency', title: 'caseManagement.featureCase.dependency',
@ -95,11 +114,6 @@
title: 'caseManagement.featureCase.caseReview', title: 'caseManagement.featureCase.caseReview',
enable: true, enable: true,
}, },
{
key: 'testPlan',
title: 'caseManagement.featureCase.testPlan',
enable: true,
},
{ {
key: 'comments', key: 'comments',
title: 'caseManagement.featureCase.comments', title: 'caseManagement.featureCase.comments',
@ -111,10 +125,22 @@
enable: true, enable: true,
}, },
]); ]);
async function getTabModule() {
const result = await postTabletList({ projectId: currentProjectId.value });
const enableModuleArr = result.filter((item: any) => item.module === 'testPlan' || item.module === 'bugManagement');
enableModuleArr.forEach((item) => {
if (item.module === 'bugManagement') {
buggerTab.push(...moduleTab.value[item.module]);
} else if (item.module === 'testPlan') {
testPlanTab.push(...moduleTab.value[item.module]);
}
});
tabDefaultSettingList.value.splice(1, 0, buggerTab[0], buggerTab[1]);
tabDefaultSettingList.value.splice(-2, 0, testPlanTab[0]);
featureCaseStore.setTab(tabDefaultSettingList.value);
}
const tabList = computed(() => { const tabList = computed(() => featureCaseStore.tabSettingList);
return featureCaseStore.tabSettingList;
});
const tabSettingList = ref([...tabList.value]); const tabSettingList = ref([...tabList.value]);
@ -151,10 +177,8 @@
} }
); );
onMounted(() => { defineExpose({
if (tabList.value.length < 1) { getTabModule,
featureCaseStore.setTab(tabDefaultSettingList.value);
}
}); });
</script> </script>