feat: tool
Some checks are pending
sync2gitee / repo-sync (push) Waiting to run

This commit is contained in:
wangdan-fit2cloud 2025-05-15 18:21:38 +08:00
parent aa7bc349ab
commit e50b5cc051
23 changed files with 1659 additions and 85 deletions

View File

@ -2,6 +2,7 @@ import { Result } from '@/request/Result'
import { get, post, del, put } from '@/request/index'
import { type Ref } from 'vue'
import type { pageRequest } from '@/api/type/common'
import type { toolData } from '@/api/type/tool'
const prefix = '/workspace'
/**
@ -38,7 +39,37 @@ const getToolList: (
)
}
/**
*
* @param
*/
const putToolLib: (
wordspace_id: string,
tool_id: string,
data: toolData,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (wordspace_id, tool_id, data, loading) => {
return put(`${prefix}/${wordspace_id}/tool/${tool_id}`, data, undefined, loading)
}
/**
*
* @param tool_id id
* @param loading
* @returns
*/
const getToolById: (
wordspace_id: string,
tool_id: String,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (wordspace_id, function_lib_id, loading) => {
return get(`${prefix}/${wordspace_id}/tool/${function_lib_id}`, undefined, loading)
}
export default {
getToolByFolder,
getToolList,
putToolLib,
getToolById
}

13
ui/src/api/type/tool.ts Normal file
View File

@ -0,0 +1,13 @@
interface toolData {
id?: String
name?: String
icon?: String
desc?: String
code?: String
input_field_list?: Array<any>
init_field_list?: Array<any>
is_active?: Boolean
folder_id?: String
}
export type { toolData }

View File

@ -117,7 +117,27 @@ export const iconMap: any = {
])
},
},
'app-disabled': {
iconReader: () => {
return h('i', [
h(
'svg',
{
style: { height: '100%', width: '100%' },
viewBox: '0 0 1024 1024',
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg',
},
[
h('path', {
d: 'M512 21.333333C241.024 21.333333 21.333333 241.024 21.333333 512S241.024 1002.666667 512 1002.666667 1002.666667 782.976 1002.666667 512 782.976 21.333333 512 21.333333z m297.685333 697.856L304.810667 214.314667a362.666667 362.666667 0 0 1 504.874666 504.874666zM149.333333 512c0-77.056 24.021333-148.48 64.981334-207.189333l504.874666 504.874666A362.666667 362.666667 0 0 1 149.333333 512z',
fill: 'currentColor',
}),
],
),
])
},
},
// 动态加载的图标
...dynamicIcons,
}

View File

