-
Notifications
You must be signed in to change notification settings - Fork 2.6k
feat: Workflow form nodes support reference assignment #3866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,28 @@ | ||
| <template> | ||
| <el-form-item> | ||
| <el-form-item v-if="getModel"> | ||
| <template #label> | ||
| <div class="flex-between"> | ||
| {{ $t('dynamicsForm.AssignmentMethod.label', '赋值方式') }} | ||
| </div> | ||
| </template> | ||
|
|
||
| <el-row style="width: 100%" :gutter="10"> | ||
| <el-radio-group v-model="formValue.assignment_method"> | ||
| <el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list">{{ | ||
| item.label | ||
| }}</el-radio> | ||
| </el-radio-group> | ||
| </el-row> | ||
| </el-form-item> | ||
| <NodeCascader | ||
| v-if="formValue.assignment_method == 'ref_variables'" | ||
| ref="nodeCascaderRef" | ||
| :nodeModel="model" | ||
| class="w-full" | ||
| :placeholder="$t('views.applicationWorkflow.variable.placeholder')" | ||
| v-model="formValue.option_list" | ||
| /> | ||
| <el-form-item v-if="formValue.assignment_method === 'custom'"> | ||
| <template #label> | ||
| <div class="flex-between"> | ||
| {{ $t('dynamicsForm.Select.label') }} | ||
|
|
@@ -51,7 +74,9 @@ | |
| </el-col> | ||
| </el-row> | ||
| </el-form-item> | ||
|
|
||
| <el-form-item | ||
| v-if="formValue.assignment_method === 'custom'" | ||
| class="defaultValueItem" | ||
| :label="$t('dynamicsForm.default.label')" | ||
| :required="formValue.required" | ||
|
|
@@ -83,8 +108,35 @@ | |
| </el-form-item> | ||
| </template> | ||
| <script setup lang="ts"> | ||
| import { computed, onMounted } from 'vue' | ||
| import { computed, onMounted, inject, ref } from 'vue' | ||
| import RadioCard from '@/components/dynamics-form/items/radio/RadioCard.vue' | ||
| import NodeCascader from '@/workflow/common/NodeCascader.vue' | ||
| import { t } from '@/locales' | ||
| const getModel = inject('getModel') as any | ||
|
|
||
| const assignment_method_option_list = computed(() => { | ||
| const option_list = [ | ||
| { | ||
| label: t('dynamicsForm.AssignmentMethod.custom.label', '自定义'), | ||
| value: 'custom', | ||
| }, | ||
| ] | ||
| if (getModel) { | ||
| option_list.push({ | ||
| label: t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量'), | ||
| value: 'ref_variables', | ||
| }) | ||
| } | ||
| return option_list | ||
| }) | ||
|
|
||
| const model = computed(() => { | ||
| if (getModel) { | ||
| return getModel() | ||
| } else { | ||
| return null | ||
| } | ||
| }) | ||
| const props = defineProps<{ | ||
| modelValue: any | ||
| }>() | ||
|
|
@@ -121,17 +173,20 @@ const getData = () => { | |
| text_field: 'label', | ||
| value_field: 'value', | ||
| option_list: formValue.value.option_list, | ||
| assignment_method: formValue.value.assignment_method || 'custom', | ||
| } | ||
| } | ||
| const rander = (form_data: any) => { | ||
| formValue.value.option_list = form_data.option_list || [] | ||
| formValue.value.default_value = form_data.default_value | ||
| formValue.value.assignment_method = form_data.assignment_method || 'custom' | ||
| } | ||
|
|
||
| defineExpose({ getData, rander }) | ||
| onMounted(() => { | ||
| formValue.value.option_list = [] | ||
| formValue.value.default_value = '' | ||
| formValue.value.assignment_method = 'custom' | ||
| if (formValue.value.show_default_value === undefined) { | ||
| formValue.value.show_default_value = true | ||
| } | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your code looks generally clean for Vue 3 with TypeScript, but there are a few areas where improvements can be made:
Here’s an updated version of your code with these improvements: <template>
<el-form-item v-if="getModel">
<el-radio-group v-model="formValue.assignment_method">
<el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<NodeCascader
v-if="assignment_method === 'ref_variables'"
ref="nodeCascaderRef"
:nodeModel="model"
class="w-full"
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
v-model="formValue.option_list"
/>
<el-form-item v-if="assignment_method === 'custom'">
<template #label>
<div class="flex-between">
{{ $t('dynamicsForm.select.label') }}
</div>
</template>
<el-row style="width: 100%" :gutter="10">
<!-- Custom content goes here -->
</el-row>
</el-form-item>
<el-form-item
v-if="assignment_method === 'custom'"
class="defaultValueItem"
:label="$t('dynamicsForm.default.label')"
:required="formValue.required"
>
<el-input
v-model="formValue.defaultValue"
placeholder="Enter default value"
/>
</el-form-item>
</template>
<script setup lang="ts">
import { computed, onMounted, inject, ref } from 'vue';
import RadioCard from '@/components/dynamics-form/items/radio/RadioCard.vue';
import NodeCascader from '@/workflow/common/NodeCascader.vue';
import { t } from '@src/i18n';
/**
* Injected global property to access the current model.
*/
const getModel = inject('getModel') as any;
/**
* Computed list of available assignment method options.
*/
const assignment_method_option_list = computed(() => {
const option_list = [
{ label: t('dynamicsForm.Assignee.type.user'), value: 'user' },
{ label: t('dynamicsForm.Assignee.type.group'), value: 'group' },
];
// Add ref variables option if getModel is a function
if (typeof getModel !== 'undefined') {
option_list.push(
{ label: t('dynamicsForm.Assignee.type.variables'), value: 'variables' },
{ label: t('dynamicsForm.Assignee.type.formula'), value: 'formula' },
);
}
return option_list;
});
/**
* Computed model value based on existence of getModel.
*/
const model = computed(() => ({
...getModel?.(),
}));
// Form data reactive values
const formValue = ref({
showDefaultValues: true,
defaultValue: '',
value: {},
required: false,
assignment_method: 'variables',
});
const updateAssignmentMethodOptions = () => {
const newOptionList = [
{ label: t('dynamicsForm.Assignee.type.user'), value: 'user' },
{ label: t('dynamicsForm.Assignee.type.group'), value: 'group' },
];
// Add ref variables option if getModel is defined
if (typeof getModel === 'function') {
newOptionList.push(
{ label: t('dynamicsForm.Assignee.type.variables'), value: 'variables' },
{ label: t('dynamicsForm.Assignee.type.formula'), value: 'formula' },
);
}
assignment_method_option_list.value.splice(0);
assignment_method_option_list.value.push(...newOptionList);
};
// Fetch initial data
onMounted(async () => {
await updateAssignmentMehtodOptions();
});
</script>
<style scoped>
<!-- Add scoped styles here -->
</style>Key Improvements:
Remember to adjust the logic and structure based on specific requirements and context of your project. |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,28 @@ | ||
| <template> | ||
| <el-form-item> | ||
| <el-form-item v-if="getModel"> | ||
| <template #label> | ||
| <div class="flex-between"> | ||
| {{ $t('dynamicsForm.AssignmentMethod.label', '赋值方式') }} | ||
| </div> | ||
| </template> | ||
|
|
||
| <el-row style="width: 100%" :gutter="10"> | ||
| <el-radio-group v-model="formValue.assignment_method"> | ||
| <el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list">{{ | ||
| item.label | ||
| }}</el-radio> | ||
| </el-radio-group> | ||
| </el-row> | ||
| </el-form-item> | ||
| <NodeCascader | ||
| v-if="formValue.assignment_method == 'ref_variables'" | ||
| ref="nodeCascaderRef" | ||
| :nodeModel="model" | ||
| class="w-full" | ||
| :placeholder="$t('views.applicationWorkflow.variable.placeholder')" | ||
| v-model="formValue.option_list" | ||
| /> | ||
| <el-form-item v-if="formValue.assignment_method == 'custom'"> | ||
| <template #label> | ||
| <div class="flex-between"> | ||
| {{ $t('dynamicsForm.Select.label') }} | ||
|
|
@@ -52,6 +75,7 @@ | |
| </el-row> | ||
| </el-form-item> | ||
| <el-form-item | ||
| v-if="formValue.assignment_method == 'custom'" | ||
| class="defaultValueItem" | ||
| :required="formValue.required" | ||
| prop="default_value" | ||
|
|
@@ -85,8 +109,34 @@ | |
| </el-form-item> | ||
| </template> | ||
| <script setup lang="ts"> | ||
| import { computed, onMounted } from 'vue' | ||
| import { computed, onMounted, inject } from 'vue' | ||
| import NodeCascader from '@/workflow/common/NodeCascader.vue' | ||
| import { t } from '@/locales' | ||
| const getModel = inject('getModel') as any | ||
|
|
||
| const assignment_method_option_list = computed(() => { | ||
| const option_list = [ | ||
| { | ||
| label: t('dynamicsForm.AssignmentMethod.custom.label', '自定义'), | ||
| value: 'custom', | ||
| }, | ||
| ] | ||
| if (getModel) { | ||
| option_list.push({ | ||
| label: t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量'), | ||
| value: 'ref_variables', | ||
| }) | ||
| } | ||
| return option_list | ||
| }) | ||
|
|
||
| const model = computed(() => { | ||
| if (getModel) { | ||
| return getModel() | ||
| } else { | ||
| return null | ||
| } | ||
| }) | ||
| const props = defineProps<{ | ||
| modelValue: any | ||
| }>() | ||
|
|
@@ -121,18 +171,21 @@ const getData = () => { | |
| text_field: 'label', | ||
| value_field: 'value', | ||
| option_list: formValue.value.option_list, | ||
| assignment_method: formValue.value.assignment_method || 'custom', | ||
| } | ||
| } | ||
| const rander = (form_data: any) => { | ||
| formValue.value.option_list = form_data.option_list || [] | ||
| formValue.value.default_value = form_data.default_value | ||
| formValue.value.show_default_value = form_data.show_default_value | ||
| formValue.value.assignment_method = form_data.assignment_method || 'custom' | ||
| } | ||
|
|
||
| defineExpose({ getData, rander }) | ||
| onMounted(() => { | ||
| formValue.value.option_list = [] | ||
| formValue.value.default_value = '' | ||
| formValue.value.assignment_method = 'custom' | ||
| if (formValue.value.show_default_value === undefined) { | ||
| formValue.value.show_default_value = true | ||
| } | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here are some suggestions and changes to improve the provided code: Improvements
Updated Code<template>
<el-form-item v-if="getModel">
<template #label>
<div class="flex-between">
{{ $t('dynamicsForm.AssignmentMethod.label', '赋值方式') }}
</div>
</template>
<el-row style="width: 100%" :gutter="10">
<el-radio-group v-model="formValue.assignment_method" size="large">
<el-radio v-for="item in assignment_method_option_list" :key="item.value" :value="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-row>
<node-cascader
ref="nodeCascaderRef"
:nodeModel="getNodeModel()"
class="w-full mt-10"
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
v-model="formValue.option_list"
/>
</el-form-item>
<el-form-item
v-if="formValue.assignment_method !== 'custom'"
class="defaultValueItem"
:required="formValue.required"
prop="default_value">
<!-- Default value template -->
</el-form-item>
</template>
<script setup lang="ts">
import { computed, onMounted } from 'vue';
import NodeCascader from '@/workflow/common/NodeCascader.vue';
import { t } from '@/locales';
// Inject required methods and values
const getNodeModel = inject('getNodeModel');
const formValue = reactive({
modelValue: null,
show_default_value: true,
});
// Compute the list of assignment method options
const assignment_method_option_list = computed(() => {
const result: any[] = [
{
label: t('dynamicsForm.AssignmentMethod.custom.label', '自定义'),
value: 'custom',
},
];
// Add referential variable option only if node model is available
if (getNodeModel()) {
result.push({
label: t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量'),
value: 'ref_variables',
});
}
return result;
});
// Define props
defineProps<{ modelValue?: any; required?: boolean }>();
const getData = (): void => {
formValue.modelValue = {
text_field: 'label',
value_field: 'value',
option_list: [],
assignment_method: '',
};
};
const render = (data: Record<string, any>): void => {
formValue.modelValue.option_list = data.option_list || [];
formValue.modelValue.default_value = data.default_value;
formValue.modelValue.show_default_value = data.show_default_value;
};SummaryMain improvements include using Vue directives consistently, simplifying conditional rendering, adding descriptive names to computed properties, removing unused variables, and ensuring all references to injected functions and values are correct. This approach enhances readability, maintainability, and performance while adhering to best coding practices. |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The provided Vue component seems largely well-formed, but there are several potential optimizations and improvements:
Use of
v-showinstead ofv-if:If the condition only affects rendering rather than state management, using
v-showcan be more efficient.Avoid Repeated Function Calls:
Ensure that
computedproperties should not perform expensive calculations unless necessary to avoid unnecessary re-renders.Simplify Condition Checks:
You can simplify this with template expressions:
Consistent Variable Names:
Ensure consistent naming conventions within templates like
<div class="flex-between">. Also, variables used inside components should be consistently prefixed withthis.in methods or directives where they need access to instance data.Code Cleanup:
Internationalization Check:
The
$t()function is being imported multiple times; ensure it's defined correctly across your project's internationalization setup.These adjustments will help improve readability, performance, and maintainability of the component without affecting its functionality.