UnisKB/ui/src/views/tool/ToolFormDrawer.vue

470 lines
15 KiB
Vue
Raw Normal View History

2025-05-15 10:21:38 +00:00
<template>
<el-drawer v-model="visible" size="60%" :before-close="close">
<template #header>
<h4>{{ title }}</h4>
</template>
<div>
<h4 class="title-decoration-1 mb-16">
2025-07-07 13:21:03 +00:00
{{ $t('views.model.modelForm.title.baseInfo') }}
2025-05-15 10:21:38 +00:00
</h4>
<el-form
ref="FormRef"
:model="form"
:rules="rules"
label-position="top"
require-asterisk-position="right"
v-loading="loading"
@submit.prevent
>
2025-05-26 10:10:18 +00:00
<el-form-item :label="$t('views.tool.form.toolName.label')" prop="name">
2025-05-15 10:21:38 +00:00
<div class="flex w-full">
<div
v-if="form.id"
class="edit-avatar mr-12"
@mouseenter="showEditIcon = true"
@mouseleave="showEditIcon = false"
>
2025-05-26 10:10:18 +00:00
<el-Avatar
2025-05-15 10:21:38 +00:00
v-if="isAppIcon(form.icon)"
:id="form.id"
shape="square"
:size="32"
style="background: none"
>
2025-06-24 08:53:58 +00:00
<img :src="String(form.icon)" alt="" />
2025-05-26 10:10:18 +00:00
</el-Avatar>
<el-avatar v-else class="avatar-green" shape="square" :size="32">
2025-07-08 18:58:16 +00:00
<img src="@/assets/workflow/icon_tool.svg" style="width: 58%" alt="" />
2025-05-26 10:10:18 +00:00
</el-avatar>
<el-Avatar
2025-05-15 10:21:38 +00:00
v-if="showEditIcon"
:id="form.id"
shape="square"
class="edit-mask"
:size="32"
@click="openEditAvatar"
>
<AppIcon iconName="app-edit"></AppIcon>
2025-05-26 10:10:18 +00:00
</el-Avatar>
2025-05-15 10:21:38 +00:00
</div>
<el-avatar v-else class="avatar-green mr-12" shape="square" :size="32">
2025-07-08 18:58:16 +00:00
<img src="@/assets/workflow/icon_tool.svg" style="width: 58%" alt="" />
2025-05-26 10:10:18 +00:00
</el-avatar>
2025-05-15 10:21:38 +00:00
<el-input
v-model="form.name"
2025-05-22 10:38:06 +00:00
:placeholder="$t('views.tool.form.toolName.placeholder')"
2025-05-15 10:21:38 +00:00
maxlength="64"
show-word-limit
@blur="form.name = form.name?.trim()"
/>
</div>
</el-form-item>
2025-05-22 10:38:06 +00:00
<el-form-item :label="$t('views.tool.form.toolDescription.label')">
2025-05-15 10:21:38 +00:00
<el-input
v-model="form.desc"
type="textarea"
2025-05-22 10:38:06 +00:00
:placeholder="$t('views.tool.form.toolDescription.placeholder')"
2025-05-15 10:21:38 +00:00
maxlength="128"
show-word-limit
:autosize="{ minRows: 3 }"
@blur="form.desc = form.desc?.trim()"
/>
</el-form-item>
</el-form>
<div class="flex-between">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.param.initParam') }}
</h4>
2025-06-26 14:11:56 +00:00
<el-button link type="primary" @click="openAddInitDialog()">
2025-06-06 01:39:01 +00:00
<el-icon class="mr-4">
2025-06-24 08:53:58 +00:00
<Plus />
2025-06-06 01:39:01 +00:00
</el-icon>
{{ $t('common.add') }}
2025-05-15 10:21:38 +00:00
</el-button>
</div>
<el-table ref="initFieldTableRef" :data="form.init_field_list" class="mb-16">
<el-table-column prop="field" :label="$t('dynamicsForm.paramForm.field.label')">
<template #default="{ row }">
<span :title="row.field" class="ellipsis-1">{{ row.field }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('dynamicsForm.paramForm.input_type.label')">
<template #default="{ row }">
2025-06-24 08:53:58 +00:00
<el-tag type="info" class="info-tag" v-if="row.input_type === 'TextInput'"
>{{ $t('dynamicsForm.input_type_list.TextInput') }}
2025-06-06 01:39:01 +00:00
</el-tag>
2025-06-24 08:53:58 +00:00
<el-tag type="info" class="info-tag" v-if="row.input_type === 'PasswordInput'"
>{{ $t('dynamicsForm.input_type_list.PasswordInput') }}
2025-06-06 01:39:01 +00:00
</el-tag>
2025-06-24 08:53:58 +00:00
<el-tag type="info" class="info-tag" v-if="row.input_type === 'Slider'"
>{{ $t('dynamicsForm.input_type_list.Slider') }}
2025-06-06 01:39:01 +00:00
</el-tag>
2025-06-24 08:53:58 +00:00
<el-tag type="info" class="info-tag" v-if="row.input_type === 'SwitchInput'"
>{{ $t('dynamicsForm.input_type_list.SwitchInput') }}
2025-06-06 01:39:01 +00:00
</el-tag>
2025-06-24 08:53:58 +00:00
<el-tag type="info" class="info-tag" v-if="row.input_type === 'SingleSelect'"
>{{ $t('dynamicsForm.input_type_list.SingleSelect') }}
2025-06-06 01:39:01 +00:00
</el-tag>
2025-06-24 08:53:58 +00:00
<el-tag type="info" class="info-tag" v-if="row.input_type === 'MultiSelect'"
>{{ $t('dynamicsForm.input_type_list.MultiSelect') }}
2025-06-06 01:39:01 +00:00
</el-tag>
2025-06-24 08:53:58 +00:00
<el-tag type="info" class="info-tag" v-if="row.input_type === 'RadioCard'"
>{{ $t('dynamicsForm.input_type_list.RadioCard') }}
2025-06-06 01:39:01 +00:00
</el-tag>
2025-06-24 08:53:58 +00:00
<el-tag type="info" class="info-tag" v-if="row.input_type === 'DatePicker'"
>{{ $t('dynamicsForm.input_type_list.DatePicker') }}
2025-06-06 01:39:01 +00:00
</el-tag>
2025-05-15 10:21:38 +00:00
</template>
</el-table-column>
<el-table-column :label="$t('common.required')">
<template #default="{ row }">
<div @click.stop>
2025-06-24 08:53:58 +00:00
<el-switch disabled size="small" v-model="row.required" />
2025-05-15 10:21:38 +00:00
</div>
</template>
</el-table-column>
<el-table-column :label="$t('common.operation')" align="left" width="90">
<template #default="{ row, $index }">
<span class="mr-4">
<el-tooltip effect="dark" :content="$t('common.modify')" placement="top">
<el-button type="primary" text @click.stop="openAddInitDialog(row, $index)">
<AppIcon iconName="app-edit"></AppIcon>
2025-05-15 10:21:38 +00:00
</el-button>
</el-tooltip>
</span>
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
<el-button type="primary" text @click="deleteInitField($index)">
<AppIcon iconName="app-delete"></AppIcon>
2025-05-15 10:21:38 +00:00
</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<div class="flex-between">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.param.inputParam') }}
<el-text type="info" class="color-secondary">
2025-05-22 10:38:06 +00:00
{{ $t('views.tool.form.param.paramInfo1') }}
2025-05-15 10:21:38 +00:00
</el-text>
</h4>
2025-06-23 09:44:46 +00:00
<el-button link type="primary" @click="openAddDialog()">
2025-06-06 01:39:01 +00:00
<el-icon class="mr-4">
2025-06-24 08:53:58 +00:00
<Plus />
2025-06-06 01:39:01 +00:00
</el-icon>
{{ $t('common.add') }}
2025-05-15 10:21:38 +00:00
</el-button>
</div>
<el-table ref="inputFieldTableRef" :data="form.input_field_list" class="mb-16">
2025-06-24 08:53:58 +00:00
<el-table-column prop="name" :label="$t('views.tool.form.paramName.label')" />
2025-05-22 10:38:06 +00:00
<el-table-column :label="$t('views.tool.form.dataType.label')">
2025-05-15 10:21:38 +00:00
<template #default="{ row }">
<el-tag type="info" class="info-tag">{{ row.type }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('common.required')">
<template #default="{ row }">
<div @click.stop>
2025-06-24 08:53:58 +00:00
<el-switch size="small" v-model="row.is_required" />
2025-05-15 10:21:38 +00:00
</div>
</template>
</el-table-column>
2025-05-26 10:10:18 +00:00
<el-table-column prop="source" :label="$t('views.tool.form.source.label')">
2025-05-15 10:21:38 +00:00
<template #default="{ row }">
{{
row.source === 'custom' ? $t('common.custom') : $t('views.tool.form.source.reference')
2025-05-15 10:21:38 +00:00
}}
</template>
</el-table-column>
<el-table-column :label="$t('common.operation')" align="left" width="90">
<template #default="{ row, $index }">
<span class="mr-4">
<el-tooltip effect="dark" :content="$t('common.modify')" placement="top">
<el-button type="primary" text @click.stop="openAddDialog(row, $index)">
<AppIcon iconName="app-edit"></AppIcon>
2025-05-15 10:21:38 +00:00
</el-button>
</el-tooltip>
</span>
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
<el-button type="primary" text @click="deleteField($index)">
<AppIcon iconName="app-delete"></AppIcon>
2025-05-15 10:21:38 +00:00
</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<h4 class="title-decoration-1 mb-16">
2025-05-22 10:38:06 +00:00
{{ $t('views.tool.form.param.code') }}
2025-05-15 10:21:38 +00:00
<span style="color: red; margin-left: -10px">*</span>
<el-text type="info" class="color-secondary">
2025-05-22 10:38:06 +00:00
{{ $t('views.tool.form.param.paramInfo2') }}
2025-05-15 10:21:38 +00:00
</el-text>
</h4>
<div class="mb-8" v-if="showEditor">
<CodemirrorEditor
2025-05-22 10:38:06 +00:00
:title="$t('views.tool.form.param.code')"
2025-05-15 10:21:38 +00:00
v-model="form.code"
@submitDialog="submitCodemirrorEditor"
/>
</div>
<h4 class="title-decoration-1 mb-16 mt-16">
{{ $t('common.param.outputParam') }}
<el-text type="info" class="color-secondary">
2025-05-22 10:38:06 +00:00
{{ $t('views.tool.form.param.paramInfo1') }}
2025-05-15 10:21:38 +00:00
</el-text>
</h4>
2025-06-26 08:36:08 +00:00
<div class="flex-between border-r-6 p-8-12 mb-8 layout-bg lighter">
2025-05-15 10:21:38 +00:00
<span>{{ $t('common.result') }} {result}</span>
</div>
</div>
<template #footer>
<div>
<el-button :loading="loading" @click="visible = false">{{ $t('common.cancel') }}</el-button>
<el-button :loading="loading" @click="openDebug" v-if="permissionPrecise.debug()">{{
2025-06-24 08:53:58 +00:00
$t('common.debug')
}}</el-button>
<el-button
type="primary"
@click="submit(FormRef)"
:loading="loading"
v-if="isEdit ? permissionPrecise.edit(form?.id as string) : permissionPrecise.create()"
>
2025-06-06 01:39:01 +00:00
{{ isEdit ? $t('common.save') : $t('common.create') }}
2025-06-24 08:53:58 +00:00
</el-button>
2025-05-15 10:21:38 +00:00
</div>
</template>
2025-06-24 08:53:58 +00:00
<ToolDebugDrawer ref="ToolDebugDrawerRef" />
<FieldFormDialog ref="FieldFormDialogRef" @refresh="refreshFieldList" />
<UserFieldFormDialog ref="UserFieldFormDialogRef" @refresh="refreshInitFieldList" />
<EditAvatarDialog ref="EditAvatarDialogRef" @refresh="refreshTool" />
2025-05-15 10:21:38 +00:00
</el-drawer>
</template>
<script setup lang="ts">
2025-06-24 08:53:58 +00:00
import { ref, reactive, watch, nextTick, computed } from 'vue'
2025-05-26 10:10:18 +00:00
import FieldFormDialog from '@/views/tool/component/FieldFormDialog.vue'
import ToolDebugDrawer from './ToolDebugDrawer.vue'
import UserFieldFormDialog from '@/views/tool/component/UserFieldFormDialog.vue'
import EditAvatarDialog from '@/views/tool/component/EditAvatarDialog.vue'
2025-06-24 08:53:58 +00:00
import type { toolData } from '@/api/type/tool'
import type { FormInstance } from 'element-plus'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { cloneDeep } from 'lodash'
import { t } from '@/locales'
import { isAppIcon } from '@/utils/common'
2025-06-23 09:44:46 +00:00
import { useRoute } from 'vue-router'
import useStore from '@/stores'
import permissionMap from '@/permission'
2025-06-24 08:53:58 +00:00
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
2025-06-23 09:44:46 +00:00
2025-06-27 09:59:38 +00:00
const route = useRoute()
2025-06-24 14:12:17 +00:00
const props = defineProps({
title: String,
})
2025-06-23 09:44:46 +00:00
const { folder, user } = useStore()
2025-06-24 14:12:17 +00:00
const apiType = computed(() => {
2025-06-23 09:44:46 +00:00
if (route.path.includes('shared')) {
return 'systemShare'
} else if (route.path.includes('resource-management')) {
return 'systemManage'
} else {
return 'workspace'
}
})
const permissionPrecise = computed(() => {
2025-06-24 14:12:17 +00:00
return permissionMap['tool'][apiType.value]
2025-06-23 09:44:46 +00:00
})
2025-05-15 10:21:38 +00:00
const emit = defineEmits(['refresh'])
const FieldFormDialogRef = ref()
2025-05-26 10:10:18 +00:00
const ToolDebugDrawerRef = ref()
2025-05-15 10:21:38 +00:00
const UserFieldFormDialogRef = ref()
const EditAvatarDialogRef = ref()
const initFieldTableRef = ref()
const inputFieldTableRef = ref()
const FormRef = ref()
const isEdit = ref(false)
const loading = ref(false)
const visible = ref(false)
const showEditor = ref(false)
const currentIndex = ref<any>(null)
const showEditIcon = ref(false)
2025-05-22 10:38:06 +00:00
const form = ref<toolData>({
2025-05-15 10:21:38 +00:00
name: '',
desc: '',
code: '',
icon: '',
input_field_list: [],
init_field_list: [],
})
watch(visible, (bool) => {
if (!bool) {
isEdit.value = false
showEditor.value = false
currentIndex.value = null
form.value = {
name: '',
desc: '',
code: '',
icon: '',
input_field_list: [],
init_field_list: [],
}
FormRef.value?.clearValidate()
}
})
const rules = reactive({
name: [
{
required: true,
2025-05-22 10:38:06 +00:00
message: t('views.tool.form.toolName.requiredMessage'),
trigger: 'blur',
},
2025-05-15 10:21:38 +00:00
],
})
function submitCodemirrorEditor(val: string) {
form.value.code = val
}
function close() {
if (isEdit.value || !areAllValuesNonEmpty(form.value)) {
visible.value = false
} else {
2025-05-22 10:38:06 +00:00
MsgConfirm(t('common.tip'), t('views.tool.tip.saveMessage'), {
2025-05-15 10:21:38 +00:00
confirmButtonText: t('common.confirm'),
2025-05-22 10:38:06 +00:00
type: 'warning',
2025-05-15 10:21:38 +00:00
})
.then(() => {
visible.value = false
})
2025-06-24 08:53:58 +00:00
.catch(() => {})
2025-05-15 10:21:38 +00:00
}
}
function areAllValuesNonEmpty(obj: any) {
return Object.values(obj).some((value) => {
return Array.isArray(value)
? value.length !== 0
: value !== null && value !== undefined && value !== ''
})
}
function openDebug() {
2025-05-26 10:10:18 +00:00
ToolDebugDrawerRef.value.open(form.value)
2025-05-15 10:21:38 +00:00
}
function deleteField(index: any) {
form.value.input_field_list?.splice(index, 1)
}
function openAddDialog(data?: any, index?: any) {
if (typeof index !== 'undefined') {
currentIndex.value = index
}
FieldFormDialogRef.value.open(data)
}
function refreshFieldList(data: any) {
if (currentIndex.value !== null) {
form.value.input_field_list?.splice(currentIndex.value, 1, data)
} else {
form.value.input_field_list?.push(data)
}
currentIndex.value = null
}
function openAddInitDialog(data?: any, index?: any) {
if (typeof index !== 'undefined') {
currentIndex.value = index
}
UserFieldFormDialogRef.value.open(data)
}
function refreshInitFieldList(data: any) {
if (currentIndex.value !== null) {
form.value.init_field_list?.splice(currentIndex.value, 1, data)
} else {
form.value.init_field_list?.push(data)
}
currentIndex.value = null
UserFieldFormDialogRef.value.close()
}
2025-06-09 13:27:12 +00:00
function refreshTool(data: any) {
2025-05-15 10:21:38 +00:00
form.value.icon = data
}
function deleteInitField(index: any) {
form.value.init_field_list?.splice(index, 1)
}
function openEditAvatar() {
EditAvatarDialogRef.value.open(form.value)
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid: any) => {
if (valid) {
if (isEdit.value) {
2025-06-24 14:12:17 +00:00
loadSharedApi({ type: 'tool', systemType: apiType.value })
2025-06-24 08:53:58 +00:00
.putTool(form.value?.id as string, form.value, loading)
.then((res: any) => {
MsgSuccess(t('common.editSuccess'))
emit('refresh', res.data)
return user.profile()
2025-06-24 08:53:58 +00:00
})
.then(() => {
visible.value = false
})
2025-05-15 10:21:38 +00:00
} else {
2025-06-24 08:53:58 +00:00
const obj = {
folder_id: folder.currentFolder?.id,
...form.value,
}
2025-06-24 14:12:17 +00:00
loadSharedApi({ type: 'tool', systemType: apiType.value })
2025-06-24 08:53:58 +00:00
.postTool(obj, loading)
.then((res: any) => {
MsgSuccess(t('common.createSuccess'))
emit('refresh')
return user.profile()
2025-06-24 08:53:58 +00:00
})
.then(() => {
visible.value = false
})
2025-05-15 10:21:38 +00:00
}
}
})
}
const open = (data: any) => {
if (data) {
isEdit.value = data?.id ? true : false
form.value = cloneDeep(data)
}
visible.value = true
setTimeout(() => {
showEditor.value = true
}, 100)
}
defineExpose({
2025-05-22 10:38:06 +00:00
open,
2025-05-15 10:21:38 +00:00
})
</script>
<style lang="scss" scoped></style>