@ -2,12 +2,14 @@
<el-card shadow="hover" class="card-box" @mouseenter="cardEnter()" @mouseleave="cardLeave()">
<div class="card-header">
<slot name="header">
<div class="title flex align-center" :class="$slots.subTitle ? 'mt-4' : ''">
<slot name="icon">
<el-avatar v-if="showIcon" class="mr-12 avatar-blue" shape="square" :size="32">
<img src="@/assets/knowledge/icon_document.svg" style="width: 58%" alt="" />
</el-avatar>
</slot>
<div class="title flex align-center">
<div class="mr-12 flex align-center" v-if="showIcon">
<slot name="icon">
<el-avatar shape="square" :size="32" class="avatar-blue">
<img src="@/assets/knowledge/icon_document.svg" style="width: 58%" alt="" />
</el-avatar>
</slot>
</div>
<div style="width: 90%">
<slot name="title">
<div>
@ -21,16 +23,19 @@
</div>
<div class="description break-all mt-12">
<slot>
<div class="content">
<div class="content color-secondary">
{{ description }}
</div>
</slot>
</div>
<div @mouseenter="subHoveredEnter">
<slot name="mouseEnter" v-if="$slots.mouseEnter && show" />
</div>
<div class="card-footer" v-if="$slots.footer">
<slot name="footer" />
<div class="card-footer flex-between" v-if="$slots.footer || $slots.mouseEnter">
<div>
<slot name="footer"></slot>
</div>
<div @mouseenter="subHoveredEnter">
<slot name="mouseEnter" v-if="$slots.mouseEnter && show" />
</div>
</div>
</el-card>
</template>
@ -80,11 +85,12 @@ function subHoveredEnter() {
min-width: var(--card-min-width);
border-radius: 8px;
.card-header {
margin-top: -10px;
margin-top: -5px;
}
.description {
line-height: 22px;
font-weight: 400;
min-height: 70px;
.content {
display: -webkit-box;
height: var(--app-card-box-description-height, 40px);
@ -96,7 +102,7 @@ function subHoveredEnter() {
.card-footer {
position: absolute;
bottom: 4px;
bottom: 8px;
left: 0;
min-height: 30px;
font-weight: 400;

View File

@ -55,7 +55,7 @@ const option_list = computed(() => {
border-radius: 4px;
font-weight: 400;
font-size: 14px;
color: #1f2329;
color: var(--el-text-color-primary);
padding: 3px 4px;
box-sizing: border-box;
white-space: nowrap;

View File

@ -193,7 +193,7 @@ const activeText = computed(() => {
justify-content: space-between;
margin-bottom: 16px;
.title {
color: #1f2329;
color: var(--el-text-color-primary);
font-weight: 400;
font-size: 14px;
line-height: 22px;

View File

@ -181,7 +181,7 @@ const activeText = computed(() => {
justify-content: space-between;
margin-bottom: 16px;
.title {
color: #1f2329;
color: var(--el-text-color-primary);
font-weight: 400;
font-size: 14px;
line-height: 22px;

View File

@ -44,12 +44,14 @@ export default {
document: 'Documents',
image: 'Image',
audio: 'Audio',
video: 'Video'
video: 'Video',
},
status: {
label: 'Status',
enabled: 'Enabled',
disabled: 'Disabled',
enableSuccess: 'Successful',
disableSuccess: 'Successful'
disableSuccess: 'Successful',
},
param: {
outputParam: 'Output Parameters',
@ -60,5 +62,5 @@ export default {
inputPlaceholder: 'Please input',
title: 'Title',
content: 'Content',
rename: 'Rename'
rename: 'Rename',
}

View File

@ -52,8 +52,10 @@ export default {
},
status: {
label: '状态',
enabled: '已启用',
disabled: '已禁用',
enableSuccess: '启用成功',
disableSuccess: '禁用成功'
disableSuccess: '禁用成功',
},
inputPlaceholder: '请输入',
title: '标题',
@ -61,7 +63,7 @@ export default {
param: {
outputParam: '输出参数',
inputParam: '输入参数',
initParam: '启动参数'
initParam: '启动参数',
},
rename: '重命名'
rename: '重命名',
}

View File

@ -44,12 +44,14 @@ export default {
document: '文檔',
image: '圖片',
audio: '音頻',
video: '視頻'
video: '視頻',
},
status: {
label: '狀態',
enabled: '已啟用',
disabled: '已停用',
enableSuccess: '啟用成功',
disableSuccess: '停用成功'
disableSuccess: '停用成功',
},
inputPlaceholder: '請輸入',
title: '標題',
@ -59,5 +61,5 @@ export default {
inputParam: '輸入參數',
initParam: '啟動參數',
},
rename: '重命名'
rename: '重命名',
}

View File

@ -386,6 +386,9 @@ h5 {
.color-secondary {
color: var(--app-text-color-secondary);
}
.color-success {
color: var(--el-color-success);
}
.avatar-purple {
background: #7f3bf5;
}

View File

@ -6,7 +6,6 @@ $primary-color: #3370ff;
// --el-menu-item-height: 45px;
// --el-box-shadow-light: 0px 2px 4px 0px rgba(31, 35, 41, 0.12);
// --el-border-color: #dee0e3;
// --el-text-color-regular: #1f2329;
// --el-color-info: #8f959e !important;
// --el-disabled-bg-color: #eff0f1 !important;
@ -79,19 +78,20 @@ $primary-color: #3370ff;
// dropdown
.el-dropdown {
color: var(--app-text-color);
color: var(--el-text-color-primary);
}
.el-dropdown-menu__item {
color: var(--app-text-color);
color: var(--el-text-color-primary);
font-weight: 400;
padding: 5px 11px;
min-width: 80px;
i {
margin-right: 8px;
}
&:not(.is-disabled):focus,
&:not(.is-active):focus {
background-color: var(--app-text-color-light-1);
color: var(--app-text-color);
color: var(--el-text-color-primary);
}
&.is-active,
&.is-active:hover {

View File

@ -1,7 +1,7 @@
<template>
<card-box :title="model.name" shadow="hover" class="model-card">
<template #icon>
<span style="height: 32px; width: 32px" :innerHTML="icon" class="mr-12"></span>
<span style="height: 32px; width: 32px" :innerHTML="icon"></span>
</template>
<template #title>
<div class="flex" style="height: 22px">
@ -23,12 +23,12 @@
</div>
</template>
<template #subTitle>
<el-text class="color-secondary" size="small">
<el-text class="color-secondary lighter" size="small">
{{ $t('common.creator') }}: {{ model.username }}
</el-text>
</template>
<ul>
<li class="flex">
<li class="flex mb-4">
<el-text type="info" class="color-secondary">{{
$t('views.model.modelForm.model_type.label')
}}</el-text>
@ -63,48 +63,46 @@
</div>
<template #mouseEnter>
<div class="operation-button">
<el-dropdown trigger="click">
<el-button text @click.stop>
<el-icon><MoreFilled /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
icon="EditPen"
:disabled="!is_permisstion"
text
@click.stop="openEditModel"
>
{{ $t('common.modify') }}
</el-dropdown-item>
<el-dropdown trigger="click">
<el-button text @click.stop>
<el-icon><MoreFilled /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
icon="EditPen"
:disabled="!is_permisstion"
text
@click.stop="openEditModel"
>
{{ $t('common.modify') }}
</el-dropdown-item>
<el-dropdown-item
v-if="
currentModel.model_type === 'TTS' ||
currentModel.model_type === 'LLM' ||
currentModel.model_type === 'IMAGE' ||
currentModel.model_type === 'TTI'
"
:disabled="!is_permisstion"
icon="Setting"
@click.stop="openParamSetting"
>
{{ $t('views.model.modelForm.title.paramSetting') }}
</el-dropdown-item>
<el-dropdown-item
divided
icon="Delete"
:disabled="!is_permisstion"
text
@click.stop="deleteModel"
>
{{ $t('common.delete') }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<el-dropdown-item
v-if="
currentModel.model_type === 'TTS' ||
currentModel.model_type === 'LLM' ||
currentModel.model_type === 'IMAGE' ||
currentModel.model_type === 'TTI'
"
:disabled="!is_permisstion"
icon="Setting"
@click.stop="openParamSetting"
>
{{ $t('views.model.modelForm.title.paramSetting') }}
</el-dropdown-item>
<el-dropdown-item
divided
icon="Delete"
:disabled="!is_permisstion"
text
@click.stop="deleteModel"
>
{{ $t('common.delete') }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<EditModel ref="editModelRef" @submit="emit('change')"></EditModel>
<ParamSettingDialog ref="paramSettingRef" :model="model" />

View File

@ -96,7 +96,7 @@ import { modelTypeList, allObj } from '@/views/model/component/data'
const props = defineProps<{
data: Array<Provider>
loading: boolean
active: Provider
active?: Provider
}>()
const emit = defineEmits(['click'])

View File

@ -0,0 +1,88 @@
<template>
<el-dialog
:title="$t('views.functionLib.functionForm.form.functionName.name')"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
append-to-body
width="450"
>
<el-form
label-position="top"
ref="fieldFormRef"
:rules="rules"
:model="form"
require-asterisk-position="right"
>
<el-form-item prop="name">
<el-input v-model="form.name" maxlength="64" show-word-limit></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit(fieldFormRef)" :loading="loading">
{{ isEdit ? $t('common.save') : $t('common.add') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
import type { FormInstance } from 'element-plus'
import { cloneDeep } from 'lodash'
import { t } from '@/locales'
const emit = defineEmits(['refresh'])
const fieldFormRef = ref()
const loading = ref<boolean>(false)
const isEdit = ref<boolean>(false)
const form = ref<any>({
name: ''
})
const rules = reactive({
name: [
{
required: true,
message: t('views.functionLib.functionForm.form.functionName.placeholder'),
trigger: 'blur'
}
]
})
const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => {
if (!bool) {
form.value = {
name: ''
}
}
})
const open = (row: any, edit: boolean) => {
if (row) {
form.value = cloneDeep(row)
}
isEdit.value = edit || false
dialogVisible.value = true
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
emit('refresh', form.value, isEdit.value)
dialogVisible.value = false
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,127 @@
<template>
<el-dialog
:title="`Logo ${$t('common.setting')}`"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
width="550"
>
<el-radio-group v-model="radioType" class="radio-block mb-16">
<el-radio value="default">
<p>{{ $t('views.applicationOverview.appInfo.EditAvatarDialog.default') }}</p>
<AppAvatar
v-if="detail?.name"
:name="detail?.name"
pinyinColor
class="mt-8 mb-8"
shape="square"
:size="32"
/>
</el-radio>
<el-radio value="custom">
<p>{{ $t('views.applicationOverview.appInfo.EditAvatarDialog.customizeUpload') }}</p>
<div class="flex mt-8">
<AppAvatar
v-if="fileURL"
shape="square"
:size="32"
style="background: none"
class="mr-16"
>
<img :src="fileURL" alt="" />
</AppAvatar>
<el-upload
ref="uploadRef"
action="#"
:auto-upload="false"
:show-file-list="false"
accept="image/jpeg, image/png, image/gif"
:on-change="onChange"
>
<el-button icon="Upload" :disabled="radioType !== 'custom'"
>{{ $t('views.applicationOverview.appInfo.EditAvatarDialog.upload') }}
</el-button>
</el-upload>
</div>
<div class="el-upload__tip info mt-8">
{{ $t('views.applicationOverview.appInfo.EditAvatarDialog.sizeTip') }}
</div>
</el-radio>
</el-radio-group>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="submit" :loading="loading">
{{ $t('common.save') }}</el-button
>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import functionLibApi from '@/api/function-lib'
import { cloneDeep } from 'lodash'
import { MsgError, MsgSuccess } from '@/utils/message'
import { defaultIcon, isAppIcon } from '@/utils/application'
import { t } from '@/locales'
const emit = defineEmits(['refresh'])
const iconFile = ref<any>(null)
const fileURL = ref<any>(null)
const dialogVisible = ref<boolean>(false)
const loading = ref(false)
const detail = ref<any>(null)
const radioType = ref('default')
watch(dialogVisible, (bool) => {
if (!bool) {
iconFile.value = null
fileURL.value = null
}
})
const open = (data: any) => {
radioType.value = isAppIcon(data.icon) ? 'custom' : 'default'
fileURL.value = isAppIcon(data.icon) ? data.icon : null
detail.value = cloneDeep(data)
dialogVisible.value = true
}
const onChange = (file: any) => {
//110MB
const isLimit = file?.size / 1024 / 1024 < 10
if (!isLimit) {
// @ts-ignore
MsgError(t('views.applicationOverview.appInfo.EditAvatarDialog.fileSizeExceeded'))
return false
} else {
iconFile.value = file
fileURL.value = URL.createObjectURL(file.raw)
}
}
function submit() {
if (radioType.value === 'default') {
emit('refresh', '/ui/favicon.ico')
dialogVisible.value = false
} else if (radioType.value === 'custom' && iconFile.value) {
let fd = new FormData()
fd.append('file', iconFile.value.raw)
functionLibApi.putFunctionLibIcon(detail.value.id, fd, loading).then((res: any) => {
emit('refresh', res.data)
dialogVisible.value = false
})
} else {
MsgError(t('views.applicationOverview.appInfo.EditAvatarDialog.uploadImagePrompt'))
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,129 @@
<template>
<el-dialog
:title="
isEdit
? $t('views.template.templateForm.title.editParam')
: $t('views.template.templateForm.title.addParam')
"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
append-to-body
>
<el-form
label-position="top"
ref="fieldFormRef"
:rules="rules"
:model="form"
require-asterisk-position="right"
>
<el-form-item :label="$t('views.functionLib.functionForm.form.paramName.label')" prop="name">
<el-input
v-model="form.name"
:placeholder="$t('views.functionLib.functionForm.form.paramName.placeholder')"
maxlength="64"
show-word-limit
@blur="form.name = form.name.trim()"
/>
</el-form-item>
<el-form-item :label="$t('views.functionLib.functionForm.form.dataType.label')">
<el-select v-model="form.type">
<el-option v-for="item in typeOptions" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item :label="$t('views.functionLib.functionForm.form.source.label')">
<el-select v-model="form.source">
<el-option
:label="$t('views.functionLib.functionForm.form.source.reference')"
value="reference"
/>
<el-option
:label="$t('views.functionLib.functionForm.form.source.custom')"
value="custom"
/>
</el-select>
</el-form-item>
<el-form-item
:label="$t('views.functionLib.functionForm.form.required.label')"
@click.prevent
>
<el-switch size="small" v-model="form.is_required"></el-switch>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit(fieldFormRef)" :loading="loading">
{{ isEdit ? $t('common.save') : $t('common.add') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import type { FormInstance } from 'element-plus'
import { cloneDeep } from 'lodash'
import { t } from '@/locales'
const typeOptions = ['string', 'int', 'dict', 'array', 'float']
const emit = defineEmits(['refresh'])
const fieldFormRef = ref()
const loading = ref<boolean>(false)
const isEdit = ref(false)
const form = ref<any>({
name: '',
type: typeOptions[0],
source: 'reference',
is_required: true
})
const rules = reactive({
name: [
{
required: true,
message: t('views.functionLib.functionForm.form.paramName.placeholder'),
trigger: 'blur'
}
]
})
const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => {
if (!bool) {
form.value = {
name: '',
type: typeOptions[0],
source: 'reference',
is_required: true
}
isEdit.value = false
}
})
const open = (row: any) => {
if (row) {
form.value = cloneDeep(row)
isEdit.value = true
}
dialogVisible.value = true
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
emit('refresh', form.value)
dialogVisible.value = false
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,184 @@
<template>
<el-drawer v-model="debugVisible" size="60%" :append-to-body="true">
<template #header>
<div class="flex align-center" style="margin-left: -8px">
<el-button class="cursor mr-4" link @click.prevent="debugVisible = false">
<el-icon :size="20">
<Back />
</el-icon>
</el-button>
<h4>{{ $t('common.debug') }}</h4>
</div>
</template>
<div>
<div v-if="form.init_field_list.length > 0">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.param.initParam') }}
</h4>
<el-card shadow="never" class="card-never" style="--el-card-padding: 12px">
<DynamicsForm
v-model="form.init_params"
:model="form.init_params"
label-position="top"
require-asterisk-position="right"
:render_data="form.init_field_list"
ref="dynamicsFormRef"
>
</DynamicsForm>
</el-card>
</div>
<div v-if="form.debug_field_list.length > 0" class="mb-16">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.param.inputParam') }}
</h4>
<el-card shadow="never" class="card-never" style="--el-card-padding: 12px">
<el-form
ref="FormRef"
:model="form"
label-position="top"
require-asterisk-position="right"
hide-required-asterisk
v-loading="loading"
@submit.prevent
>
<template v-for="(item, index) in form.debug_field_list" :key="index">
<el-form-item
:label="item.name"
:prop="'debug_field_list.' + index + '.value'"
:rules="{
required: item.is_required,
message: $t('views.functionLib.functionForm.form.param.inputPlaceholder'),
trigger: 'blur'
}"
>
<template #label>
<div class="flex">
<span
>{{ item.name }} <span class="danger" v-if="item.is_required">*</span></span
>
<el-tag type="info" class="info-tag ml-4">{{ item.type }}</el-tag>
</div>
</template>
<el-input
v-model="item.value"
:placeholder="$t('views.functionLib.functionForm.form.param.inputPlaceholder')"
/>
</el-form-item>
</template>
</el-form>
</el-card>
</div>
<el-button type="primary" @click="submit(FormRef)" :loading="loading">
{{ $t('views.functionLib.functionForm.form.debug.run') }}
</el-button>
<div v-if="showResult" class="mt-8">
<h4 class="title-decoration-1 mb-16 mt-16">
{{ $t('views.functionLib.functionForm.form.debug.runResult') }}
</h4>
<div class="mb-16">
<el-alert
v-if="isSuccess"
:title="$t('views.functionLib.functionForm.form.debug.runSuccess')"
type="success"
show-icon
:closable="false"
/>
<el-alert
v-else
:title="$t('views.functionLib.functionForm.form.debug.runFailed')"
type="error"
show-icon
:closable="false"
/>
</div>
<p class="lighter mb-8">{{ $t('views.functionLib.functionForm.form.debug.output') }}</p>
<el-card
:class="isSuccess ? '' : 'danger'"
class="pre-wrap"
shadow="never"
style="max-height: 350px; overflow: scroll"
>
{{ String(result) == '0' ? 0 : result || '-' }}
</el-card>
</div>
</div>
</el-drawer>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import functionLibApi from '@/api/function-lib'
import type { FormInstance } from 'element-plus'
import DynamicsForm from '@/components/dynamics-form/index.vue'
const FormRef = ref()
const dynamicsFormRef = ref()
const loading = ref(false)
const debugVisible = ref(false)
const showResult = ref(false)
const isSuccess = ref(false)
const result = ref('')
const form = ref<any>({
debug_field_list: [],
code: '',
input_field_list: [],
init_field_list: [],
init_params: {}
})
watch(debugVisible, (bool) => {
if (!bool) {
showResult.value = false
isSuccess.value = false
result.value = ''
form.value = {
debug_field_list: [],
code: '',
input_field_list: [],
init_field_list: [],
init_params: {}
}
}
})
const submit = async (formEl: FormInstance | undefined) => {
const validate = formEl ? formEl.validate() : Promise.resolve()
Promise.all([dynamicsFormRef.value?.validate(), validate]).then(() => {
functionLibApi.postFunctionLibDebug(form.value, loading).then((res) => {
if (res.code === 500) {
showResult.value = true
isSuccess.value = false
result.value = res.message
} else {
showResult.value = true
isSuccess.value = true
result.value = res.data
}
})
})
}
const open = (data: any) => {
if (data.input_field_list.length > 0) {
data.input_field_list.forEach((item: any) => {
form.value.debug_field_list.push({
value: '',
...item
})
})
}
form.value.code = data.code
form.value.input_field_list = data.input_field_list
form.value.init_field_list = data.init_field_list
debugVisible.value = true
}
defineExpose({
open
})
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,518 @@
<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">
{{ $t('views.functionLib.functionForm.title.baseInfo') }}
</h4>
<el-form
ref="FormRef"
:model="form"
:rules="rules"
label-position="top"
require-asterisk-position="right"
v-loading="loading"
@submit.prevent
>
<el-form-item
:label="$t('views.functionLib.functionForm.form.functionName.label')"
prop="name"
>
<div class="flex w-full">
<div
v-if="form.id"
class="edit-avatar mr-12"
@mouseenter="showEditIcon = true"
@mouseleave="showEditIcon = false"
>
<AppAvatar
v-if="isAppIcon(form.icon)"
:id="form.id"
shape="square"
:size="32"
style="background: none"
>
<img :src="String(form.icon)" alt="" />
</AppAvatar>
<AppAvatar
v-else-if="form.name"
:id="form.id"
:name="form.name"
pinyinColor
shape="square"
:size="32"
/>
<AppAvatar
v-if="showEditIcon"
:id="form.id"
shape="square"
class="edit-mask"
:size="32"
@click="openEditAvatar"
>
<el-icon><EditPen /></el-icon>
</AppAvatar>
</div>
<AppAvatar shape="square" style="background: #34c724" class="mr-12" v-else>
<img src="@/assets/icon_function_outlined.svg" style="width: 75%" alt="" />
</AppAvatar>
<el-input
v-model="form.name"
:placeholder="$t('views.functionLib.functionForm.form.functionName.placeholder')"
maxlength="64"
show-word-limit
@blur="form.name = form.name?.trim()"
/>
</div>
</el-form-item>
<el-form-item :label="$t('views.functionLib.functionForm.form.functionDescription.label')">
<el-input
v-model="form.desc"
type="textarea"
:placeholder="$t('views.functionLib.functionForm.form.functionDescription.placeholder')"
maxlength="128"
show-word-limit
:autosize="{ minRows: 3 }"
@blur="form.desc = form.desc?.trim()"
/>
</el-form-item>
<!--
<el-form-item prop="permission_type">
<template #label>
<span>{{ $t('views.functionLib.functionForm.form.permission_type.label') }}</span>
</template>
<el-radio-group v-model="form.permission_type" class="card__radio">
<el-row :gutter="16">
<template v-for="(value, key) of PermissionType" :key="key">
<el-col :span="12">
<el-card
shadow="never"
class="mb-16"
:class="form.permission_type === key ? 'active' : ''"
>
<el-radio :value="key" size="large">
<p class="mb-4">{{ $t(value) }}</p>
<el-text type="info">
{{ $t(PermissionDesc[key]) }}
</el-text>
</el-radio>
</el-card>
</el-col>
</template>
</el-row>
</el-radio-group>
</el-form-item>
-->
</el-form>
<div class="flex-between">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.param.initParam') }}
</h4>
<el-button link type="primary" @click="openAddInitDialog()">
<el-icon class="mr-4"><Plus /></el-icon> {{ $t('common.add') }}
</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 }">
<el-tag type="info" class="info-tag" v-if="row.input_type === 'TextInput'">{{
$t('dynamicsForm.input_type_list.TextInput')
}}</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'PasswordInput'">{{
$t('dynamicsForm.input_type_list.PasswordInput')
}}</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'Slider'">{{
$t('dynamicsForm.input_type_list.Slider')
}}</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'SwitchInput'">{{
$t('dynamicsForm.input_type_list.SwitchInput')
}}</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'SingleSelect'">{{
$t('dynamicsForm.input_type_list.SingleSelect')
}}</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'MultiSelect'">{{
$t('dynamicsForm.input_type_list.MultiSelect')
}}</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'RadioCard'">{{
$t('dynamicsForm.input_type_list.RadioCard')
}}</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'DatePicker'">{{
$t('dynamicsForm.input_type_list.DatePicker')
}}</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('common.required')">
<template #default="{ row }">
<div @click.stop>
<el-switch disabled size="small" v-model="row.required" />
</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)">
<el-icon><EditPen /></el-icon>
</el-button>
</el-tooltip>
</span>
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
<el-button type="primary" text @click="deleteInitField($index)">
<el-icon>
<Delete />
</el-icon>
</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">
{{ $t('views.functionLib.functionForm.form.param.paramInfo1') }}
</el-text>
</h4>
<el-button link type="primary" @click="openAddDialog()">
<el-icon class="mr-4"><Plus /></el-icon> {{ $t('common.add') }}
</el-button>
</div>
<el-table ref="inputFieldTableRef" :data="form.input_field_list" class="mb-16">
<el-table-column
prop="name"
:label="$t('views.functionLib.functionForm.form.paramName.label')"
/>
<el-table-column :label="$t('views.functionLib.functionForm.form.dataType.label')">
<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>
<el-switch size="small" v-model="row.is_required" />
</div>
</template>
</el-table-column>
<el-table-column
prop="source"
:label="$t('views.functionLib.functionForm.form.source.label')"
>
<template #default="{ row }">
{{
row.source === 'custom'
? $t('views.functionLib.functionForm.form.source.custom')
: $t('views.functionLib.functionForm.form.source.reference')
}}
</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)">
<el-icon><EditPen /></el-icon>
</el-button>
</el-tooltip>
</span>
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
<el-button type="primary" text @click="deleteField($index)">
<el-icon>
<Delete />
</el-icon>
</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<h4 class="title-decoration-1 mb-16">
{{ $t('views.functionLib.functionForm.form.param.code') }}
<span style="color: red; margin-left: -10px">*</span>
<el-text type="info" class="color-secondary">
{{ $t('views.functionLib.functionForm.form.param.paramInfo2') }}
</el-text>
</h4>
<div class="mb-8" v-if="showEditor">
<CodemirrorEditor
:title="$t('views.functionLib.functionForm.form.param.code')"
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">
{{ $t('views.functionLib.functionForm.form.param.paramInfo1') }}
</el-text>
</h4>
<div class="flex-between border-r-4 p-8-12 mb-8 layout-bg lighter">
<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">{{ $t('common.debug') }}</el-button>
<el-button type="primary" @click="submit(FormRef)" :loading="loading">
{{ isEdit ? $t('common.save') : $t('common.create') }}</el-button
>
</div>
</template>
<FunctionDebugDrawer ref="FunctionDebugDrawerRef" />
<FieldFormDialog ref="FieldFormDialogRef" @refresh="refreshFieldList" />
<UserFieldFormDialog ref="UserFieldFormDialogRef" @refresh="refreshInitFieldList" />
<EditAvatarDialog ref="EditAvatarDialogRef" @refresh="refreshFunctionLib" />
</el-drawer>
</template>
<script setup lang="ts">
import { ref, reactive, watch, nextTick } from 'vue'
import FieldFormDialog from './FieldFormDialog.vue'
import FunctionDebugDrawer from './FunctionDebugDrawer.vue'
import type { functionLibData } from '@/api/type/function-lib'
import functionLibApi from '@/api/function-lib'
import type { FormInstance } from 'element-plus'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { cloneDeep } from 'lodash'
import { PermissionType, PermissionDesc } from '@/enums/model'
import { t } from '@/locales'
import UserFieldFormDialog from '@/workflow/nodes/base-node/component/UserFieldFormDialog.vue'
import { isAppIcon } from '@/utils/application'
import EditAvatarDialog from './EditAvatarDialog.vue'
import Sortable from 'sortablejs'
const props = defineProps({
title: String
})
const emit = defineEmits(['refresh'])
const FieldFormDialogRef = ref()
const FunctionDebugDrawerRef = ref()
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)
const form = ref<functionLibData>({
name: '',
desc: '',
code: '',
icon: '',
input_field_list: [],
init_field_list: [],
permission_type: 'PRIVATE'
})
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: [],
permission_type: 'PRIVATE'
}
FormRef.value?.clearValidate()
}
})
const rules = reactive({
name: [
{
required: true,
message: t('views.functionLib.functionForm.form.functionName.requiredMessage'),
trigger: 'blur'
}
],
permission_type: [
{
required: true,
message: t('views.functionLib.functionForm.form.permission_type.requiredMessage'),
trigger: 'change'
}
]
})
function onDragHandle() {
// For init_field_list table
if (initFieldTableRef.value) {
const el = initFieldTableRef.value.$el.querySelector('.el-table__body-wrapper tbody')
Sortable.create(el, {
animation: 150,
ghostClass: 'sortable-ghost',
onEnd: ({ newIndex, oldIndex }) => {
if (newIndex === undefined || oldIndex === undefined) return
if (newIndex !== oldIndex) {
const item = form.value.init_field_list?.splice(oldIndex, 1)[0]
form.value.init_field_list?.splice(newIndex, 0, item)
}
}
})
}
// For input_field_list table
if (inputFieldTableRef.value) {
const el = inputFieldTableRef.value.$el.querySelector('.el-table__body-wrapper tbody')
Sortable.create(el, {
animation: 150,
ghostClass: 'sortable-ghost',
onEnd: ({ newIndex, oldIndex }) => {
if (newIndex === undefined || oldIndex === undefined) return
if (newIndex !== oldIndex) {
const item = form.value.input_field_list?.splice(oldIndex, 1)[0]
form.value.input_field_list?.splice(newIndex, 0, item)
}
}
})
}
}
function submitCodemirrorEditor(val: string) {
form.value.code = val
}
function close() {
if (isEdit.value || !areAllValuesNonEmpty(form.value)) {
visible.value = false
} else {
MsgConfirm(t('common.tip'), t('views.functionLib.tip.saveMessage'), {
confirmButtonText: t('common.confirm'),
type: 'warning'
})
.then(() => {
visible.value = false
})
.catch(() => {})
}
}
function areAllValuesNonEmpty(obj: any) {
return Object.values(obj).some((value) => {
return Array.isArray(value)
? value.length !== 0
: value !== null && value !== undefined && value !== ''
})
}
function openDebug() {
FunctionDebugDrawerRef.value.open(form.value)
}
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()
}
function refreshFunctionLib(data: any) {
form.value.icon = data
// console.log(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) {
// console.log(form.value)
if (isEdit.value) {
functionLibApi.putFunctionLib(form.value?.id as string, form.value, loading).then((res) => {
MsgSuccess(t('common.editSuccess'))
emit('refresh', res.data)
visible.value = false
})
} else {
functionLibApi.postFunctionLib(form.value, loading).then((res) => {
MsgSuccess(t('common.createSuccess'))
emit('refresh')
visible.value = false
})
}
}
})
}
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({
open
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,94 @@
<template>
<el-drawer v-model="debugVisible" size="60%" :append-to-body="true">
<template #header>
<div class="flex align-center" style="margin-left: -8px">
<el-button class="cursor mr-4" link @click.prevent="debugVisible = false">
<el-icon :size="20">
<Back />
</el-icon>
</el-button>
<h4>{{ $t('common.param.initParam') }}</h4>
</div>
</template>
<div>
<div v-if="form.init_field_list?.length > 0">
<DynamicsForm
v-model="form.init_params"
:model="form.init_params"
label-position="top"
require-asterisk-position="right"
:render_data="form.init_field_list"
ref="dynamicsFormRef"
>
</DynamicsForm>
</div>
</div>
<template #footer>
<div>
<el-button type="primary" @click="submit()" :loading="loading">
{{ $t('common.save') }}
</el-button>
</div>
</template>
</el-drawer>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import ToolApi from '@/api/tool/tool'
import DynamicsForm from '@/components/dynamics-form/index.vue'
import { MsgSuccess } from '@/utils/message'
import { t } from '@/locales'
import { cloneDeep } from 'lodash'
const emit = defineEmits(['refresh'])
const dynamicsFormRef = ref()
const loading = ref(false)
const debugVisible = ref(false)
const form = ref<any>({
init_params: {},
})
watch(debugVisible, (bool) => {
if (!bool) {
form.value = {
init_params: {},
is_active: false,
}
}
})
const submit = async () => {
dynamicsFormRef.value.validate().then(() => {
ToolApi.putToolLib('default', form.value?.id as string, form.value, loading).then((res) => {
MsgSuccess(t('common.editSuccess'))
emit('refresh')
debugVisible.value = false
})
})
}
const open = (data: any, is_active: boolean) => {
if (data) {
form.value = cloneDeep(data)
form.value.is_active = is_active
}
const init_params = form.value.init_field_list
.map((item: any) => {
if (item.show_default_value === false) {
return { [item.field]: undefined }
}
return { [item.field]: item.default_value }
})
.reduce((x: any, y: any) => ({ ...x, ...y }), {})
form.value.init_params = { ...init_params, ...form.value.init_params }
debugVisible.value = true
}
defineExpose({
open,
})
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,100 @@
<template>
<el-drawer v-model="visibleInternalDesc" size="60%" :append-to-body="true">
<template #header>
<div class="flex align-center" style="margin-left: -8px">
<el-button class="cursor mr-4" link @click.prevent="visibleInternalDesc = false">
<el-icon :size="20">
<Back />
</el-icon>
</el-button>
<h4>详情</h4>
</div>
</template>
<div>
<div class="card-header">
<div class="flex-between">
<div class="title flex align-center">
<AppAvatar
v-if="isAppIcon(functionDetail?.icon)"
shape="square"
:size="64"
style="background: none"
class="mr-8"
>
<img :src="functionDetail?.icon" alt="" />
</AppAvatar>
<AppAvatar
v-else-if="functionDetail?.name"
:name="functionDetail?.name"
pinyinColor
shape="square"
:size="64"
class="mr-8"
/>
<div class="ml-16">
<h3 class="mb-8">{{ functionDetail.name }}</h3>
<el-text type="info" v-if="functionDetail?.desc">
{{ functionDetail.desc }}
</el-text>
</div>
</div>
<div @click.stop>
<el-button type="primary" @click="addInternalFunction(functionDetail)">
{{ $t('common.add') }}
</el-button>
</div>
</div>
<div class="mt-16">
<el-text type="info">
<div>{{ $t('common.author') }}: MaxKB</div>
</el-text>
</div>
</div>
<MdPreview
ref="editorRef"
editorId="preview-only"
:modelValue="markdownContent"
style="background: none"
noImgZoomIn
/>
</div>
</el-drawer>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { cloneDeep } from 'lodash'
import { isAppIcon } from '@/utils/application'
const emit = defineEmits(['refresh', 'addFunction'])
const visibleInternalDesc = ref(false)
const markdownContent = ref('')
const functionDetail = ref<any>({})
watch(visibleInternalDesc, (bool) => {
if (!bool) {
markdownContent.value = ''
}
})
const open = (data: any, detail: any) => {
functionDetail.value = detail
if (data) {
markdownContent.value = cloneDeep(data)
}
visibleInternalDesc.value = true
}
const addInternalFunction = (data: any) => {
emit('addFunction', data)
visibleInternalDesc.value = false
}
defineExpose({
open
})
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,106 @@
<template>
<el-dialog
:title="$t('views.functionLib.functionForm.form.permission_type.label')"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
append-to-body
width="450"
>
<el-form
label-position="top"
ref="fieldFormRef"
:rules="rules"
:model="form"
require-asterisk-position="right"
>
<el-radio-group v-model="form.permission_type" class="radio-block">
<el-radio value="PRIVATE" size="large">
{{ $t('common.private') }}
<el-text type="info">{{
$t('views.template.templateForm.form.permissionType.privateDesc')
}}</el-text>
</el-radio>
<el-radio value="PUBLIC" size="large">
{{ $t('common.public') }}
<el-text type="info">{{
$t('views.template.templateForm.form.permissionType.publicDesc')
}}</el-text>
</el-radio>
</el-radio-group>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit(fieldFormRef)" :loading="loading">
{{ isEdit ? $t('common.save') : $t('common.add') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
import type { FormInstance } from 'element-plus'
import { cloneDeep } from 'lodash'
import { t } from '@/locales'
import functionLibApi from '@/api/function-lib'
import { MsgSuccess } from '@/utils/message'
const emit = defineEmits(['refresh'])
const fieldFormRef = ref()
const loading = ref<boolean>(false)
const isEdit = ref(false)
const form = ref<any>({
permission_type: 'PRIVATE'
})
const rules = reactive({
permission_type: [
{
required: true,
message: t('views.functionLib.functionForm.form.paramName.placeholder'),
trigger: 'blur'
}
]
})
const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => {
if (!bool) {
form.value = {
permission_type: 'PRIVATE'
}
isEdit.value = false
}
})
const open = (row: any) => {
if (row) {
form.value = cloneDeep(row)
isEdit.value = true
}
dialogVisible.value = true
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
functionLibApi.putFunctionLib(form.value?.id as string, form.value, loading).then((res) => {
MsgSuccess(t('common.editSuccess'))
emit('refresh')
dialogVisible.value = false
})
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -48,22 +48,111 @@
</template>
<div>
<el-row v-if="toolList.length > 0" :gutter="15">
<el-row v-if="toolFolderList.length > 0 || toolList.length > 0" :gutter="15">
<template v-for="(item, index) in toolFolderList" :key="index">
<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="6" class="mb-16">
<CardBox
:title="item.name"
:description="item.desc || $t('common.noData')"
class="cursor"
>
<template #icon>
<el-avatar shape="square" :size="32" style="background: none">
<AppIcon iconName="app-folder" style="font-size: 32px"></AppIcon>
</el-avatar>
</template>
<template #subTitle>
<el-text class="color-secondary lighter" size="small">
{{ $t('common.creator') }}: {{ item.username }}
</el-text>
</template>
</CardBox>
</el-col>
</template>
<template v-for="(item, index) in toolList" :key="index">
<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="6" class="mb-16">
<CardBox :title="item.name" :description="item.desc" class="cursor">
<template #icon>
<el-avatar class="mr-8 avatar-green" shape="square" :size="32">
<el-avatar class="avatar-green" shape="square" :size="32">
<img src="@/assets/node/icon_tool.svg" style="width: 58%" alt="" />
</el-avatar>
</template>
<template #subTitle>
<el-text class="color-secondary" size="small">
<auto-tooltip :content="item.username">
{{ $t('common.creator') }}: {{ item.username }}
</auto-tooltip>
<el-text class="color-secondary lighter" size="small">
{{ $t('common.creator') }}: {{ item.username }}
</el-text>
</template>
<template #footer>
<div v-if="item.is_active" class="flex align-center">
<el-icon class="color-success mr-8" style="font-size: 16px"
><SuccessFilled
/></el-icon>
<span class="color-secondary">
{{ $t('common.status.enabled') }}
</span>
</div>
<div v-else class="flex align-center">
<AppIcon iconName="app-disabled" class="color-secondary mr-8"></AppIcon>
<span class="color-secondary">
{{ $t('common.status.disabled') }}
</span>
</div>
</template>
<template #mouseEnter>
<div @click.stop>
<el-switch
v-model="item.is_active"
:before-change="() => changeState(item)"
size="small"
class="mr-4"
/>
<el-divider direction="vertical" />
<el-dropdown trigger="click">
<el-button text @click.stop>
<el-icon><MoreFilled /></el-icon>
</el-button>
<!-- <template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
v-if="!item.template_id"
@click.stop="openCreateDialog(item)"
>
<el-icon><EditPen /></el-icon>
{{ $t('common.edit') }}
</el-dropdown-item>
<el-dropdown-item
:disabled="item.permission_type === 'PUBLIC' && !canEdit(item)"
v-if="!item.template_id"
@click.stop="copyFunctionLib(item)"
>
<AppIcon iconName="app-copy"></AppIcon>
{{ $t('common.copy') }}
</el-dropdown-item>
<el-dropdown-item
v-if="item.init_field_list?.length > 0"
@click.stop="configInitParams(item)"
>
<AppIcon iconName="app-operation" class="mr-4"></AppIcon>
{{ $t('common.param.initParam') }}
</el-dropdown-item>
<el-dropdown-item
v-if="!item.template_id"
@click.stop="exportFunctionLib(item)"
>
<AppIcon iconName="app-export"></AppIcon>
{{ $t('common.export') }}
</el-dropdown-item>
<el-dropdown-item divided @click.stop="deleteFunctionLib(item)">
<el-icon><Delete /></el-icon>
{{ $t('common.delete') }}
</el-dropdown-item>
</el-dropdown-menu>
</template> -->
</el-dropdown>
</div>
</template>
</CardBox>
</el-col>
</template>
@ -71,6 +160,7 @@
<el-empty :description="$t('common.noData')" v-else />
</div>
</ContentContainer>
<InitParamDrawer ref="InitParamDrawerRef" @refresh="refresh" />
</LayoutContainer>
</template>
@ -78,11 +168,14 @@
import { onMounted, ref, reactive, computed } from 'vue'
import ToolApi from '@/api/tool/tool'
import useStore from '@/stores'
import { numberFormat } from '@/utils/common'
import { MsgConfirm } from '@/utils/message'
import InitParamDrawer from '@/views/tool/component/InitParamDrawer.vue'
import { t } from '@/locales'
const { folder } = useStore()
const InitParamDrawerRef = ref()
const search_type = ref('name')
const search_form = ref<{
name: string
@ -94,6 +187,7 @@ const search_form = ref<{
const user_options = ref<any[]>([])
const loading = ref(false)
const changeStateloading = ref(false)
const paginationConfig = reactive({
current_page: 1,
page_size: 30,
@ -102,6 +196,7 @@ const paginationConfig = reactive({
const folderList = ref<any[]>([])
const toolList = ref<any[]>([])
const toolFolderList = ref<any[]>([])
const currentFolder = ref<any>({})
const search_type_change = () => {
@ -114,8 +209,9 @@ function getList() {
tool_type: 'CUSTOM',
}
ToolApi.getToolList('default', paginationConfig, params, loading).then((res) => {
paginationConfig.total = res.data.total
toolList.value = [...toolList.value, ...res.data.records]
toolFolderList.value = res.data?.folders
paginationConfig.total = res.data?.tools.total
toolList.value = [...toolList.value, ...res.data?.tools.records]
})
}
@ -128,6 +224,61 @@ function getFolder() {
})
}
async function changeState(row: any) {
// if (!bool) {
// MsgConfirm(
// `${t('views.functionLib.disabled.confirmTitle')}${row.name} ?`,
// t('views.functionLib.disabled.confirmMessage'),
// {
// confirmButtonText: t('views.functionLib.setting.disabled'),
// confirmButtonClass: 'danger',
// },
// )
// .then(() => {
// const obj = {
// is_active: bool,
// }
// ToolApi.putToolLib('default', row.id, obj, changeStateloading).then((res) => {})
// })
// .catch(() => {
// row.is_active = true
// })
// } else {
// const res = await ToolApi.getToolById('default', row.id, changeStateloading)
// if (
// !res.data.init_params &&
// res.data.init_field_list &&
// res.data.init_field_list.length > 0 &&
// res.data.init_field_list.filter((item: any) => item.default_value && item.show_default_value)
// .length !== res.data.init_field_list.length
// ) {
// row.is_active = false
// InitParamDrawerRef.value.open(res.data, bool)
// return
// }
// const obj = {
// is_active: bool,
// }
// ToolApi.putToolLib('default', row.id, obj, changeStateloading).then((res) => {})
// }
}
function refresh(data: any) {
if (data) {
const index = toolList.value.findIndex((v) => v.id === data.id)
// if (user.userInfo && data.user_id === user.userInfo.id) {
// data.username = user.userInfo.username
// } else {
// data.username = userOptions.value.find((v) => v.value === data.user_id)?.label
// }
toolList.value.splice(index, 1, data)
}
paginationConfig.total = 0
paginationConfig.current_page = 1
toolList.value = []
getList()
}
function folderClickHandel(row: any) {
// currentFolder.value = row
// toolList.value = []