mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
This commit is contained in:
parent
ab46d7ab61
commit
69e35b36aa
|
|
@ -13,11 +13,14 @@
|
|||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/lang-json": "^6.0.1",
|
||||
"@codemirror/theme-one-dark": "^6.1.2",
|
||||
"axios": "^1.8.4",
|
||||
"element-plus": "^2.9.7",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.1",
|
||||
"vue": "^3.5.13",
|
||||
"vue-codemirror": "^6.1.1",
|
||||
"vue-i18n": "^11.1.3",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,209 @@
|
|||
import { request } from '../../request/index'
|
||||
import { Result } from '@/request/Result'
|
||||
import { get, post, del, put } from '@/request/index'
|
||||
import { type Ref } from 'vue'
|
||||
import type {
|
||||
modelRequest,
|
||||
Provider,
|
||||
ListModelRequest,
|
||||
Model,
|
||||
BaseModel,
|
||||
CreateModelRequest,
|
||||
EditModelRequest
|
||||
} from '@/api/type/model'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import type { KeyValue } from '../type/common'
|
||||
const prefix = '/model'
|
||||
const prefix_provider = '/provider'
|
||||
|
||||
/**
|
||||
* 获得模型列表
|
||||
* @params 参数 name, model_type, model_name
|
||||
*/
|
||||
const getModel: (
|
||||
request?: ListModelRequest,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Array<Model>>> = (data, loading) => {
|
||||
return get(`${prefix}`, data, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得供应商列表
|
||||
*/
|
||||
const getProvider: (loading?: Ref<boolean>) => Promise<Result<Array<Provider>>> = (loading) => {
|
||||
return get(`${prefix_provider}`, {}, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得供应商列表
|
||||
*/
|
||||
const getProviderByModelType: (model_type: string, loading?: Ref<boolean>) => Promise<Result<Array<Provider>>> = (model_type, loading) => {
|
||||
return get(`${prefix_provider}`, {model_type}, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型创建表单
|
||||
* @param provider
|
||||
* @param model_type
|
||||
* @param model_name
|
||||
* @param loading
|
||||
* @returns
|
||||
*/
|
||||
const getModelCreateForm: (
|
||||
provider: string,
|
||||
model_type: string,
|
||||
model_name: string,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Array<FormField>>> = (provider, model_type, model_name, loading) => {
|
||||
return get(`${prefix_provider}/model_form`, { provider, model_type, model_name }, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型参数表单
|
||||
* @param model_id 模型id
|
||||
* @param loading
|
||||
* @returns
|
||||
*/
|
||||
const getModelParamsForm: (
|
||||
model_id: string,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Array<FormField>>> = (model_id, loading) => {
|
||||
return get(`model/${model_id}/model_params_form`, {}, loading)
|
||||
}
|
||||
/**
|
||||
* 获取模型类型列表
|
||||
* @param provider 供应商
|
||||
* @param loading 加载器
|
||||
* @returns 模型类型列表
|
||||
*/
|
||||
const listModelType: (
|
||||
provider: string,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Array<KeyValue<string, string>>>> = (provider, loading?: Ref<boolean>) => {
|
||||
return get(`${prefix_provider}/model_type_list`, { provider }, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取基础模型列表
|
||||
* @param provider
|
||||
* @param model_type
|
||||
* @param loading
|
||||
* @returns
|
||||
*/
|
||||
const listBaseModel: (
|
||||
provider: string,
|
||||
model_type: string,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Array<BaseModel>>> = (provider, model_type, loading) => {
|
||||
return get(`${prefix_provider}/model_list`, { provider, model_type }, loading)
|
||||
}
|
||||
|
||||
const listBaseModelParamsForm: (
|
||||
provider: string,
|
||||
model_type: string,
|
||||
model_name: string,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Array<BaseModel>>> = (provider, model_type, model_name, loading) => {
|
||||
return get(`${prefix_provider}/model_params_form`, { provider, model_type, model_name}, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建模型
|
||||
* @param request 请求对象
|
||||
* @param loading 加载器
|
||||
* @returns
|
||||
*/
|
||||
const createModel: (
|
||||
request: CreateModelRequest,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Model>> = (request, loading) => {
|
||||
return post(`${prefix}`, request, {}, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改模型
|
||||
* @param request 請求對象
|
||||
* @param loading 加載器
|
||||
* @returns
|
||||
*/
|
||||
const updateModel: (
|
||||
model_id: string,
|
||||
request: EditModelRequest,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Model>> = (model_id, request, loading) => {
|
||||
return put(`${prefix}/${model_id}`, request, {}, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改模型参数配置
|
||||
* @param request 請求對象
|
||||
* @param loading 加載器
|
||||
* @returns
|
||||
*/
|
||||
const updateModelParamsForm: (
|
||||
model_id: string,
|
||||
request: any[],
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Model>> = (model_id, request, loading) => {
|
||||
return put(`${prefix}/${model_id}/model_params_form`, request, {}, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型详情根据模型id 包括认证信息
|
||||
* @param model_id 模型id
|
||||
* @param loading 加载器
|
||||
* @returns
|
||||
*/
|
||||
const getModelById: (model_id: string, loading?: Ref<boolean>) => Promise<Result<Model>> = (
|
||||
model_id,
|
||||
loading
|
||||
) => {
|
||||
return get(`${prefix}/${model_id}`, {}, loading)
|
||||
}
|
||||
/**
|
||||
* 获取模型信息不包括认证信息根据模型id
|
||||
* @param model_id 模型id
|
||||
* @param loading 加载器
|
||||
* @returns
|
||||
*/
|
||||
const getModelMetaById: (model_id: string, loading?: Ref<boolean>) => Promise<Result<Model>> = (
|
||||
model_id,
|
||||
loading
|
||||
) => {
|
||||
return get(`${prefix}/${model_id}/meta`, {}, loading)
|
||||
}
|
||||
/**
|
||||
* 暂停下载
|
||||
* @param model_id 模型id
|
||||
* @param loading 加载器
|
||||
* @returns
|
||||
*/
|
||||
const pauseDownload: (model_id: string, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
|
||||
model_id,
|
||||
loading
|
||||
) => {
|
||||
return put(`${prefix}/${model_id}/pause_download`, undefined, {}, loading)
|
||||
}
|
||||
const deleteModel: (model_id: string, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
|
||||
model_id,
|
||||
loading
|
||||
) => {
|
||||
return del(`${prefix}/${model_id}`, undefined, {}, loading)
|
||||
}
|
||||
export default {
|
||||
getModel,
|
||||
getProvider,
|
||||
getModelCreateForm,
|
||||
listModelType,
|
||||
listBaseModel,
|
||||
listBaseModelParamsForm,
|
||||
createModel,
|
||||
updateModel,
|
||||
deleteModel,
|
||||
getModelById,
|
||||
getModelMetaById,
|
||||
pauseDownload,
|
||||
getModelParamsForm,
|
||||
updateModelParamsForm,
|
||||
getProviderByModelType
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { Result } from '@/request/Result'
|
||||
import { get, post } from '@/request/index'
|
||||
import type { Ref } from 'vue'
|
||||
const trigger: (
|
||||
provider: string,
|
||||
method: string,
|
||||
request_body: any,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<Array<any> | string>> = (provider, method, request_body, loading) => {
|
||||
return post(`provider/${provider}/${method}`, {}, request_body, loading)
|
||||
}
|
||||
export default { trigger, get }
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
interface KeyValue<K, V> {
|
||||
key: K
|
||||
value: V
|
||||
}
|
||||
interface Dict<V> {
|
||||
[propName: string]: V
|
||||
}
|
||||
|
||||
interface pageRequest {
|
||||
current_page: number
|
||||
page_size: number
|
||||
}
|
||||
|
||||
export type { KeyValue, Dict, pageRequest }
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
import type { Dict } from './common'
|
||||
interface modelRequest {
|
||||
name: string
|
||||
model_type: string
|
||||
model_name: string
|
||||
}
|
||||
|
||||
interface Provider {
|
||||
/**
|
||||
* 供应商代号
|
||||
*/
|
||||
provider: string
|
||||
/**
|
||||
* 供应商名称
|
||||
*/
|
||||
name: string
|
||||
/**
|
||||
* 供应商icon
|
||||
*/
|
||||
icon: string
|
||||
}
|
||||
|
||||
interface ListModelRequest {
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
name?: string
|
||||
/**
|
||||
* 模型类型
|
||||
*/
|
||||
model_type?: string
|
||||
/**
|
||||
* 基础模型名称
|
||||
*/
|
||||
model_name?: string
|
||||
/**
|
||||
* 供应商
|
||||
*/
|
||||
provider?: string
|
||||
}
|
||||
|
||||
interface Model {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id: string
|
||||
/**
|
||||
* 模型名
|
||||
*/
|
||||
name: string
|
||||
/**
|
||||
* 模型类型
|
||||
*/
|
||||
model_type: string
|
||||
user_id: string
|
||||
username: string
|
||||
permission_type: 'PUBLIC' | 'PRIVATE'
|
||||
/**
|
||||
* 基础模型
|
||||
*/
|
||||
model_name: string
|
||||
/**
|
||||
* 认证信息
|
||||
*/
|
||||
credential: any
|
||||
/**
|
||||
* 供应商
|
||||
*/
|
||||
provider: string
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
status: 'SUCCESS' | 'DOWNLOAD' | 'ERROR' | 'PAUSE_DOWNLOAD'
|
||||
/**
|
||||
* 元数据
|
||||
*/
|
||||
meta: Dict<any>
|
||||
/**
|
||||
* 模型参数配置
|
||||
*/
|
||||
model_params_form: Dict<any>[]
|
||||
}
|
||||
interface CreateModelRequest {
|
||||
/**
|
||||
* 模型名
|
||||
*/
|
||||
name: string
|
||||
/**
|
||||
* 模型类型
|
||||
*/
|
||||
model_type: string
|
||||
/**
|
||||
* 基础模型
|
||||
*/
|
||||
model_name: string
|
||||
/**
|
||||
* 认证信息
|
||||
*/
|
||||
credential: any
|
||||
/**
|
||||
* 供应商
|
||||
*/
|
||||
provider: string
|
||||
}
|
||||
|
||||
interface EditModelRequest {
|
||||
/**
|
||||
* 模型名
|
||||
*/
|
||||
name: string
|
||||
/**
|
||||
* 模型类型
|
||||
*/
|
||||
model_type: string
|
||||
/**
|
||||
* 基础模型
|
||||
*/
|
||||
model_name: string
|
||||
/**
|
||||
* 认证信息
|
||||
*/
|
||||
credential: any
|
||||
}
|
||||
|
||||
interface BaseModel {
|
||||
/**
|
||||
* 基础模型名称
|
||||
*/
|
||||
name: string
|
||||
/**
|
||||
* 基础模型描述
|
||||
*/
|
||||
desc: string
|
||||
/**
|
||||
* 基础模型类型
|
||||
*/
|
||||
model_type: string
|
||||
}
|
||||
export type {
|
||||
modelRequest,
|
||||
Provider,
|
||||
ListModelRequest,
|
||||
Model,
|
||||
BaseModel,
|
||||
CreateModelRequest,
|
||||
EditModelRequest
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ interface User {
|
|||
* 用户名
|
||||
*/
|
||||
username: string
|
||||
nick_name: string
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
|
|
@ -14,7 +15,7 @@ interface User {
|
|||
/**
|
||||
* 用户角色
|
||||
*/
|
||||
role: string
|
||||
role: Array<string>
|
||||
/**
|
||||
* 用户权限
|
||||
*/
|
||||
|
|
@ -25,7 +26,7 @@ interface User {
|
|||
is_edit_password?: boolean
|
||||
IS_XPACK?: boolean
|
||||
XPACK_LICENSE_IS_VALID?: boolean
|
||||
language: string
|
||||
language?: string
|
||||
}
|
||||
|
||||
interface LoginRequest {
|
||||
|
|
@ -117,5 +118,5 @@ export type {
|
|||
CheckCodeRequest,
|
||||
ResetPasswordRequest,
|
||||
User,
|
||||
ResetCurrentUserPasswordRequest
|
||||
ResetCurrentUserPasswordRequest,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<svg width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 7.33333H4C2.15905 7.33333 0 8.62098 0 10.9333V12.7333C0 13.0647 0.298477 13.3333 0.666667 13.3333H11.3333C11.7015 13.3333 12 13.0647 12 12.7333V10.9333C12 8.61904 9.84095 7.33333 8 7.33333Z" fill="url(#paint0_linear_264_32130)"/>
|
||||
<path d="M2.66667 3.33333C2.66667 5.17428 4.15905 6.66667 6 6.66667C7.84095 6.66667 9.33333 5.17428 9.33333 3.33333C9.33333 1.49238 7.84095 0 6 0C4.15905 0 2.66667 1.49238 2.66667 3.33333Z" fill="url(#paint1_linear_264_32130)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_264_32130" x1="6" y1="-1.34111e-08" x2="6" y2="13.6667" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_264_32130" x1="6" y1="-1.34111e-08" x2="6" y2="13.6667" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<component
|
||||
v-if="isIconfont"
|
||||
:is="
|
||||
Object.keys(iconMap).includes(iconName)
|
||||
? iconMap[iconName].iconReader()
|
||||
: iconMap['404'].iconReader()
|
||||
"
|
||||
class="el-icon app-icon"
|
||||
>
|
||||
</component>
|
||||
<el-icon v-else-if="iconName">
|
||||
<component :is="iconName" />
|
||||
</el-icon>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { iconMap } from '@/components/app-icon/index'
|
||||
defineOptions({ name: 'AppIcon' })
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
iconName?: string
|
||||
}>(),
|
||||
{
|
||||
iconName: '404'
|
||||
}
|
||||
)
|
||||
|
||||
const isIconfont = computed(() => props.iconName?.includes('app-'))
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import { h } from 'vue'
|
||||
export default {
|
||||
'app-github': {
|
||||
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: 'M511.6 76.3C264.3 76.2 64 276.4 64 523.5 64 718.9 189.3 885 363.8 946c23.5 5.9 19.9-10.8 19.9-22.2v-77.5c-135.7 15.9-141.2-73.9-150.3-88.9C215 726 171.5 718 184.5 703c30.9-15.9 62.4 4 98.9 57.9 26.4 39.1 77.9 32.5 104 26 5.7-23.5 17.9-44.5 34.7-60.8-140.6-25.2-199.2-111-199.2-213 0-49.5 16.3-95 48.3-131.7-20.4-60.5 1.9-112.3 4.9-120 58.1-5.2 118.5 41.6 123.2 45.3 33-8.9 70.7-13.6 112.9-13.6 42.4 0 80.2 4.9 113.5 13.9 11.3-8.6 67.3-48.8 121.3-43.9 2.9 7.7 24.7 58.3 5.5 118 32.4 36.8 48.9 82.7 48.9 132.3 0 102.2-59 188.1-200 212.9 23.5 23.2 38.1 55.4 38.1 91v112.5c0.8 9 0 17.9 15 17.9 177.1-59.7 304.6-227 304.6-424.1 0-247.2-200.4-447.3-447.5-447.3z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
'app-help': {
|
||||
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 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768z m0 85.333333C252.8 981.333333 42.666667 771.2 42.666667 512S252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333-210.133333 469.333333-469.333333 469.333333z m-21.333333-298.666666h42.666666a21.333333 21.333333 0 0 1 21.333334 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333334 21.333333h-42.666666a21.333333 21.333333 0 0 1-21.333334-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333334-21.333333zM343.466667 396.032c0.554667-4.778667 1.109333-8.746667 1.664-11.946667 8.32-46.293333 29.397333-80.341333 63.189333-102.144 26.453333-17.28 59.008-25.941333 97.621333-25.941333 50.730667 0 92.842667 12.288 126.378667 36.864 33.578667 24.533333 50.346667 60.928 50.346667 109.141333 0 29.568-7.253333 54.485333-21.888 74.752-8.533333 12.245333-24.917333 27.946667-49.152 47.061334l-23.893334 18.773333c-13.013333 10.24-21.632 22.186667-25.898666 35.84-1.152 3.712-2.176 10.624-3.072 20.736a21.333333 21.333333 0 0 1-21.248 19.498667h-47.786667a21.333333 21.333333 0 0 1-21.248-23.296c2.773333-29.696 5.717333-48.469333 8.832-56.362667 5.845333-14.677333 20.906667-31.573333 45.141333-50.688l24.533334-19.413333c8.106667-6.144 49.749333-35.456 49.749333-61.44 0-25.941333-4.522667-35.498667-17.578667-49.749334-13.013333-14.208-42.368-18.773333-68.864-18.773333-26.026667 0-48.256 6.869333-59.136 24.405333-5.034667 8.106667-9.173333 16.768-12.117333 25.6a89.472 89.472 0 0 0-3.114667 13.098667 21.333333 21.333333 0 0 1-21.034666 17.706667H364.672a21.333333 21.333333 0 0 1-21.205333-23.722667z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
'app-user-manual': {
|
||||
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: 'M768 128H256a85.333333 85.333333 0 0 0-85.333333 85.333333v426.666667h512V64h85.333333v640a21.333333 21.333333 0 0 1-21.333333 21.333333H256a85.333333 85.333333 0 0 0-0.128 170.666667H832a21.333333 21.333333 0 0 0 21.333333-21.333333V341.333333h85.333334v597.333334a42.666667 42.666667 0 0 1-42.666667 42.666666H256c-94.293333 0-170.666667-76.16-170.666667-170.410666V213.248C85.333333 119.04 161.706667 42.666667 256 42.666667h469.333333a42.666667 42.666667 0 0 1 42.666667 42.666666v42.666667z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
h('path', {
|
||||
d: 'M277.333333 768a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h469.333334a21.333333 21.333333 0 0 0 21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 0-21.333333-21.333333h-469.333334z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import { h } from 'vue'
|
||||
const iconsImport: any = import.meta.glob('./icons/*.ts', { eager: true, import: 'default' })
|
||||
const dynamicIcons = Object.values(iconsImport).reduce(
|
||||
(acc: Record<string, any>, module) => ({
|
||||
...acc,
|
||||
...(typeof module === 'object' && module !== null ? module : {}),
|
||||
}),
|
||||
{} as Record<string, any>,
|
||||
)
|
||||
export const iconMap: any = {
|
||||
'app-warning': {
|
||||
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 234.666667A53.333333 53.333333 0 1 1 512 341.333333a53.333333 53.333333 0 0 1 0-106.666666zM522.666667 384h-64a21.333333 21.333333 0 0 0-21.333334 21.333333v42.666667a21.333333 21.333333 0 0 0 21.333334 21.333333h21.333333v213.333334H426.666667a21.333333 21.333333 0 0 0-21.333334 21.333333v42.666667a21.333333 21.333333 0 0 0 21.333334 21.333333h192a21.333333 21.333333 0 0 0 21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 0-21.333333-21.333333h-53.333334v-256a42.666667 42.666667 0 0 0-42.666666-42.666667z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
h('path', {
|
||||
d: 'M512 981.333333C252.8 981.333333 42.666667 771.2 42.666667 512S252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333-210.133333 469.333333-469.333333 469.333333z m0-85.333333a384 384 0 1 0 0-768 384 384 0 0 0 0 768z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
'app-warning-colorful': {
|
||||
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: 'M42.666667 512c0 259.2 210.133333 469.333333 469.333333 469.333333s469.333333-210.133333 469.333333-469.333333S771.2 42.666667 512 42.666667 42.666667 252.8 42.666667 512z m469.333333-277.333333A53.333333 53.333333 0 1 1 512 341.333333a53.333333 53.333333 0 0 1 0-106.666666zM458.666667 384h64a42.666667 42.666667 0 0 1 42.666666 42.666667v256h53.333334a21.333333 21.333333 0 0 1 21.333333 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333333 21.333333H426.666667a21.333333 21.333333 0 0 1-21.333334-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333334-21.333333h53.333333v-213.333334h-21.333333a21.333333 21.333333 0 0 1-21.333334-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333334-21.333333z',
|
||||
fill: '#3370FF',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
'app-copy': {
|
||||
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: 'M213.333333 341.333333v512h426.666667V341.333333H213.333333z m512-42.666666v602.069333c0 20.949333-17.834667 37.930667-39.808 37.930667H167.808C145.834667 938.666667 128 921.685333 128 900.736V293.973333C128 272.981333 145.834667 256 167.808 256H682.666667a42.666667 42.666667 0 0 1 42.666666 42.666667z m158.165334-200.832A42.538667 42.538667 0 0 1 896 128v533.333333a21.333333 21.333333 0 0 1-21.333333 21.333334h-42.666667a21.333333 21.333333 0 0 1-21.333333-21.333334V170.666667H405.333333a21.333333 21.333333 0 0 1-21.333333-21.333334v-42.666666a21.333333 21.333333 0 0 1 21.333333-21.333334H853.333333c11.776 0 22.442667 4.778667 30.165334 12.501334z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
// 动态加载的图标
|
||||
...dynamicIcons,
|
||||
}
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
<template>
|
||||
<div style="width: 1024px">
|
||||
<DynamicsForm
|
||||
v-model="form_data"
|
||||
:model="form_data"
|
||||
:render_data="damo_data"
|
||||
ref="dynamicsFormRef"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-form-item label="其他字段">
|
||||
<el-input v-model="scope.form_value['zha']" /> </el-form-item
|
||||
></template>
|
||||
</DynamicsForm>
|
||||
<el-button @click="click">点我校验</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
import { ref } from 'vue'
|
||||
import type { Dict } from '@/api/type/common'
|
||||
|
||||
const damo_data: Array<FormField> = [
|
||||
{ field: 'name', input_type: 'PasswordInput', label: '用戶名', required: false },
|
||||
{ field: 'json_text', input_type: 'JsonInput', label: 'aa', required: false },
|
||||
{
|
||||
field: 'array_object_card_field',
|
||||
input_type: 'ArrayObjectCard',
|
||||
label: '測試',
|
||||
trigger_type: 'CHILD_FORMS',
|
||||
attrs: { 'label-width': '120px', 'label-suffix': ':ssss', 'label-position': 'top' },
|
||||
required: false,
|
||||
children: [
|
||||
{ field: 'name1', input_type: 'TextInput', label: '用戶名1' },
|
||||
{ field: 'name2', input_type: 'TextInput', label: '用戶名2' },
|
||||
{ field: 'name3', input_type: 'TextInput', label: '用戶名3' }
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'maxkb_tokens',
|
||||
input_type: 'Slider',
|
||||
default_value: 1,
|
||||
attrs: {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 1,
|
||||
precision: 1,
|
||||
'show-input-controls': false,
|
||||
'show-input': true
|
||||
},
|
||||
label: { label: '温度', attrs: { tooltip: 'sss' }, input_type: 'TooltipLabel' }
|
||||
},
|
||||
{
|
||||
field: 'object_card_field',
|
||||
input_type: 'ObjectCard',
|
||||
label: '測試',
|
||||
trigger_type: 'CHILD_FORMS',
|
||||
attrs: { 'label-width': '120px', 'label-suffix': ':ssss', 'label-position': 'left' },
|
||||
required: false,
|
||||
children: [
|
||||
{ field: 'name1', input_type: 'TextInput', label: '用戶名1' },
|
||||
{ field: 'name2', input_type: 'TextInput', label: '用戶名2' },
|
||||
{ field: 'name3', input_type: 'TextInput', label: '用戶名3' }
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'tab_card_field',
|
||||
input_type: 'TabCard',
|
||||
label: '測試',
|
||||
trigger_type: 'CHILD_FORMS',
|
||||
attrs: { 'label-width': '120px', 'label-suffix': ':ssss', 'label-position': 'left' },
|
||||
required: false,
|
||||
relation_trigger_field_dict: {
|
||||
'array_object_card_field.0.name1': ['111']
|
||||
},
|
||||
props_info: { tabs_label: '用户' },
|
||||
children: [
|
||||
{ field: 'name1', input_type: 'TextInput', label: '用戶名1' },
|
||||
{ field: 'name2', input_type: 'TextInput', label: '用戶名2' },
|
||||
{ field: 'name3', input_type: 'TextInput', label: '用戶名3' }
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'single_select_field',
|
||||
input_type: 'SingleSelect',
|
||||
label: '测试单选',
|
||||
required: true,
|
||||
attrs: { placeholder: '请选择' },
|
||||
option_list: [
|
||||
{
|
||||
key: '测试',
|
||||
value: 'test'
|
||||
},
|
||||
{
|
||||
key: '测试1',
|
||||
value: 'test1'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'multi_select_field',
|
||||
input_type: 'MultiSelect',
|
||||
default_value: ['test1'],
|
||||
relation_show_field_dict: {
|
||||
'object_card_field.name1': []
|
||||
},
|
||||
label: '测试多选下拉',
|
||||
required: true,
|
||||
attrs: { placeholder: '请选择' },
|
||||
option_list: [
|
||||
{
|
||||
key: '测试',
|
||||
value: 'test'
|
||||
},
|
||||
{
|
||||
key: '测试1',
|
||||
value: 'test1'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'radio_field',
|
||||
input_type: 'Radio',
|
||||
label: '测试单选',
|
||||
required: true,
|
||||
attrs: { placeholder: '请选择' },
|
||||
option_list: [
|
||||
{
|
||||
key: '测试',
|
||||
value: 'test'
|
||||
},
|
||||
{
|
||||
key: '测试1',
|
||||
value: 'test1'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'radio_button_field',
|
||||
input_type: 'RadioButton',
|
||||
label: '测试单选',
|
||||
required: true,
|
||||
attrs: { placeholder: '请选择' },
|
||||
option_list: [
|
||||
{
|
||||
key: '测试',
|
||||
value: 'test'
|
||||
},
|
||||
{
|
||||
key: '测试1',
|
||||
value: 'test1'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'radio_card_field',
|
||||
input_type: 'RadioCard',
|
||||
label: '测试单选1',
|
||||
required: true,
|
||||
attrs: { placeholder: '请选择' },
|
||||
option_list: [
|
||||
{
|
||||
key: '测试',
|
||||
value: 'test'
|
||||
},
|
||||
{
|
||||
key: '测试111111',
|
||||
value: 'test1'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'table_radio_field',
|
||||
input_type: 'TableRadio',
|
||||
label: '表格单选',
|
||||
required: true,
|
||||
attrs: { placeholder: '请选择' },
|
||||
props_info: {
|
||||
active_msg: '当前选中',
|
||||
table_columns: [
|
||||
{
|
||||
property: '`${row.key}${row.number}`',
|
||||
label: '名称',
|
||||
type: 'eval'
|
||||
},
|
||||
{
|
||||
property: 'ProgressTableItem',
|
||||
label: '数值',
|
||||
type: 'component',
|
||||
value_field: 'number',
|
||||
attrs: {
|
||||
color: [
|
||||
{ color: '#f56c6c', percentage: 20 },
|
||||
{ color: '#e6a23c', percentage: 40 },
|
||||
{ color: '#5cb87a', percentage: 60 },
|
||||
{ color: '#1989fa', percentage: 80 },
|
||||
{ color: '#6f7ad3', percentage: 100 }
|
||||
]
|
||||
},
|
||||
props_info: {
|
||||
view_card: [
|
||||
{
|
||||
type: 'eval',
|
||||
title: '测试',
|
||||
value_field:
|
||||
'`${parseFloat(row.number).toLocaleString("zh-CN",{style: "decimal",maximumFractionDigits:1})}% `'
|
||||
},
|
||||
{
|
||||
type: 'eval',
|
||||
title: '名称',
|
||||
value_field: '`${row.key} `'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
style: { width: '500px' }
|
||||
},
|
||||
option_list: [
|
||||
{
|
||||
key: '测试',
|
||||
value: 'test',
|
||||
number: 10
|
||||
},
|
||||
{
|
||||
key: '测试111111',
|
||||
value: 'test1',
|
||||
number: 100
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
field: 'table_checkbox_field',
|
||||
input_type: 'TableCheckbox',
|
||||
label: '表格多选',
|
||||
required: true,
|
||||
attrs: { placeholder: '请选择' },
|
||||
props_info: {
|
||||
active_msg: '当前选中',
|
||||
table_columns: [
|
||||
{
|
||||
property: '`${row.key}${row.number}`',
|
||||
label: '名称',
|
||||
type: 'eval'
|
||||
},
|
||||
{
|
||||
property: 'ProgressTableItem',
|
||||
label: '数值',
|
||||
type: 'component',
|
||||
value_field: 'number',
|
||||
attrs: {
|
||||
color: [
|
||||
{ color: '#f56c6c', percentage: 20 },
|
||||
{ color: '#e6a23c', percentage: 40 },
|
||||
{ color: '#5cb87a', percentage: 60 },
|
||||
{ color: '#1989fa', percentage: 80 },
|
||||
{ color: '#6f7ad3', percentage: 100 }
|
||||
]
|
||||
},
|
||||
props_info: {
|
||||
view_card: [
|
||||
{
|
||||
type: 'eval',
|
||||
title: '测试',
|
||||
value_field:
|
||||
'`${parseFloat(row.number).toLocaleString("zh-CN",{style: "decimal",maximumFractionDigits:1})}% `'
|
||||
},
|
||||
{
|
||||
type: 'eval',
|
||||
title: '名称',
|
||||
value_field: '`${row.key} `'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
style: { width: '500px' }
|
||||
},
|
||||
option_list: [
|
||||
{
|
||||
key: '测试',
|
||||
value: 'test',
|
||||
number: 10
|
||||
},
|
||||
{
|
||||
key: '测试111111',
|
||||
value: 'test1',
|
||||
number: 100
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
const form_data = ref<Dict<any>>({})
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
const click = () => {
|
||||
dynamicsFormRef.value?.validate()
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-card shadow="never">
|
||||
<DynamicsFormConstructor
|
||||
v-model="item"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
ref="DynamicsFormConstructorRef"
|
||||
></DynamicsFormConstructor>
|
||||
<el-button @click="add_field">添加</el-button>
|
||||
</el-card></el-col
|
||||
>
|
||||
<el-col :span="12">
|
||||
<el-card shadow="never">
|
||||
<DynamicsForm
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
v-model="form_data"
|
||||
:model="form_data"
|
||||
:render_data="form_item_list"
|
||||
ref="dynamicsFormRef"
|
||||
>
|
||||
</DynamicsForm>
|
||||
<el-button @click="validate">校验</el-button>
|
||||
</el-card></el-col
|
||||
>
|
||||
</el-row>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import DynamicsFormConstructor from '@/components/dynamics-form/constructor/index.vue'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
const DynamicsFormConstructorRef = ref<InstanceType<typeof DynamicsFormConstructor>>()
|
||||
|
||||
const form_item_list = ref<Array<any>>([])
|
||||
const add_field = () => {
|
||||
if (DynamicsFormConstructorRef.value) {
|
||||
DynamicsFormConstructorRef.value.validate().then(() => {
|
||||
form_item_list.value.push(DynamicsFormConstructorRef.value?.getData())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const form_data = ref({})
|
||||
const item = ref({})
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
const validate = () => {
|
||||
dynamicsFormRef.value
|
||||
?.validate()
|
||||
.then((ok) => {})
|
||||
.catch((e) => {})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
<template>
|
||||
<el-form-item
|
||||
v-loading="loading"
|
||||
:style="formItemStyle"
|
||||
:prop="formfield.field"
|
||||
:key="formfield.field"
|
||||
:rules="rules"
|
||||
>
|
||||
<template #label v-if="formfield.label">
|
||||
<FormItemLabel v-if="isString(formfield.label)" :form-field="formfield"></FormItemLabel>
|
||||
<component
|
||||
v-else
|
||||
:is="formfield.label.input_type"
|
||||
:label="formfield.label.label"
|
||||
v-bind="label_attrs"
|
||||
></component>
|
||||
</template>
|
||||
<component
|
||||
ref="componentFormRef"
|
||||
:view="view"
|
||||
v-model="itemValue"
|
||||
:is="formfield.input_type"
|
||||
:form-field="formfield"
|
||||
:other-params="otherParams"
|
||||
:style="componentStyle"
|
||||
:field="formfield.field"
|
||||
v-bind="attrs"
|
||||
:formfield-list="formfieldList"
|
||||
></component>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, type Ref } from 'vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import FormItemLabel from './FormItemLabel.vue'
|
||||
import type { Dict } from '@/api/type/common'
|
||||
import bus from '@/utils/bus'
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps<{
|
||||
// 双向绑定的值
|
||||
modelValue: any
|
||||
|
||||
// 表单Item
|
||||
formfield: FormField
|
||||
// 是否只读
|
||||
view: boolean
|
||||
// 调用接口所需要的其他参数
|
||||
otherParams: any
|
||||
// 获取Options
|
||||
trigger: (formItem: FormField, loading: Ref<boolean>) => Promise<any>
|
||||
// 初始化默认数据
|
||||
initDefaultData: (formItem: FormField) => void
|
||||
// 默认每个宽度
|
||||
defaultItemWidth: string
|
||||
// 表单收集数据
|
||||
formValue: Dict<any>
|
||||
|
||||
formfieldList: Array<FormField>
|
||||
|
||||
parent_field?: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
const loading = ref<boolean>(false)
|
||||
|
||||
const isString = (value: any) => {
|
||||
return typeof value === 'string'
|
||||
}
|
||||
const itemValue = computed({
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
},
|
||||
set: (value: any) => {
|
||||
emit('change', value)
|
||||
if (props.parent_field) {
|
||||
bus.emit(props.parent_field + '.' + props.formfield.field, value)
|
||||
} else {
|
||||
bus.emit(props.formfield.field, value)
|
||||
}
|
||||
}
|
||||
})
|
||||
const componentFormRef = ref<any>()
|
||||
const label_attrs = computed(() => {
|
||||
return props.formfield.label &&
|
||||
typeof props.formfield.label !== 'string' &&
|
||||
props.formfield.label.attrs
|
||||
? props.formfield.label.attrs
|
||||
: {}
|
||||
})
|
||||
const props_info = computed(() => {
|
||||
return props.formfield.props_info ? props.formfield.props_info : {}
|
||||
})
|
||||
/**
|
||||
* 表单 item style
|
||||
*/
|
||||
const formItemStyle = computed(() => {
|
||||
return props_info.value.item_style ? props_info.value.item_style : {}
|
||||
})
|
||||
|
||||
/**
|
||||
* 表单错误Msg
|
||||
*/
|
||||
const errMsg = computed(() => {
|
||||
return props_info.value.err_msg
|
||||
? props_info.value.err_msg
|
||||
: isString(props.formfield.label)
|
||||
? props.formfield.label + ' ' + t('dynamicsForm.tip.requiredMessage')
|
||||
: props.formfield.label.label + ' ' + t('dynamicsForm.tip.requiredMessage')
|
||||
})
|
||||
/**
|
||||
* 反序列化
|
||||
* @param rule
|
||||
*/
|
||||
const to_rule = (rule: any) => {
|
||||
if (rule.validator) {
|
||||
let validator = (rule: any, value: string, callback: any) => {}
|
||||
eval(rule.validator)
|
||||
return { ...rule, validator }
|
||||
}
|
||||
return rule
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验
|
||||
*/
|
||||
const rules = computed(() => {
|
||||
return props_info.value.rules
|
||||
? props_info.value.rules.map(to_rule)
|
||||
: {
|
||||
message: errMsg.value,
|
||||
trigger: props.formfield.input_type === 'Slider' ? 'blur' : ['blur', 'change'],
|
||||
required: props.formfield.required === false ? false : true
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 组件样式
|
||||
*/
|
||||
const componentStyle = computed(() => {
|
||||
return props_info.value.style ? props_info.value.style : {}
|
||||
})
|
||||
|
||||
/**
|
||||
* 组件attrs
|
||||
*/
|
||||
const attrs = computed(() => {
|
||||
return props.formfield.attrs ? props.formfield.attrs : {}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
props.initDefaultData(props.formfield)
|
||||
if (props.formfield.provider && props.formfield.method) {
|
||||
props.trigger(props.formfield, loading)
|
||||
}
|
||||
// 监听字段变化
|
||||
const trigger_field_dict = props.formfield.relation_trigger_field_dict
|
||||
if (trigger_field_dict) {
|
||||
const keys = Object.keys(trigger_field_dict)
|
||||
keys.forEach((key) => {
|
||||
const value = trigger_field_dict[key]
|
||||
// 添加关系
|
||||
bus.on(key, (v: any) => {
|
||||
if (value && value.length > 0) {
|
||||
if (value.includes(v)) {
|
||||
props.trigger(props.formfield, loading)
|
||||
}
|
||||
} else {
|
||||
props.trigger(props.formfield, loading)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const validate = () => {
|
||||
if (props.formfield.trigger_type === 'CHILD_FORMS' && componentFormRef.value) {
|
||||
return componentFormRef.value.validate()
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
||||
defineExpose({ validate })
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<template>
|
||||
{{ formField.label }}
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
const props = defineProps<{
|
||||
// 表单Item
|
||||
formField: FormField
|
||||
}>()
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import { t } from '@/locales'
|
||||
const input_type_list = [
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.TextInput'),
|
||||
value: 'TextInput'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.PasswordInput'),
|
||||
value: 'PasswordInput'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.Slider'),
|
||||
value: 'Slider'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.SwitchInput'),
|
||||
value: 'SwitchInput'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.SingleSelect'),
|
||||
value: 'SingleSelect'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.MultiSelect'),
|
||||
value: 'MultiSelect'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.DatePicker'),
|
||||
value: 'DatePicker'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.JsonInput'),
|
||||
value: 'JsonInput'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.RadioCard'),
|
||||
value: 'RadioCard'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.RadioRow'),
|
||||
value: 'RadioRow'
|
||||
}
|
||||
]
|
||||
export { input_type_list }
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
<template>
|
||||
<el-form
|
||||
@submit.prevent
|
||||
ref="ruleFormRef"
|
||||
class="mb-24"
|
||||
label-width="auto"
|
||||
:model="form_data"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<el-form-item :label="$t('dynamicsForm.paramForm.field.label')" :required="true" prop="field" :rules="rules.field">
|
||||
<el-input
|
||||
v-model="form_data.field"
|
||||
:maxlength="64"
|
||||
:placeholder="$t('dynamicsForm.paramForm.field.placeholder')"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dynamicsForm.paramForm.name.label')" :required="true" prop="label" :rules="rules.label">
|
||||
<el-input
|
||||
v-model="form_data.label"
|
||||
:maxlength="64"
|
||||
show-word-limit
|
||||
:placeholder="$t('dynamicsForm.paramForm.name.placeholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dynamicsForm.paramForm.tooltip.label')">
|
||||
<el-input
|
||||
v-model="form_data.tooltip"
|
||||
:maxlength="128"
|
||||
show-word-limit
|
||||
:placeholder="$t('dynamicsForm.paramForm.tooltip.placeholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dynamicsForm.paramForm.required.label')" :required="true" prop="required" :rules="rules.required">
|
||||
<el-switch v-model="form_data.required" :active-value="true" :inactive-value="false" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dynamicsForm.paramForm.input_type.label')" :required="true" prop="input_type" :rules="rules.input_type">
|
||||
<el-select v-model="form_data.input_type" :placeholder="$t('dynamicsForm.paramForm.input_type.placeholder')">
|
||||
<el-option
|
||||
v-for="input_type in input_type_list"
|
||||
:key="input_type.value"
|
||||
:label="input_type.label"
|
||||
:value="input_type.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<component
|
||||
v-if="form_data.input_type"
|
||||
ref="componentFormRef"
|
||||
v-model="form_data"
|
||||
:is="form_data.input_type"
|
||||
></component>
|
||||
</el-form>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, nextTick } from 'vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import _ from 'lodash'
|
||||
import { input_type_list as input_type_list_data } from '@/components/dynamics-form/constructor/data'
|
||||
import { t } from '@/locales'
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue?: any
|
||||
input_type_list?: Array<{ label: string; value: string }>
|
||||
}>(),
|
||||
{
|
||||
input_type_list: () =>
|
||||
input_type_list_data.map((item) => ({ label: item.label, value: item.value + 'Constructor' }))
|
||||
}
|
||||
)
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const ruleFormRef = ref<FormInstance>()
|
||||
|
||||
const componentFormRef = ref<any>()
|
||||
const form_data = ref<any>({
|
||||
label: '',
|
||||
field: '',
|
||||
tooltip: '',
|
||||
required: false,
|
||||
input_type: ''
|
||||
})
|
||||
const rules = {
|
||||
label: [{ required: true, message: t('dynamicsForm.paramForm.name.requiredMessage') }],
|
||||
field: [{ required: true, message: t('dynamicsForm.paramForm.field.requiredMessage') }],
|
||||
required: [{ required: true, message: t('dynamicsForm.paramForm.required.requiredMessage') }],
|
||||
input_type: [{ required: true, message: t('dynamicsForm.paramForm.input_type.requiredMessage') }]
|
||||
}
|
||||
const getData = () => {
|
||||
let label: string | any = form_data.value.label
|
||||
if (form_data.value.tooltip) {
|
||||
label = {
|
||||
input_type: 'TooltipLabel',
|
||||
label: form_data.value.label,
|
||||
attrs: { tooltip: form_data.value.tooltip },
|
||||
props_info: {}
|
||||
}
|
||||
}
|
||||
return {
|
||||
label: label,
|
||||
required: form_data.value.required,
|
||||
field: form_data.value.field,
|
||||
default_value: form_data.value.default_value,
|
||||
show_default_value: form_data.value.show_default_value,
|
||||
...componentFormRef.value.getData()
|
||||
}
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
if (ruleFormRef.value) {
|
||||
return ruleFormRef.value?.validate()
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.modelValue) {
|
||||
rander(props.modelValue)
|
||||
}
|
||||
})
|
||||
const rander = (data: any) => {
|
||||
form_data.value.required = data.required ? data.required : false
|
||||
form_data.value.field = data.field
|
||||
if (data.show_default_value !== undefined) {
|
||||
form_data.value.show_default_value = data.show_default_value
|
||||
}
|
||||
if (data.input_type) {
|
||||
form_data.value.input_type = data.input_type + 'Constructor'
|
||||
}
|
||||
|
||||
if (data.label && data.label.input_type === 'TooltipLabel') {
|
||||
form_data.value.tooltip = data.label.attrs.tooltip
|
||||
form_data.value.label = data.label.label
|
||||
} else {
|
||||
form_data.value.label = data.label
|
||||
}
|
||||
nextTick(() => {
|
||||
componentFormRef.value?.rander(data)
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ getData, validate, rander })
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
<template>
|
||||
<el-form-item :label="$t('dynamicsForm.DatePicker.dataType.label')" required>
|
||||
<el-select
|
||||
@change="type_change"
|
||||
v-model="formValue.type"
|
||||
:placeholder="$t('dynamicsForm.DatePicker.dataType.placeholder')"
|
||||
>
|
||||
<el-option
|
||||
v-for="input_type in type_list"
|
||||
:key="input_type.value"
|
||||
:label="input_type.label"
|
||||
:value="input_type.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dynamicsForm.DatePicker.format.label')" required>
|
||||
<el-select
|
||||
v-model="formValue.format"
|
||||
filterable
|
||||
default-first-option
|
||||
allow-create
|
||||
:placeholder="$t('dynamicsForm.DatePicker.format.placeholder')"
|
||||
>
|
||||
<el-option
|
||||
v-for="input_type in type_dict[formValue.type]"
|
||||
:key="input_type.value"
|
||||
:label="input_type.value"
|
||||
:value="input_type.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="defaultValueItem"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:rules="
|
||||
formValue.required
|
||||
? [{ required: true, message: `${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}` }]
|
||||
: []
|
||||
"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
v-model="formValue.show_default_value"
|
||||
:label="$t('dynamicsForm.default.show')"
|
||||
/>
|
||||
</div>
|
||||
<el-date-picker
|
||||
v-model="formValue.default_value"
|
||||
:type="formValue.type"
|
||||
:placeholder="$t('dynamicsForm.DatePicker.placeholder')"
|
||||
:format="formValue.format"
|
||||
:value-format="formValue.format"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeMount } from 'vue'
|
||||
import { t } from '@/locales'
|
||||
const type_list = [
|
||||
{
|
||||
label: t('dynamicsForm.DatePicker.year'),
|
||||
value: 'year'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.DatePicker.month'),
|
||||
value: 'month'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.DatePicker.date'),
|
||||
value: 'date'
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.DatePicker.datetime'),
|
||||
value: 'datetime'
|
||||
}
|
||||
]
|
||||
const type_dict: any = {
|
||||
year: [{ value: 'YYYY' }],
|
||||
month: [{ value: 'YYYY-MM' }],
|
||||
date: [{ value: 'YYYY-MM-DD' }],
|
||||
datetime: [{ value: 'YYYY-MM-DD HH:mm:ss' }]
|
||||
}
|
||||
const type_change = () => {
|
||||
formValue.value.format = type_dict[formValue.value.type][0].value
|
||||
formValue.value.default_value = ''
|
||||
}
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'DatePicker',
|
||||
attrs: {
|
||||
type: formValue.value.type,
|
||||
format: formValue.value.format,
|
||||
'value-format': formValue.value.format
|
||||
},
|
||||
default_value: formValue.value.default_value,
|
||||
show_default_value: formValue.value.show_default_value
|
||||
}
|
||||
}
|
||||
const rander = (form_data: any) => {
|
||||
formValue.value.type = form_data.attrs.type
|
||||
formValue.value.format = form_data.attrs?.format
|
||||
formValue.value.default_value = form_data.default_value || ''
|
||||
}
|
||||
defineExpose({ getData, rander })
|
||||
onBeforeMount(() => {
|
||||
formValue.value.type = 'datetime'
|
||||
formValue.value.format = 'YYYY-MM-DD HH:mm:ss'
|
||||
formValue.value.default_value = ''
|
||||
if (formValue.value.show_default_value === undefined) {
|
||||
formValue.value.show_default_value = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.defaultValueItem {
|
||||
position: relative;
|
||||
.defaultValueCheckbox {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -35px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<template>
|
||||
<el-form-item
|
||||
class="defaultValueItem"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:rules="[default_value_rule]"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
v-model="formValue.show_default_value"
|
||||
:label="$t('dynamicsForm.default.show')"
|
||||
/>
|
||||
</div>
|
||||
<JsonInput ref="jsonInputRef" v-model="formValue.default_value"> </JsonInput>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import JsonInput from '@/components/dynamics-form/items/JsonInput.vue'
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
const jsonInputRef = ref<InstanceType<typeof JsonInput>>()
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'JsonInput',
|
||||
attrs: {},
|
||||
props_info: {
|
||||
rules: [
|
||||
{
|
||||
required: formValue.value.required,
|
||||
validator: `validator = (rule, value, callback) => {
|
||||
return componentFormRef.value?.validate_rules(rule, value, callback);
|
||||
|
||||
}`,
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
},
|
||||
default_value: formValue.value.default_value,
|
||||
show_default_value: formValue.value.show_default_value
|
||||
}
|
||||
}
|
||||
|
||||
const default_value_rule = {
|
||||
required: true,
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
jsonInputRef.value?.validate_rules(rule, value, callback)
|
||||
return true
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
|
||||
const rander = (form_data: any) => {
|
||||
formValue.value.default_value = form_data.default_value
|
||||
}
|
||||
defineExpose({ getData, rander })
|
||||
onMounted(() => {
|
||||
formValue.value.default_value = {}
|
||||
if (formValue.value.show_default_value === undefined) {
|
||||
formValue.value.show_default_value = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.defaultValueItem {
|
||||
position: relative;
|
||||
.defaultValueCheckbox {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -35px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
{{ $t('dynamicsForm.Select.label') }}
|
||||
<el-button link type="primary" @click.stop="addOption()">
|
||||
<el-icon class="mr-4">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
{{ $t('common.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-col :span="10">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.tag.label') }}
|
||||
</el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.Select.label') }}</el-col
|
||||
>
|
||||
</el-row>
|
||||
<el-row
|
||||
style="width: 100%"
|
||||
v-for="(option, $index) in formValue.option_list"
|
||||
:key="$index"
|
||||
:gutter="10"
|
||||
class="mb-8"
|
||||
>
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].label" :placeholder="$t('dynamicsForm.tag.placeholder')"
|
||||
/></el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].value"
|
||||
:placeholder="$t('dynamicsForm.Select.label')"
|
||||
/></el-col>
|
||||
<el-col :span="1"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-button link class="ml-8" @click.stop="delOption($index)">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon> </el-button
|
||||
></el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="defaultValueItem"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:rules="
|
||||
formValue.required
|
||||
? [{ required: true, message: `${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}` }]
|
||||
: []
|
||||
"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
v-model="formValue.show_default_value"
|
||||
:label="$t('dynamicsForm.default.show')"
|
||||
/>
|
||||
</div>
|
||||
<el-select
|
||||
class="m-2"
|
||||
multiple
|
||||
collapse-tags
|
||||
filterable
|
||||
clearable
|
||||
v-model="formValue.default_value"
|
||||
:teleported="false"
|
||||
popper-class="default-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="(option, index) in formValue.option_list"
|
||||
:key="index"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
|
||||
const addOption = () => {
|
||||
formValue.value.option_list.push({ value: '', label: '' })
|
||||
}
|
||||
|
||||
const delOption = (index: number) => {
|
||||
const option = formValue.value.option_list[index]
|
||||
if (option.value && formValue.value.default_value == option.value) {
|
||||
formValue.value.default_value = ''
|
||||
}
|
||||
formValue.value.option_list.splice(index, 1)
|
||||
}
|
||||
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'MultiSelect',
|
||||
attrs: {},
|
||||
default_value: formValue.value.default_value,
|
||||
show_default_value: formValue.value.show_default_value,
|
||||
text_field: 'label',
|
||||
value_field: 'value',
|
||||
option_list: formValue.value.option_list
|
||||
}
|
||||
}
|
||||
const rander = (form_data: any) => {
|
||||
formValue.value.option_list = form_data.option_list || []
|
||||
formValue.value.default_value = form_data.default_value
|
||||
}
|
||||
|
||||
defineExpose({ getData, rander })
|
||||
onMounted(() => {
|
||||
formValue.value.option_list = []
|
||||
formValue.value.default_value = ''
|
||||
if (formValue.value.show_default_value === undefined) {
|
||||
formValue.value.show_default_value = true
|
||||
}
|
||||
addOption()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.defaultValueItem {
|
||||
position: relative;
|
||||
.defaultValueCheckbox {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -35px;
|
||||
}
|
||||
}
|
||||
:deep(.el-form-item__label) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
:deep(.el-select-dropdown) {
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
<template>
|
||||
<el-form-item :label="$t('dynamicsForm.TextInput.length.label')" required>
|
||||
<el-row class="w-full">
|
||||
<el-col :span="11">
|
||||
<el-form-item
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('dynamicsForm.TextInput.length.minRequired'),
|
||||
trigger: 'change'
|
||||
}
|
||||
]"
|
||||
prop="minlength"
|
||||
>
|
||||
<el-input-number
|
||||
style="width: 100%"
|
||||
:min="1"
|
||||
:step="1"
|
||||
step-strictly
|
||||
v-model="formValue.minlength"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="2" class="text-center">
|
||||
<span>-</span>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('dynamicsForm.TextInput.length.maxRequired'),
|
||||
trigger: 'change'
|
||||
}
|
||||
]"
|
||||
prop="maxlength"
|
||||
>
|
||||
<el-input-number
|
||||
style="width: 100%"
|
||||
:min="formValue.minlength > formValue.maxlength ? formValue.minlength : 1"
|
||||
step-strictly
|
||||
:step="1"
|
||||
v-model="formValue.maxlength"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
class="defaultValueItem"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:rules="
|
||||
formValue.required ? [{ required: true, message: `${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}` }, ...rules] : rules
|
||||
"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
v-model="formValue.show_default_value"
|
||||
:label="$t('dynamicsForm.default.show')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<el-input
|
||||
v-model="formValue.default_value"
|
||||
:maxlength="formValue.maxlength"
|
||||
:minlength="formValue.minlength"
|
||||
:placeholder="$t('dynamicsForm.default.placeholder')"
|
||||
show-word-limit
|
||||
type="password"
|
||||
show-password
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
watch(
|
||||
() => formValue.value.minlength,
|
||||
() => {
|
||||
if (formValue.value.minlength > formValue.value.maxlength) {
|
||||
formValue.value.maxlength = formValue.value.minlength
|
||||
}
|
||||
}
|
||||
)
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'PasswordInput',
|
||||
attrs: {
|
||||
maxlength: formValue.value.maxlength,
|
||||
minlength: formValue.value.minlength,
|
||||
'show-word-limit': true,
|
||||
type: 'password',
|
||||
'show-password': true
|
||||
},
|
||||
default_value: formValue.value.default_value,
|
||||
show_default_value: formValue.value.show_default_value,
|
||||
props_info: {
|
||||
rules: formValue.value.required
|
||||
? [
|
||||
{
|
||||
required: true,
|
||||
message: `${formValue.value.label} ${t('dynamicsForm.default.requiredMessage')}`
|
||||
},
|
||||
{
|
||||
min: formValue.value.minlength,
|
||||
max: formValue.value.maxlength,
|
||||
message: `${formValue.value.label}${t('dynamicsForm.TextInput.length.requiredMessage1')} ${formValue.value.minlength} ${t('dynamicsForm.TextInput.length.requiredMessage2')} ${formValue.value.maxlength} ${t('dynamicsForm.TextInput.length.requiredMessage3')}`,
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
min: formValue.value.minlength,
|
||||
max: formValue.value.maxlength,
|
||||
message: `${formValue.value.label}${t('dynamicsForm.TextInput.length.requiredMessage1')} ${formValue.value.minlength} ${t('dynamicsForm.TextInput.length.requiredMessage2')} ${formValue.value.maxlength} ${t('dynamicsForm.TextInput.length.requiredMessage3')}`,
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
const rander = (form_data: any) => {
|
||||
const attrs = form_data.attrs || {}
|
||||
formValue.value.minlength = attrs.minlength
|
||||
formValue.value.maxlength = attrs.maxlength
|
||||
formValue.value.default_value = form_data.default_value
|
||||
formValue.value.show_default_value = form_data.show_default_value
|
||||
formValue.value.show_password = attrs['show-password']
|
||||
}
|
||||
const rangeRules = [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (!formValue.value.minlength) {
|
||||
callback(new Error(t('dynamicsForm.TextInput.length.requiredMessage4')))
|
||||
}
|
||||
if (!formValue.value.maxlength) {
|
||||
callback(new Error(t('dynamicsForm.TextInput.length.requiredMessage4')))
|
||||
}
|
||||
return true
|
||||
},
|
||||
message: `${formValue.value.label} ${t('dynamicsForm.default.requiredMessage')}`
|
||||
}
|
||||
]
|
||||
const rules = computed(() => [
|
||||
{
|
||||
min: formValue.value.minlength,
|
||||
max: formValue.value.maxlength,
|
||||
message: `${t('dynamicsForm.TextInput.length.requiredMessage1')} ${formValue.value.minlength} ${t('dynamicsForm.TextInput.length.requiredMessage2')} ${formValue.value.maxlength} ${t('dynamicsForm.TextInput.length.requiredMessage3')}`,
|
||||
trigger: 'blur'
|
||||
}
|
||||
])
|
||||
|
||||
defineExpose({ getData, rander })
|
||||
onMounted(() => {
|
||||
formValue.value.minlength = 0
|
||||
formValue.value.maxlength = 200
|
||||
formValue.value.default_value = ''
|
||||
formValue.value.show_password = true
|
||||
|
||||
if (formValue.value.show_default_value === undefined) {
|
||||
formValue.value.show_default_value = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.defaultValueItem {
|
||||
position: relative;
|
||||
|
||||
.defaultValueCheckbox {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -35px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
<template>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
{{ $t('dynamicsForm.Select.label') }}
|
||||
<el-button link type="primary" @click.stop="addOption()">
|
||||
<el-icon class="mr-4">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
{{ $t('common.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-col :span="10">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.tag.label') }}
|
||||
</el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.Select.label') }}</el-col
|
||||
>
|
||||
</el-row>
|
||||
<el-row
|
||||
style="width: 100%"
|
||||
v-for="(option, $index) in formValue.option_list"
|
||||
:key="$index"
|
||||
:gutter="10"
|
||||
class="mb-8"
|
||||
>
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].label" :placeholder="$t('dynamicsForm.tag.placeholder')"
|
||||
/></el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].value"
|
||||
:placeholder="$t('dynamicsForm.Select.label')"
|
||||
/></el-col>
|
||||
<el-col :span="1"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-button link class="ml-8" @click.stop="delOption($index)">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon> </el-button
|
||||
></el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="defaultValueItem"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:rules="
|
||||
formValue.required
|
||||
? [{ required: true, message: `${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}` }]
|
||||
: []
|
||||
"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
v-model="formValue.show_default_value"
|
||||
:label="$t('dynamicsForm.default.show')"
|
||||
/>
|
||||
</div>
|
||||
<RadioCard
|
||||
:form-field="formField"
|
||||
v-model="formValue.default_value"
|
||||
:other-params="{}"
|
||||
field="default_value"
|
||||
>
|
||||
</RadioCard>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue'
|
||||
import RadioCard from '@/components/dynamics-form/items/radio/RadioCard.vue'
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
|
||||
const addOption = () => {
|
||||
formValue.value.option_list.push({ value: '', label: '' })
|
||||
}
|
||||
|
||||
const delOption = (index: number) => {
|
||||
const option = formValue.value.option_list[index]
|
||||
if (option.value && formValue.value.default_value == option.value) {
|
||||
formValue.value.default_value = ''
|
||||
}
|
||||
formValue.value.option_list.splice(index, 1)
|
||||
}
|
||||
const formField = computed(() => {
|
||||
return { field: '', ...getData() }
|
||||
})
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'RadioCard',
|
||||
attrs: {},
|
||||
default_value: formValue.value.default_value,
|
||||
show_default_value: formValue.value.show_default_value,
|
||||
text_field: 'label',
|
||||
value_field: 'value',
|
||||
option_list: formValue.value.option_list
|
||||
}
|
||||
}
|
||||
const rander = (form_data: any) => {
|
||||
formValue.value.option_list = form_data.option_list || []
|
||||
formValue.value.default_value = form_data.default_value
|
||||
}
|
||||
|
||||
defineExpose({ getData, rander })
|
||||
onMounted(() => {
|
||||
formValue.value.option_list = []
|
||||
formValue.value.default_value = ''
|
||||
if (formValue.value.show_default_value === undefined) {
|
||||
formValue.value.show_default_value = true
|
||||
}
|
||||
addOption()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.defaultValueItem {
|
||||
position: relative;
|
||||
.defaultValueCheckbox {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -35px;
|
||||
}
|
||||
}
|
||||
:deep(.el-form-item__label) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
:deep(.el-select-dropdown) {
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
<template>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
{{ $t('dynamicsForm.Select.label') }}
|
||||
<el-button link type="primary" @click.stop="addOption()">
|
||||
<el-icon class="mr-4">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
{{ $t('common.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-col :span="10">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.tag.label') }}
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.Select.label') }}
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row
|
||||
style="width: 100%"
|
||||
v-for="(option, $index) in formValue.option_list"
|
||||
:key="$index"
|
||||
:gutter="10"
|
||||
class="mb-8"
|
||||
>
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].label"
|
||||
:placeholder="$t('dynamicsForm.tag.placeholder')"
|
||||
/></el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].value"
|
||||
:placeholder="$t('dynamicsForm.Select.label')"
|
||||
/></el-col>
|
||||
<el-col :span="1"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-button link class="ml-8" @click.stop="delOption($index)">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon> </el-button
|
||||
></el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="defaultValueItem"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:rules="
|
||||
formValue.required
|
||||
? [{ required: true, message:`${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}` }]
|
||||
: []
|
||||
"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
v-model="formValue.show_default_value"
|
||||
:label="$t('dynamicsForm.default.show')"
|
||||
/>
|
||||
</div>
|
||||
<RadioRow
|
||||
:form-field="formField"
|
||||
v-model="formValue.default_value"
|
||||
:other-params="{}"
|
||||
field="default_value"
|
||||
>
|
||||
</RadioRow>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue'
|
||||
import RadioRow from '@/components/dynamics-form/items/radio/RadioRow.vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
|
||||
const addOption = () => {
|
||||
formValue.value.option_list.push({ value: '', label: '' })
|
||||
}
|
||||
|
||||
const delOption = (index: number) => {
|
||||
const option = formValue.value.option_list[index]
|
||||
if (option.value && formValue.value.default_value == option.value) {
|
||||
formValue.value.default_value = ''
|
||||
}
|
||||
formValue.value.option_list.splice(index, 1)
|
||||
}
|
||||
const formField = computed<FormField>(() => {
|
||||
return { field: '', ...getData() }
|
||||
})
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'RadioRow',
|
||||
attrs: {},
|
||||
default_value: formValue.value.default_value,
|
||||
text_field: 'label',
|
||||
value_field: 'value',
|
||||
option_list: formValue.value.option_list
|
||||
}
|
||||
}
|
||||
const rander = (form_data: any) => {
|
||||
formValue.value.option_list = form_data.option_list || []
|
||||
formValue.value.default_value = form_data.default_value
|
||||
}
|
||||
|
||||
defineExpose({ getData, rander })
|
||||
onMounted(() => {
|
||||
formValue.value.option_list = []
|
||||
formValue.value.default_value = ''
|
||||
if (formValue.value.show_default_value === undefined) {
|
||||
formValue.value.show_default_value = true
|
||||
}
|
||||
addOption()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.defaultValueItem {
|
||||
position: relative;
|
||||
.defaultValueCheckbox {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -35px;
|
||||
}
|
||||
}
|
||||
:deep(.el-form-item__label) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
:deep(.el-select-dropdown) {
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
<template>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
{{ $t('dynamicsForm.Select.label') }}
|
||||
<el-button link type="primary" @click.stop="addOption()">
|
||||
<el-icon class="mr-4">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
{{ $t('common.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.tag.label') }}</el-col
|
||||
>
|
||||
<el-col :span="12">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.Select.label') }}
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row
|
||||
style="width: 100%"
|
||||
v-for="(option, $index) in formValue.option_list"
|
||||
:key="$index"
|
||||
:gutter="10"
|
||||
class="mb-8"
|
||||
>
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].label" :placeholder="$t('dynamicsForm.tag.placeholder')"
|
||||
/></el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].value"
|
||||
:placeholder="$t('dynamicsForm.Select.label')"
|
||||
/></el-col>
|
||||
<el-col :span="1"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-button link class="ml-8" @click.stop="delOption($index)">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon> </el-button
|
||||
></el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="defaultValueItem"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:rules="
|
||||
formValue.required
|
||||
? [{ required: true, message: `${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}` }]
|
||||
: []
|
||||
"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
v-model="formValue.show_default_value"
|
||||
:label="$t('dynamicsForm.default.show')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<el-select v-model="formValue.default_value" :teleported="false" popper-class="default-select">
|
||||
<el-option
|
||||
v-for="(option, index) in formValue.option_list"
|
||||
:key="index"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
|
||||
const addOption = () => {
|
||||
formValue.value.option_list.push({ value: '', label: '' })
|
||||
}
|
||||
|
||||
const delOption = (index: number) => {
|
||||
const option = formValue.value.option_list[index]
|
||||
if (option.value && formValue.value.default_value == option.value) {
|
||||
formValue.value.default_value = ''
|
||||
}
|
||||
formValue.value.option_list.splice(index, 1)
|
||||
}
|
||||
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'SingleSelect',
|
||||
attrs: {},
|
||||
default_value: formValue.value.default_value,
|
||||
show_default_value: formValue.value.show_default_value,
|
||||
text_field: 'label',
|
||||
value_field: 'value',
|
||||
option_list: formValue.value.option_list
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
defineExpose({ getData, rander })
|
||||
onMounted(() => {
|
||||
formValue.value.option_list = []
|
||||
formValue.value.default_value = ''
|
||||
if (formValue.value.show_default_value === undefined) {
|
||||
formValue.value.show_default_value = true
|
||||
}
|
||||
addOption()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.defaultValueItem {
|
||||
position: relative;
|
||||
.defaultValueCheckbox {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -35px;
|
||||
}
|
||||
}
|
||||
:deep(.el-form-item__label) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
:deep(.el-select-dropdown) {
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
<template>
|
||||
<el-form-item :label="$t('dynamicsForm.Slider.showInput.label')" required prop="showInput">
|
||||
<el-switch v-model="formValue.showInput" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dynamicsForm.Slider.valueRange.label')" required>
|
||||
<el-col :span="11" style="padding-left: 0">
|
||||
<el-form-item
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('dynamicsForm.Slider.valueRange.minRequired'),
|
||||
trigger: 'change'
|
||||
}
|
||||
]"
|
||||
prop="min"
|
||||
>
|
||||
<el-input-number style="width: 100%" v-model="formValue.min" controls-position="right"
|
||||
/></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="2" class="text-center">
|
||||
<span class="text-gray-500">-</span>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('dynamicsForm.Slider.valueRange.maxRequired'),
|
||||
trigger: 'change'
|
||||
}
|
||||
]"
|
||||
prop="max"
|
||||
><el-input-number
|
||||
prop="max"
|
||||
style="width: 100%"
|
||||
v-model="formValue.max"
|
||||
:min="formValue.min > formValue.max ? formValue.min : undefined"
|
||||
controls-position="right"
|
||||
/></el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-col :span="11" style="padding-left: 0">
|
||||
<el-form-item
|
||||
:label="$t('dynamicsForm.Slider.step.label')"
|
||||
required
|
||||
prop="step"
|
||||
:rules="step_rules"
|
||||
>
|
||||
<el-input-number
|
||||
style="width: 100%"
|
||||
v-model="formValue.step"
|
||||
:min="0"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-form-item
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:rules="
|
||||
formValue.required
|
||||
? [{ required: true, message: $t('dynamicsForm.default.requiredMessage') }]
|
||||
: []
|
||||
"
|
||||
>
|
||||
<el-slider
|
||||
v-model="formValue.default_value"
|
||||
:show-input="formValue.showInput"
|
||||
:show-input-controls="false"
|
||||
:max="formValue.max"
|
||||
:min="formValue.min"
|
||||
:step="formValue.step == 0 ? 0.1 : formValue.step"
|
||||
:precision="formValue.precision"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeMount, watch } from 'vue'
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'Slider',
|
||||
attrs: {
|
||||
min: formValue.value.min,
|
||||
max: formValue.value.max,
|
||||
step: formValue.value.step,
|
||||
precision: formValue.value.precision,
|
||||
'show-input-controls': false,
|
||||
'show-input': formValue.value.showInput
|
||||
},
|
||||
props_info: {
|
||||
rules: [
|
||||
{
|
||||
message: formValue.value.label + ' ' + t('dynamicsForm.tip.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
required: formValue.value.required
|
||||
}
|
||||
]
|
||||
},
|
||||
show_default_value: true,
|
||||
default_value: formValue.value.default_value
|
||||
}
|
||||
}
|
||||
watch(
|
||||
() => formValue.value.min,
|
||||
() => {
|
||||
if (formValue.value.min > formValue.value.max) {
|
||||
formValue.value.max = formValue.value.min
|
||||
}
|
||||
}
|
||||
)
|
||||
const rander = (form_data: any) => {
|
||||
const attrs = form_data.attrs
|
||||
formValue.value.option_list = form_data.option_list
|
||||
formValue.value.min = attrs.min
|
||||
formValue.value.max = attrs.max
|
||||
formValue.value.step = attrs.step
|
||||
formValue.value.showInput = attrs['show-input']
|
||||
formValue.value.default_value = form_data.default_value
|
||||
}
|
||||
const step_rules = [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (!value) {
|
||||
callback(new Error(t('dynamicsForm.Slider.step.requiredMessage1')))
|
||||
return false
|
||||
}
|
||||
if (value === 0) {
|
||||
callback(new Error(t('dynamicsForm.Slider.step.requiredMessage2')))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
defineExpose({ getData, rander })
|
||||
onBeforeMount(() => {
|
||||
formValue.value.min = 0
|
||||
formValue.value.max = 20
|
||||
formValue.value.step = 0.1
|
||||
formValue.value.default_value = 1
|
||||
formValue.value.showInput = true
|
||||
})
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<el-form-item
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:rules="
|
||||
formValue.required
|
||||
? [{ required: true, message: `${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}` }]
|
||||
: []
|
||||
"
|
||||
>
|
||||
<el-switch v-model="formValue.default_value" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'SwitchInput',
|
||||
show_default_value: true,
|
||||
attrs: {},
|
||||
default_value: formValue.value.default_value
|
||||
}
|
||||
}
|
||||
|
||||
const rander = (form_data: any) => {
|
||||
formValue.value.default_value = form_data.default_value || false
|
||||
}
|
||||
defineExpose({ getData, rander })
|
||||
onMounted(() => {
|
||||
formValue.value.default_value = false
|
||||
})
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
<template>
|
||||
<el-form-item :label="$t('dynamicsForm.TextInput.length.label')" required>
|
||||
<el-row class="w-full">
|
||||
<el-col :span="11">
|
||||
<el-form-item
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('dynamicsForm.TextInput.length.minRequired'),
|
||||
trigger: 'change'
|
||||
}
|
||||
]"
|
||||
prop="minlength"
|
||||
>
|
||||
<el-input-number
|
||||
style="width: 100%"
|
||||
:min="1"
|
||||
:step="1"
|
||||
step-strictly
|
||||
v-model="formValue.minlength"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="2" class="text-center">
|
||||
<span>-</span>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('dynamicsForm.TextInput.length.maxRequired'),
|
||||
trigger: 'change'
|
||||
}
|
||||
]"
|
||||
prop="maxlength"
|
||||
>
|
||||
<el-input-number
|
||||
style="width: 100%"
|
||||
:min="formValue.minlength > formValue.maxlength ? formValue.minlength : 1"
|
||||
step-strictly
|
||||
:step="1"
|
||||
v-model="formValue.maxlength"
|
||||
controls-position="right"
|
||||
/></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
class="defaultValueItem"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:rules="
|
||||
formValue.required ? [{ required: true, message: `${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}` }, ...rules] : rules
|
||||
"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
v-model="formValue.show_default_value"
|
||||
:label="$t('dynamicsForm.default.show')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<el-input
|
||||
v-model="formValue.default_value"
|
||||
:maxlength="formValue.maxlength"
|
||||
:minlength="formValue.minlength"
|
||||
:placeholder="$t('dynamicsForm.default.placeholder')"
|
||||
show-word-limit
|
||||
type="text"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
}
|
||||
})
|
||||
watch(
|
||||
() => formValue.value.minlength,
|
||||
() => {
|
||||
if (formValue.value.minlength > formValue.value.maxlength) {
|
||||
formValue.value.maxlength = formValue.value.minlength
|
||||
}
|
||||
}
|
||||
)
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'TextInput',
|
||||
attrs: {
|
||||
maxlength: formValue.value.maxlength,
|
||||
minlength: formValue.value.minlength,
|
||||
'show-word-limit': true
|
||||
},
|
||||
default_value: formValue.value.default_value,
|
||||
show_default_value: formValue.value.show_default_value,
|
||||
props_info: {
|
||||
rules: formValue.value.required
|
||||
? [
|
||||
{ required: true, message: `${formValue.value.label} ${t('dynamicsForm.default.requiredMessage')}` },
|
||||
{
|
||||
min: formValue.value.minlength,
|
||||
max: formValue.value.maxlength,
|
||||
message: `${formValue.value.label}${t('dynamicsForm.TextInput.length.requiredMessage1')} ${formValue.value.minlength} ${t('dynamicsForm.TextInput.length.requiredMessage2')} ${formValue.value.maxlength} ${t('dynamicsForm.TextInput.length.requiredMessage3')}`,
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
min: formValue.value.minlength,
|
||||
max: formValue.value.maxlength,
|
||||
message: `${formValue.value.label}${t('dynamicsForm.TextInput.length.requiredMessage1')} ${formValue.value.minlength} ${t('dynamicsForm.TextInput.length.requiredMessage2')} ${formValue.value.maxlength} ${t('dynamicsForm.TextInput.length.requiredMessage3')}`,
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
const rander = (form_data: any) => {
|
||||
const attrs = form_data.attrs || {}
|
||||
formValue.value.minlength = attrs.minlength
|
||||
formValue.value.maxlength = attrs.maxlength
|
||||
formValue.value.default_value = form_data.default_value
|
||||
formValue.value.show_default_value = form_data.show_default_value
|
||||
}
|
||||
const rangeRules = [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (!formValue.value.minlength) {
|
||||
callback(new Error(t('dynamicsForm.TextInput.length.requiredMessage4')))
|
||||
}
|
||||
if (!formValue.value.maxlength) {
|
||||
callback(new Error(t('dynamicsForm.TextInput.length.requiredMessage4')))
|
||||
}
|
||||
return true
|
||||
},
|
||||
message: `${formValue.value.label} ${t('dynamicsForm.default.requiredMessage')}`
|
||||
}
|
||||
]
|
||||
const rules = computed(() => [
|
||||
{
|
||||
min: formValue.value.minlength,
|
||||
max: formValue.value.maxlength,
|
||||
message: `${t('dynamicsForm.TextInput.length.requiredMessage1')} ${formValue.value.minlength} ${t('dynamicsForm.TextInput.length.requiredMessage2')} ${formValue.value.maxlength} ${t('dynamicsForm.TextInput.length.requiredMessage3')}`,
|
||||
trigger: 'blur'
|
||||
}
|
||||
])
|
||||
|
||||
defineExpose({ getData, rander })
|
||||
onMounted(() => {
|
||||
formValue.value.minlength = 0
|
||||
formValue.value.maxlength = 200
|
||||
formValue.value.default_value = ''
|
||||
// console.log(formValue.value.show_default_value)
|
||||
if (formValue.value.show_default_value === undefined) {
|
||||
formValue.value.show_default_value = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.defaultValueItem {
|
||||
position: relative;
|
||||
.defaultValueCheckbox {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -35px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import type { App } from 'vue'
|
||||
import type { Dict } from '@/api/type/common'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
let components: Dict<any> = import.meta.glob('@/components/dynamics-form/**/**.vue', {
|
||||
eager: true
|
||||
})
|
||||
components = {
|
||||
...components,
|
||||
...import.meta.glob('@/components/dynamics-form/**/**/**.vue', {
|
||||
eager: true
|
||||
})
|
||||
}
|
||||
|
||||
const install = (app: App) => {
|
||||
Object.keys(components).forEach((key: string) => {
|
||||
const commentName: string = key
|
||||
.substring(key.lastIndexOf('/') + 1, key.length)
|
||||
.replace('.vue', '')
|
||||
if (key !== '/src/components/dynamics-form/constructor/index.vue') {
|
||||
app.component(commentName, components[key].default)
|
||||
}
|
||||
})
|
||||
app.component('DynamicsForm', DynamicsForm)
|
||||
}
|
||||
export default { install }
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
<template>
|
||||
<el-form
|
||||
@submit.prevent
|
||||
ref="ruleFormRef"
|
||||
label-width="130px"
|
||||
label-suffix=":"
|
||||
v-loading="loading"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<slot :form_value="formValue"></slot>
|
||||
<template v-for="item in formFieldList" :key="item.field">
|
||||
<FormItem
|
||||
ref="formFieldRef"
|
||||
:key="item.field"
|
||||
v-if="show(item)"
|
||||
@change="change(item, $event)"
|
||||
v-bind:modelValue="formValue[item.field]"
|
||||
:formfield="item"
|
||||
:trigger="trigger"
|
||||
:view="view"
|
||||
:initDefaultData="initDefaultData"
|
||||
:defaultItemWidth="defaultItemWidth"
|
||||
:other-params="otherParams"
|
||||
:form-value="formValue"
|
||||
:formfield-list="formFieldList"
|
||||
:parent_field="parent_field"
|
||||
>
|
||||
</FormItem>
|
||||
</template>
|
||||
</el-form>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { Dict } from '@/api/type/common'
|
||||
import FormItem from '@/components/dynamics-form/FormItem.vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import { ref, onBeforeMount, watch, type Ref } from 'vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import triggerApi from '@/api/model/provider'
|
||||
import type Result from '@/request/Result'
|
||||
import _ from 'lodash'
|
||||
|
||||
defineOptions({ name: 'dynamicsForm' })
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
// 页面渲染数据
|
||||
render_data: Promise<Result<Array<FormField>>> | string | Array<FormField>
|
||||
// 调用接口所需要的其他参数
|
||||
otherParams?: any
|
||||
// 是否只读
|
||||
view?: boolean
|
||||
// 默认每个宽度
|
||||
defaultItemWidth?: string
|
||||
|
||||
parent_field?: string
|
||||
|
||||
modelValue?: Dict<any>
|
||||
}>(),
|
||||
{ view: false, defaultItemWidth: '75%', otherParams: () => {} }
|
||||
)
|
||||
|
||||
const formValue = ref<Dict<any>>({})
|
||||
|
||||
const loading = ref<boolean>(false)
|
||||
|
||||
const formFieldList = ref<Array<FormField>>([])
|
||||
|
||||
const ruleFormRef = ref<FormInstance>()
|
||||
|
||||
const formFieldRef = ref<Array<InstanceType<typeof FormItem>>>([])
|
||||
/**
|
||||
* 当前 field是否展示
|
||||
* @param field
|
||||
*/
|
||||
const show = (field: FormField) => {
|
||||
if (field.relation_show_field_dict) {
|
||||
let keys = Object.keys(field.relation_show_field_dict)
|
||||
for (const index in keys) {
|
||||
const key = keys[index]
|
||||
let v = _.get(formValue.value, key)
|
||||
if (v && v !== undefined && v !== null) {
|
||||
let values = field.relation_show_field_dict[key]
|
||||
if (values && values.length > 0) {
|
||||
return values.includes(v)
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
/**
|
||||
* 表单字段修改
|
||||
* @param field
|
||||
* @param value
|
||||
*/
|
||||
const change = (field: FormField, value: any) => {
|
||||
formValue.value[field.field] = value
|
||||
}
|
||||
|
||||
watch(
|
||||
formValue,
|
||||
() => {
|
||||
emit('update:modelValue', formValue.value)
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
/**
|
||||
* 触发器,用户获取子表单 或者 下拉选项
|
||||
* @param field
|
||||
* @param loading
|
||||
*/
|
||||
const trigger = (field: FormField, loading: Ref<boolean>) => {
|
||||
if (field.provider && field.method) {
|
||||
return triggerApi
|
||||
.trigger(
|
||||
field.provider,
|
||||
field.method,
|
||||
{
|
||||
...props.otherParams,
|
||||
...formValue.value
|
||||
},
|
||||
loading
|
||||
)
|
||||
.then((ok) => {
|
||||
if (field.trigger_type === 'CHILD_FORMS') {
|
||||
field.children = ok.data as Array<FormField>
|
||||
} else {
|
||||
field.option_list = ok.data as Array<any>
|
||||
}
|
||||
})
|
||||
}
|
||||
return Promise.resolve([])
|
||||
}
|
||||
/**
|
||||
* 初始化默认数据
|
||||
*/
|
||||
const initDefaultData = (formField: FormField) => {
|
||||
if (
|
||||
formField.default_value &&
|
||||
(formValue.value[formField.field] === undefined ||
|
||||
formValue.value[formField.field] === null ||
|
||||
!formValue.value[formField.field]) &&
|
||||
formValue.value[formField.field] != false
|
||||
) {
|
||||
if (formField.show_default_value === true) {
|
||||
formValue.value[formField.field] = formField.default_value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
render(props.render_data, props.modelValue)
|
||||
})
|
||||
|
||||
const render = (
|
||||
render_data: string | Array<FormField> | Promise<Result<Array<FormField>>>,
|
||||
data?: Dict<any>
|
||||
) => {
|
||||
if (typeof render_data == 'string') {
|
||||
triggerApi.get(render_data, {}, loading).then((ok) => {
|
||||
formFieldList.value = ok.data
|
||||
})
|
||||
} else if (render_data instanceof Array) {
|
||||
formFieldList.value = render_data
|
||||
} else {
|
||||
render_data.then((ok) => {
|
||||
formFieldList.value = ok.data
|
||||
})
|
||||
}
|
||||
const form_data = data ? data : {}
|
||||
if (form_data) {
|
||||
const value = formFieldList.value
|
||||
.map((item) => {
|
||||
if (form_data[item.field] !== undefined) {
|
||||
if (item.value_field && item.option_list && item.option_list.length > 0) {
|
||||
const value_field = item.value_field
|
||||
const find = item.option_list?.find((i) => {
|
||||
if (typeof form_data[item.field] === 'string') {
|
||||
return i[value_field] === form_data[item.field]
|
||||
} else {
|
||||
return form_data[item.field].indexOf([value_field]) === -1
|
||||
}
|
||||
})
|
||||
if (find) {
|
||||
return { [item.field]: form_data[item.field] }
|
||||
}
|
||||
if (item.show_default_value === true || item.show_default_value === undefined) {
|
||||
return { [item.field]: item.default_value }
|
||||
}
|
||||
} else {
|
||||
return { [item.field]: form_data[item.field] }
|
||||
}
|
||||
}
|
||||
if (item.show_default_value === true || item.show_default_value === undefined) {
|
||||
return { [item.field]: item.default_value }
|
||||
}
|
||||
return {}
|
||||
})
|
||||
.reduce((x, y) => ({ ...x, ...y }), {})
|
||||
formValue.value = _.cloneDeep(value)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 校验函数
|
||||
*/
|
||||
const validate = () => {
|
||||
return Promise.all([
|
||||
...formFieldRef.value.map((item) => item.validate()),
|
||||
ruleFormRef.value ? ruleFormRef.value.validate() : Promise.resolve()
|
||||
])
|
||||
}
|
||||
|
||||
// 暴露获取当前表单数据函数
|
||||
defineExpose({
|
||||
initDefaultData,
|
||||
validate,
|
||||
render,
|
||||
ruleFormRef
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<template>
|
||||
<el-date-picker v-bind="$attrs" />
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<div style="width: 100%" class="function-CodemirrorEditor">
|
||||
<Codemirror
|
||||
v-bind="$attrs"
|
||||
ref="cmRef"
|
||||
v-model="model_value"
|
||||
:extensions="extensions"
|
||||
:style="codemirrorStyle"
|
||||
:tab-size="4"
|
||||
:autofocus="true"
|
||||
/>
|
||||
<div class="function-CodemirrorEditor__format">
|
||||
<el-button text type="info" @click="format" class="magnify">
|
||||
<el-icon><DocumentChecked /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="function-CodemirrorEditor__footer">
|
||||
<el-button text type="info" @click="openCodemirrorDialog" class="magnify">
|
||||
<AppIcon iconName="app-magnify" style="font-size: 16px"></AppIcon>
|
||||
</el-button>
|
||||
</div>
|
||||
<!-- Codemirror 弹出层 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="$t('dynamicsForm.default.label')"
|
||||
append-to-body
|
||||
fullscreen
|
||||
>
|
||||
<Codemirror
|
||||
v-model="cloneContent"
|
||||
:extensions="extensions"
|
||||
:style="codemirrorStyle"
|
||||
:tab-size="4"
|
||||
:autofocus="true"
|
||||
style="
|
||||
height: calc(100vh - 160px) !important;
|
||||
border: 1px solid #bbbfc4;
|
||||
border-radius: 4px;
|
||||
"
|
||||
/>
|
||||
<template #footer>
|
||||
<div class="dialog-footer mt-24">
|
||||
<el-button type="primary" @click="submitDialog"> {{ $t('common.confirm') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { json, jsonParseLinter } from '@codemirror/lang-json'
|
||||
import { oneDark } from '@codemirror/theme-one-dark'
|
||||
import { Codemirror } from 'vue-codemirror'
|
||||
import { linter } from '@codemirror/lint'
|
||||
import { computed, ref } from 'vue'
|
||||
import { t } from '@/locales'
|
||||
const props = withDefaults(defineProps<{ modelValue?: any }>(), { modelValue: () => {} })
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const cache_model_value_str = ref<string>()
|
||||
|
||||
const model_value = computed({
|
||||
get: () => {
|
||||
if (cache_model_value_str.value) {
|
||||
return cache_model_value_str.value
|
||||
}
|
||||
return JSON.stringify(props.modelValue, null, 4)
|
||||
},
|
||||
set: (v: string) => {
|
||||
if (!v) {
|
||||
emit('update:modelValue', JSON.parse('{}'))
|
||||
} else {
|
||||
try {
|
||||
cache_model_value_str.value = v
|
||||
const result = JSON.parse(v)
|
||||
emit('update:modelValue', result)
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const extensions = [json(), linter(jsonParseLinter()), oneDark]
|
||||
|
||||
const codemirrorStyle = {
|
||||
height: '210px!important',
|
||||
width: '100%'
|
||||
}
|
||||
|
||||
// 弹出框相关代码
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
const cloneContent = ref<string>('')
|
||||
|
||||
const openCodemirrorDialog = () => {
|
||||
cloneContent.value = model_value.value
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const format = () => {
|
||||
try {
|
||||
const json_str = JSON.parse(model_value.value)
|
||||
model_value.value = JSON.stringify(json_str, null, 4)
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function submitDialog() {
|
||||
model_value.value = cloneContent.value
|
||||
dialogVisible.value = false
|
||||
}
|
||||
/**
|
||||
* 校验格式
|
||||
* @param rule
|
||||
* @param value
|
||||
* @param callback
|
||||
*/
|
||||
const validate_rules = (rule: any, value: any, callback: any) => {
|
||||
if (model_value.value) {
|
||||
try {
|
||||
JSON.parse(model_value.value)
|
||||
} catch (e) {
|
||||
callback(new Error(t('dynamicsForm.tip.requiredMessage')))
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
defineExpose({ validate_rules: validate_rules })
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.function-CodemirrorEditor__footer {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
.function-CodemirrorEditor {
|
||||
position: relative;
|
||||
}
|
||||
.function-CodemirrorEditor__format {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<template>
|
||||
<el-input v-bind="$attrs" :show-password="true"></el-input>
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<template>
|
||||
<el-input v-bind="$attrs" />
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
<template v-loading="_loading">
|
||||
<div class="arrt-object-card flex w-full">
|
||||
<el-card class="box-card" :style="style" v-for="(item, index) in _data" :key="index">
|
||||
<DynamicsForm
|
||||
:style="formStyle"
|
||||
:view="view"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
ref="ceFormRef"
|
||||
v-model="_data[index]"
|
||||
:model="_data[index]"
|
||||
:other-params="other"
|
||||
:render_data="render_data()"
|
||||
v-bind="attr"
|
||||
:parent_field="formField.field + '.' + index"
|
||||
></DynamicsForm>
|
||||
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
|
||||
<el-button text @click.stop="deleteDataset(item)" class="delete-button">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="card-add box-card" @click="add_card">
|
||||
<div class="flex-center">
|
||||
<AppIcon iconName="Plus" class="add-icon layout-bg p-8 border-r-4" />
|
||||
<span>{{ add_msg }}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import _ from 'lodash'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
import Result from '@/request/Result'
|
||||
const props = defineProps<{
|
||||
modelValue?: Array<any>
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
}>()
|
||||
|
||||
const render_data = () => {
|
||||
return Promise.resolve(Result.success(props.formField.children as Array<FormField>))
|
||||
}
|
||||
const deleteDataset = (item: any) => {
|
||||
_data.value = _data.value.filter((row) => row !== item)
|
||||
}
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
// 校验实例对象
|
||||
const dynamicsFormRef = ref<Array<InstanceType<typeof DynamicsForm>>>([])
|
||||
|
||||
const _data = computed<Array<any>>({
|
||||
get() {
|
||||
if (props.modelValue) {
|
||||
return props.modelValue
|
||||
} else {
|
||||
emit('update:modelValue', [{}])
|
||||
return []
|
||||
}
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
|
||||
const props_info = computed(() => {
|
||||
return props.formField.props_info ? props.formField.props_info : {}
|
||||
})
|
||||
const add_msg = computed(() => {
|
||||
return props_info.value.add_msg ? props_info.value.add_msg : '添加'
|
||||
})
|
||||
/**
|
||||
* 添加一个card
|
||||
*/
|
||||
const add_card = () => {
|
||||
_data.value = [..._data.value, {}]
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件样式
|
||||
*/
|
||||
const formStyle = computed(() => {
|
||||
return props_info.value.form_style ? props_info.value.form_style : {}
|
||||
})
|
||||
const style = computed(() => {
|
||||
return props_info.value.style ? props_info.value.style : {}
|
||||
})
|
||||
const attr = computed(() => {
|
||||
if (props.formField.attrs) {
|
||||
return props.formField.attrs
|
||||
}
|
||||
return {}
|
||||
})
|
||||
|
||||
/**
|
||||
* 校验方法
|
||||
*/
|
||||
function validate() {
|
||||
return Promise.all(dynamicsFormRef.value.map((item) => item.validate()))
|
||||
}
|
||||
const other = computed(() => {
|
||||
return { ...(props.formValue ? props.formValue : {}), ...props.otherParams }
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
validate,
|
||||
field: props.field
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.arrt-object-card {
|
||||
.box-card {
|
||||
width: 30%;
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
.card-add {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
min-height: var(--card-min-height);
|
||||
border: 1px dashed var(--el-color-primary);
|
||||
background: var(--el-disabled-bg-color);;
|
||||
padding-bottom: 20px;
|
||||
|
||||
.add-icon {
|
||||
font-size: 14px;
|
||||
border: 1px solid var(--app-border-color-dark);
|
||||
margin-right: 12px;
|
||||
}
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
background: #ffffff;
|
||||
.add-icon {
|
||||
background: #ffffff;
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
.delete-button {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 10px;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<el-card :style="style">
|
||||
<DynamicsForm
|
||||
:read-only="view"
|
||||
:style="formStyle"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
ref="dynamicsFormRef"
|
||||
v-model="data"
|
||||
:other-params="other"
|
||||
:render_data="formField.children ? formField.children : []"
|
||||
v-bind="$attrs"
|
||||
:parent_field="formField.field"
|
||||
></DynamicsForm>
|
||||
</el-card>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: any
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
}>()
|
||||
|
||||
const data = computed({
|
||||
get: () => {
|
||||
if (props.modelValue) {
|
||||
return props.modelValue
|
||||
}
|
||||
return {}
|
||||
},
|
||||
set: ($event) => {
|
||||
emit('update:modelValue', $event)
|
||||
}
|
||||
})
|
||||
|
||||
const other = computed(() => {
|
||||
return { ...(props.formfieldList ? props.formfieldList : {}), ...props.otherParams }
|
||||
})
|
||||
// 校验实例对象
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
/**
|
||||
* 组件样式
|
||||
*/
|
||||
const formStyle = computed(() => {
|
||||
return props_info.value.form_style ? props_info.value.form_style : {}
|
||||
})
|
||||
const props_info = computed(() => {
|
||||
return props.formField.props_info ? props.formField.props_info : {}
|
||||
})
|
||||
|
||||
const style = computed(() => {
|
||||
return props_info.value.style ? props_info.value.style : {}
|
||||
})
|
||||
/**
|
||||
* 校验方法
|
||||
*/
|
||||
function validate() {
|
||||
if (dynamicsFormRef.value) {
|
||||
return dynamicsFormRef.value.validate()
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
||||
defineExpose({
|
||||
validate
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<template v-loading="_loading">
|
||||
<div style="width: 100%">
|
||||
<el-tabs v-model="activeTab" editable @edit="handleTabsEdit" type="card">
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in _data"
|
||||
:key="index"
|
||||
:label="tabs_label + (index + 1)"
|
||||
:name="index"
|
||||
>
|
||||
<template v-if="formField.children">
|
||||
<el-card :style="style">
|
||||
<DynamicsForm
|
||||
:style="formStyle"
|
||||
:view="view"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
ref="ceFormRef"
|
||||
v-model="_data[index]"
|
||||
:model="_data[index]"
|
||||
:other-params="other"
|
||||
:render_data="render_data()"
|
||||
v-bind="attr"
|
||||
:parent_field="formField.field + '.' + index"
|
||||
></DynamicsForm>
|
||||
</el-card>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import _ from 'lodash'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
import Result from '@/request/Result'
|
||||
import type { TabPaneName } from 'element-plus'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: Array<any>
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
}>()
|
||||
|
||||
const render_data = () => {
|
||||
return Promise.resolve(Result.success(props.formField.children as Array<FormField>))
|
||||
}
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
// 校验实例对象
|
||||
const dynamicsFormRef = ref<Array<InstanceType<typeof DynamicsForm>>>([])
|
||||
|
||||
const _data = computed<Array<any>>({
|
||||
get() {
|
||||
if (props.modelValue) {
|
||||
return props.modelValue
|
||||
} else {
|
||||
emit('update:modelValue', [{}])
|
||||
return []
|
||||
}
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
|
||||
const props_info = computed(() => {
|
||||
return props.formField.props_info ? props.formField.props_info : {}
|
||||
})
|
||||
|
||||
const tabs_label = computed(() => {
|
||||
return props_info.value.tabs_label ? props_info.value.tabs_label : 'label'
|
||||
})
|
||||
/**
|
||||
* 组件样式
|
||||
*/
|
||||
const formStyle = computed(() => {
|
||||
return props_info.value.form_style ? props_info.value.form_style : {}
|
||||
})
|
||||
|
||||
const attr = computed(() => {
|
||||
if (props.formField.attrs) {
|
||||
return props.formField.attrs
|
||||
}
|
||||
return {}
|
||||
})
|
||||
const activeTab = ref(0)
|
||||
|
||||
/**
|
||||
* 校验方法
|
||||
*/
|
||||
function validate() {
|
||||
return Promise.all(dynamicsFormRef.value.map((item) => item.validate()))
|
||||
}
|
||||
const other = computed(() => {
|
||||
return { ...(props.formValue ? props.formValue : {}), ...props.otherParams }
|
||||
})
|
||||
const style = computed(() => {
|
||||
return props_info.value.style ? props_info.value.style : {}
|
||||
})
|
||||
|
||||
const handleTabsEdit = (targetName: TabPaneName | undefined, action: 'remove' | 'add') => {
|
||||
if (action === 'add') {
|
||||
_data.value = [..._data.value, {}]
|
||||
activeTab.value = _data.value.length
|
||||
} else if (action === 'remove') {
|
||||
const update_value = _data.value.filter((item, index) => index != targetName)
|
||||
_data.value = update_value
|
||||
activeTab.value = update_value.length - 1
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
validate,
|
||||
field: props.field
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="flex-between mr-4">
|
||||
<span>{{ label }}</span>
|
||||
</div>
|
||||
<el-tooltip effect="dark" placement="right">
|
||||
<template #content
|
||||
><div style="max-width: 200px">{{ tooltip }}</div></template
|
||||
>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon" style="flex-shrink: 0"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
label: string
|
||||
tooltip: string
|
||||
}>()
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<el-radio-group v-bind="$attrs">
|
||||
<el-radio v-for="(item, index) in option_list" :key="index" :label="item[valueField]">
|
||||
<div v-html="label(item)"></div>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import _ from 'lodash'
|
||||
|
||||
const props = defineProps<{
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
}>()
|
||||
|
||||
const textField = computed(() => {
|
||||
return props.formField.text_field ? props.formField.text_field : 'key'
|
||||
})
|
||||
|
||||
const valueField = computed(() => {
|
||||
return props.formField.value_field ? props.formField.value_field : 'value'
|
||||
})
|
||||
|
||||
const option_list = computed(() => {
|
||||
return props.formField.option_list ? props.formField.option_list : []
|
||||
})
|
||||
|
||||
const label = (option: any) => {
|
||||
return option[textField.value]
|
||||
}
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<el-radio-group v-bind="$attrs">
|
||||
<el-radio-button v-for="(item, index) in option_list" :key="index" :label="item[valueField]">
|
||||
<div v-html="label(item)"></div>
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import _ from 'lodash'
|
||||
|
||||
const props = defineProps<{
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
}>()
|
||||
|
||||
const textField = computed(() => {
|
||||
return props.formField.text_field ? props.formField.text_field : 'key'
|
||||
})
|
||||
|
||||
const valueField = computed(() => {
|
||||
return props.formField.value_field ? props.formField.value_field : 'value'
|
||||
})
|
||||
|
||||
const option_list = computed(() => {
|
||||
return props.formField.option_list ? props.formField.option_list : []
|
||||
})
|
||||
|
||||
const label = (option: any) => {
|
||||
return option[textField.value]
|
||||
}
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
<template>
|
||||
<div class="radio_content" :style="radioContentStyle">
|
||||
<el-row :gutter="12" class="w-full">
|
||||
<template v-for="(item, index) in option_list" :key="index">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
|
||||
<el-card
|
||||
:key="item.value"
|
||||
class="item break-all"
|
||||
shadow="never"
|
||||
style="--el-card-padding: 12px 16px"
|
||||
:class="[
|
||||
inputDisabled ? 'is-disabled' : '',
|
||||
modelValue == item[valueField] ? 'active' : ''
|
||||
]"
|
||||
@click="inputDisabled ? () => {} : selected(item[valueField])"
|
||||
>
|
||||
{{ item[textField] }}
|
||||
</el-card>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, inject } from 'vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import { useFormDisabled, formItemContextKey } from 'element-plus'
|
||||
|
||||
const inputDisabled = useFormDisabled()
|
||||
|
||||
const props = defineProps<{
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
// 选中的值
|
||||
modelValue?: any
|
||||
disabled?: boolean
|
||||
}>()
|
||||
const elFormItem = inject(formItemContextKey, void 0)
|
||||
const selected = (activeValue: string | number) => {
|
||||
emit('update:modelValue', activeValue)
|
||||
if (elFormItem?.validate) {
|
||||
elFormItem.validate('change')
|
||||
}
|
||||
}
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
const width = ref<number>()
|
||||
const radioContentStyle = computed(() => {
|
||||
if (width.value) {
|
||||
if (width.value < 350) {
|
||||
return { '--maxkb-radio-card-width': '316px' }
|
||||
} else if (width.value > 770) {
|
||||
return { '--maxkb-radio-card-width': '378px' }
|
||||
} else {
|
||||
return { '--maxkb-radio-card-width': '100%' }
|
||||
}
|
||||
}
|
||||
return {}
|
||||
})
|
||||
|
||||
const textField = computed(() => {
|
||||
return props.formField.text_field ? props.formField.text_field : 'key'
|
||||
})
|
||||
|
||||
const valueField = computed(() => {
|
||||
return props.formField.value_field ? props.formField.value_field : 'value'
|
||||
})
|
||||
|
||||
const option_list = computed(() => {
|
||||
return props.formField.option_list ? props.formField.option_list : []
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.radio_content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
|
||||
.is-disabled {
|
||||
border: 1px solid var(--el-card-border-color);
|
||||
background-color: var(--el-fill-color-light);
|
||||
color: var(--el-text-color-placeholder);
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
.active {
|
||||
border: 1px solid var(--el-color-primary);
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
.item {
|
||||
line-height: 22px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: var(--maxkb-radio-card-width, 100%);
|
||||
margin: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<div class="radio_content">
|
||||
<div
|
||||
v-for="item in option_list"
|
||||
:key="item.value"
|
||||
class="item"
|
||||
:class="[inputDisabled ? 'is-disabled' : '', modelValue == item[valueField] ? 'active' : '']"
|
||||
@click="selected(item[valueField])"
|
||||
>
|
||||
{{ item[textField] }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject } from 'vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import { useFormDisabled, formItemContextKey } from 'element-plus'
|
||||
const inputDisabled = useFormDisabled()
|
||||
const props = defineProps<{
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
// 选中的值
|
||||
modelValue?: any
|
||||
}>()
|
||||
const elFormItem = inject(formItemContextKey, void 0)
|
||||
const selected = (activeValue: string | number) => {
|
||||
emit('update:modelValue', activeValue)
|
||||
if (elFormItem?.validate) {
|
||||
elFormItem.validate('change')
|
||||
}
|
||||
}
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const textField = computed(() => {
|
||||
return props.formField.text_field ? props.formField.text_field : 'key'
|
||||
})
|
||||
|
||||
const valueField = computed(() => {
|
||||
return props.formField.value_field ? props.formField.value_field : 'value'
|
||||
})
|
||||
|
||||
const option_list = computed(() => {
|
||||
return props.formField.option_list ? props.formField.option_list : []
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.radio_content {
|
||||
height: 32px;
|
||||
display: inline-flex;
|
||||
border: 1px solid #bbbfc4;
|
||||
border-radius: 4px;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #1f2329;
|
||||
padding: 3px 4px;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
.is-disabled {
|
||||
border: 1px solid var(--el-card-border-color);
|
||||
background-color: var(--el-fill-color-light);
|
||||
color: var(--el-text-color-placeholder);
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
.active {
|
||||
border-radius: 4px;
|
||||
background: var(--el-color-primary-light-9);
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
.item {
|
||||
cursor: pointer;
|
||||
margin: 0px 2px;
|
||||
padding: 2px 8px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
&:last-child {
|
||||
margin: 0 4px 0 2px;
|
||||
}
|
||||
&:first-child {
|
||||
margin: 0 2px 0 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<el-select
|
||||
class="m-2"
|
||||
multiple
|
||||
filterable
|
||||
clearable
|
||||
v-bind="$attrs"
|
||||
v-model="_modelValue"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in option_list"
|
||||
:key="index"
|
||||
:label="label(item)"
|
||||
:value="item[valueField]"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import { computed, ref } from 'vue'
|
||||
import _ from 'lodash'
|
||||
const rowTemp = ref<any>()
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: Array<any>
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const _modelValue = computed({
|
||||
get() {
|
||||
if (props.modelValue) {
|
||||
return props.modelValue
|
||||
}
|
||||
return []
|
||||
},
|
||||
set($event) {
|
||||
emit('update:modelValue', $event)
|
||||
}
|
||||
})
|
||||
const textField = computed(() => {
|
||||
return props.formField.text_field ? props.formField.text_field : 'key'
|
||||
})
|
||||
|
||||
const valueField = computed(() => {
|
||||
return props.formField.value_field ? props.formField.value_field : 'value'
|
||||
})
|
||||
|
||||
const option_list = computed(() => {
|
||||
return props.formField.option_list ? props.formField.option_list : []
|
||||
})
|
||||
|
||||
const label = (option: any) => {
|
||||
return option[textField.value]
|
||||
}
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<el-select
|
||||
filterable
|
||||
:teleported="true"
|
||||
popper-class="dynamics-single-select"
|
||||
clearable
|
||||
v-bind="$attrs"
|
||||
v-model="_modelValue"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in option_list"
|
||||
:key="index"
|
||||
teleported
|
||||
:label="label(item)"
|
||||
:value="item[valueField]"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import { computed, ref } from 'vue'
|
||||
import _ from 'lodash'
|
||||
const rowTemp = ref<any>()
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const _modelValue = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
emit('change', props.formField)
|
||||
}
|
||||
})
|
||||
const textField = computed(() => {
|
||||
return props.formField.text_field ? props.formField.text_field : 'key'
|
||||
})
|
||||
|
||||
const valueField = computed(() => {
|
||||
return props.formField.value_field ? props.formField.value_field : 'value'
|
||||
})
|
||||
|
||||
const option_list = computed(() => {
|
||||
return props.formField.option_list ? props.formField.option_list : []
|
||||
})
|
||||
|
||||
const label = (option: any) => {
|
||||
//置空
|
||||
if (props.modelValue && option_list.value) {
|
||||
const oldItem = option_list.value.find((item) => item[valueField.value] === props.modelValue)
|
||||
if (!oldItem) {
|
||||
emit('update:modelValue', undefined)
|
||||
}
|
||||
}
|
||||
|
||||
return option[textField.value]
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.dynamics-single-select {
|
||||
.el-select-dropdown {
|
||||
max-width: 1px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<template>
|
||||
<el-slider v-bind="$attrs" show-input :show-input-controls="false" class="custom-slider" />
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
<style lang="scss" scoped>
|
||||
.custom-slider {
|
||||
.el-input-number.is-without-controls .el-input__wrapper {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<el-switch v-bind="$attrs" />
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<template>
|
||||
<div class="progress-table-item">
|
||||
<el-popover placement="top-start" :title="row[text_field]" :width="200" trigger="hover">
|
||||
<template #reference>
|
||||
<el-progress v-bind="$attrs" :percentage="row[value_field]"></el-progress
|
||||
></template>
|
||||
<div>
|
||||
<el-row v-for="(item, index) in view_card" :key="index">
|
||||
<el-col :span="6">{{ item.title }}</el-col>
|
||||
<el-col :span="18"> <span class="value" :innerHTML="value_html(item)"> </span></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
const props = defineProps<{
|
||||
/**
|
||||
*表单渲染Item column
|
||||
*/
|
||||
column: any
|
||||
/**
|
||||
* 这一行数据
|
||||
*/
|
||||
row: any
|
||||
}>()
|
||||
const rowRef = ref<any>()
|
||||
|
||||
function evalF(text: string, row: any) {
|
||||
rowRef.value = row
|
||||
return eval(text)
|
||||
}
|
||||
const props_info = computed(() => {
|
||||
return props.column.props_info ? props.column.props_info : {}
|
||||
})
|
||||
const text_field = computed(() => {
|
||||
return props.column.text_field ? props.column.text_field : 'key'
|
||||
})
|
||||
const value_field = computed(() => {
|
||||
return props.column.value_field ? props.column.value_field : 'value'
|
||||
})
|
||||
|
||||
const value_html = (view_card_item: any) => {
|
||||
if (view_card_item.type === 'eval') {
|
||||
return evalF(view_card_item.value_field, props.row)
|
||||
} else {
|
||||
return props.row[view_card_item.value_field]
|
||||
}
|
||||
}
|
||||
|
||||
const view_card = computed(() => {
|
||||
return props_info.value.view_card ? props_info.value.view_card : []
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@mixin valueScss() {
|
||||
color: rgba(31, 35, 41, 1);
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
.progress-table-item {
|
||||
.value {
|
||||
float: right;
|
||||
@include valueScss;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
<template>
|
||||
<div class="table-checkbox">
|
||||
<div class="header">
|
||||
<div class="title">{{ title }}</div>
|
||||
|
||||
<el-input
|
||||
v-model="filterText"
|
||||
:validate-event="false"
|
||||
:placeholder="$t('dynamicsForm.searchBar.placeholder')"
|
||||
class="input-with-select"
|
||||
style="--el-color-danger: #c0c4cc"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button :icon="Search" />
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
ref="multipleTableRef"
|
||||
:data="tableData"
|
||||
highlight-current-row
|
||||
style="width: 100%; height: 100%; --el-bg-color: #f5f6f7"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
v-bind="column"
|
||||
:label="column.label"
|
||||
>
|
||||
<template #default="scope">
|
||||
<template v-if="column.type === 'component'">
|
||||
<TableColumn :column="column" :row="scope.row"></TableColumn>
|
||||
</template>
|
||||
<template v-else-if="column.type === 'eval'">
|
||||
<span v-html="evalF(column.property, scope.row)"></span
|
||||
></template>
|
||||
<template v-else>
|
||||
<span>{{ scope.row[column.property] }}</span></template
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="msg" v-show="props.modelValue">
|
||||
{{ activeMsg }}
|
||||
<span class="active">
|
||||
{{ activeText }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import type { ElTable } from 'element-plus'
|
||||
|
||||
import _ from 'lodash'
|
||||
import TableColumn from '@/components/dynamics-form/items/table/TableColumn.vue'
|
||||
const filterText = ref<string>('')
|
||||
const props = defineProps<{
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
// 选中的值
|
||||
modelValue?: Array<any>
|
||||
}>()
|
||||
const rowTemp = ref<any>()
|
||||
const evalF: (text: string, row: any) => string = (text: string, row: any) => {
|
||||
rowTemp.value = row
|
||||
return eval(text)
|
||||
}
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
|
||||
|
||||
const _data = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
emit('change', props.formField)
|
||||
}
|
||||
})
|
||||
const handleSelectionChange = (val: any[]) => {
|
||||
_data.value = val.map((row) => row[valueField.value])
|
||||
}
|
||||
|
||||
const propsInfo = computed(() => {
|
||||
return props.formField.props_info ? props.formField.props_info : {}
|
||||
})
|
||||
|
||||
const activeMsg = computed(() => {
|
||||
return propsInfo.value.active_msg ? propsInfo.value.active_msg : ''
|
||||
})
|
||||
const title = computed(() => {
|
||||
return propsInfo.value.title ? propsInfo.value.title : ''
|
||||
})
|
||||
const tableColumns = computed(() => {
|
||||
return propsInfo.value.table_columns ? propsInfo.value.table_columns : []
|
||||
})
|
||||
|
||||
const option_list = computed(() => {
|
||||
return props.formField.option_list ? props.formField.option_list : []
|
||||
})
|
||||
|
||||
const textField = computed(() => {
|
||||
return props.formField.text_field ? props.formField.text_field : 'key'
|
||||
})
|
||||
|
||||
const valueField = computed(() => {
|
||||
return props.formField.value_field ? props.formField.value_field : 'value'
|
||||
})
|
||||
|
||||
const tableData = computed(() => {
|
||||
if (option_list.value) {
|
||||
if (filterText.value) {
|
||||
return option_list.value.filter((item: any) =>
|
||||
tableColumns.value.some((c: any) => {
|
||||
let v = ''
|
||||
if (c.type === 'eval') {
|
||||
v = evalF(c.property, item)
|
||||
} else if (c.type === 'component') {
|
||||
return false
|
||||
} else {
|
||||
v = item[c.property]
|
||||
}
|
||||
return typeof v == 'string' ? v.indexOf(filterText.value) >= 0 : false
|
||||
})
|
||||
)
|
||||
} else {
|
||||
return option_list.value.filter((item: any) => item[valueField.value])
|
||||
}
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
/**
|
||||
* 监听表格数据,设置默认值
|
||||
*/
|
||||
watch(
|
||||
() => tableData.value,
|
||||
() => {
|
||||
if (tableData.value && tableData.value.length > 0) {
|
||||
const defaultItem = _.head(tableData.value)
|
||||
let defaultItemValue = _.get(defaultItem, valueField.value)
|
||||
if (props.modelValue) {
|
||||
const row = option_list.value.find((f: any) => f[valueField.value] === props.modelValue)
|
||||
if (row) {
|
||||
defaultItemValue = row[valueField.value]
|
||||
}
|
||||
}
|
||||
emit('update:modelValue', defaultItemValue)
|
||||
} else {
|
||||
emit('update:modelValue', undefined)
|
||||
}
|
||||
emit('change', props.formField)
|
||||
}
|
||||
)
|
||||
|
||||
const activeText = computed(() => {
|
||||
if (props.modelValue) {
|
||||
const rows = option_list.value.filter((f: any) =>
|
||||
props.modelValue?.includes(f[valueField.value])
|
||||
)
|
||||
if (rows) {
|
||||
if (rows.length > 3) {
|
||||
return (
|
||||
rows
|
||||
.map((row) => row[textField.value])
|
||||
.splice(0, 3)
|
||||
.join(',') + '...'
|
||||
)
|
||||
} else {
|
||||
return rows.map((row) => row[textField.value]).join(',')
|
||||
}
|
||||
}
|
||||
}
|
||||
return props.modelValue
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.table-checkbox {
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
.title {
|
||||
color: #1f2329;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.input-with-select {
|
||||
width: 45%;
|
||||
}
|
||||
}
|
||||
.msg {
|
||||
margin-top: 12px;
|
||||
color: rgba(100, 106, 115, 1);
|
||||
.active {
|
||||
margin-left: 3px;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<template>
|
||||
<component :is="column.property" v-bind="attrs" :column="column" :row="row"></component>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import _ from 'lodash'
|
||||
const props = defineProps<{
|
||||
/**
|
||||
*表单渲染Item column
|
||||
*/
|
||||
column: any
|
||||
/**
|
||||
* 这一行数据
|
||||
*/
|
||||
row: any
|
||||
}>()
|
||||
|
||||
const attrs = computed(() => {
|
||||
return props.column.attrs ? props.column.attrs : {}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
<template>
|
||||
<div class="table-radio">
|
||||
<div class="header">
|
||||
<div class="title">{{ title }}</div>
|
||||
|
||||
<el-input
|
||||
v-model="filterText"
|
||||
:validate-event="false"
|
||||
:placeholder="$t('dynamicsForm.searchBar.placeholder')"
|
||||
class="input-with-select"
|
||||
style="--el-color-danger: #c0c4cc"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button :icon="Search" />
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
ref="singleTableRef"
|
||||
:data="tableData"
|
||||
highlight-current-row
|
||||
style="width: 100%; height: 100%; --el-bg-color: #f5f6f7"
|
||||
@current-change="_data = $event[valueField]"
|
||||
>
|
||||
<el-table-column width="50px">
|
||||
<template #default="scope">
|
||||
<input type="radio" :checked="_data === scope.row[valueField]" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(column, index) in tableColumns"
|
||||
v-bind="column"
|
||||
:label="column.label"
|
||||
:key="index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<template v-if="column.type === 'component'">
|
||||
<TableColumn :column="column" :row="scope.row"></TableColumn>
|
||||
</template>
|
||||
<template v-else-if="column.type === 'eval'">
|
||||
<span v-html="evalF(column.property, scope.row)"></span
|
||||
></template>
|
||||
<template v-else>
|
||||
<span>{{ scope.row[column.property] }}</span></template
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="msg" v-show="props.modelValue">
|
||||
{{ activeMsg }}
|
||||
<span class="active">
|
||||
{{ activeText }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import type { ElTable } from 'element-plus'
|
||||
|
||||
import _ from 'lodash'
|
||||
import TableColumn from '@/components/dynamics-form/items/table/TableColumn.vue'
|
||||
const filterText = ref<string>('')
|
||||
const props = defineProps<{
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
// 选中的值
|
||||
modelValue?: any
|
||||
}>()
|
||||
const rowTemp = ref<any>()
|
||||
const evalF = (text: string, row: any) => {
|
||||
rowTemp.value = row
|
||||
return eval(text)
|
||||
}
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const singleTableRef = ref<InstanceType<typeof ElTable>>()
|
||||
|
||||
const _data = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
emit('change', props.formField)
|
||||
}
|
||||
})
|
||||
|
||||
const propsInfo = computed(() => {
|
||||
return props.formField.props_info ? props.formField.props_info : {}
|
||||
})
|
||||
|
||||
const activeMsg = computed(() => {
|
||||
return propsInfo.value.active_msg ? propsInfo.value.active_msg : ''
|
||||
})
|
||||
const title = computed(() => {
|
||||
return propsInfo.value.title ? propsInfo.value.title : ''
|
||||
})
|
||||
const tableColumns = computed(() => {
|
||||
return propsInfo.value.table_columns ? propsInfo.value.table_columns : []
|
||||
})
|
||||
|
||||
const option_list = computed(() => {
|
||||
return props.formField.option_list ? props.formField.option_list : []
|
||||
})
|
||||
|
||||
const textField = computed(() => {
|
||||
return props.formField.text_field ? props.formField.text_field : 'key'
|
||||
})
|
||||
|
||||
const valueField = computed(() => {
|
||||
return props.formField.value_field ? props.formField.value_field : 'value'
|
||||
})
|
||||
|
||||
const tableData = computed(() => {
|
||||
if (option_list.value) {
|
||||
if (filterText.value) {
|
||||
return option_list.value.filter((item: any) =>
|
||||
tableColumns.value.some((c: any) => {
|
||||
let v = ''
|
||||
if (c.type === 'eval') {
|
||||
v = evalF(c.property, item)
|
||||
} else if (c.type === 'component') {
|
||||
return false
|
||||
} else {
|
||||
v = item[c.property]
|
||||
}
|
||||
return typeof v == 'string' ? v.indexOf(filterText.value) >= 0 : false
|
||||
})
|
||||
)
|
||||
} else {
|
||||
return option_list.value.filter((item: any) => item[valueField.value])
|
||||
}
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
/**
|
||||
* 监听表格数据,设置默认值
|
||||
*/
|
||||
watch(
|
||||
() => tableData.value,
|
||||
() => {
|
||||
if (tableData.value && tableData.value.length > 0) {
|
||||
const defaultItem = _.head(tableData.value)
|
||||
let defaultItemValue = _.get(defaultItem, valueField.value)
|
||||
if (props.modelValue) {
|
||||
const row = option_list.value.find((f: any) => f[valueField.value] === props.modelValue)
|
||||
if (row) {
|
||||
defaultItemValue = row[valueField.value]
|
||||
}
|
||||
}
|
||||
emit('update:modelValue', defaultItemValue)
|
||||
} else {
|
||||
emit('update:modelValue', undefined)
|
||||
}
|
||||
emit('change', props.formField)
|
||||
}
|
||||
)
|
||||
|
||||
const activeText = computed(() => {
|
||||
if (props.modelValue) {
|
||||
const row = option_list.value.find((f: any) => f[valueField.value] === props.modelValue)
|
||||
return row[textField.value]
|
||||
}
|
||||
return props.modelValue
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.table-radio {
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
.title {
|
||||
color: #1f2329;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.input-with-select {
|
||||
width: 45%;
|
||||
}
|
||||
}
|
||||
.msg {
|
||||
margin-top: 12px;
|
||||
color: rgba(100, 106, 115, 1);
|
||||
.active {
|
||||
margin-left: 3px;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
import type { Dict } from '@/api/type/common'
|
||||
|
||||
interface ViewCardItem {
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
type: 'eval' | 'default'
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
title: string
|
||||
/**
|
||||
* 值 根据类型不一样 取值也不一样 default= row[value_field] eval `${parseFloat(row.number).toLocaleString("zh-CN",{style: "decimal",maximumFractionDigits:1})}% `
|
||||
*/
|
||||
value_field: string
|
||||
}
|
||||
|
||||
interface TableColumn {
|
||||
/**
|
||||
* 字段|组件名称|可计算的模板字符串
|
||||
*/
|
||||
property: string
|
||||
/**
|
||||
*表头
|
||||
*/
|
||||
label: string
|
||||
/**
|
||||
* 表数据字段
|
||||
*/
|
||||
value_field?: string
|
||||
|
||||
attrs?: Attrs
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
type: 'eval' | 'component' | 'default'
|
||||
|
||||
props_info?: PropsInfo
|
||||
}
|
||||
interface ColorItem {
|
||||
/**
|
||||
* 颜色#f56c6c
|
||||
*/
|
||||
color: string
|
||||
/**
|
||||
* 进度
|
||||
*/
|
||||
percentage: number
|
||||
}
|
||||
interface Attrs {
|
||||
/**
|
||||
* 提示语
|
||||
*/
|
||||
placeholder?: string
|
||||
/**
|
||||
* 标签的长度,例如 '50px'。 作为 Form 直接子元素的 form-item 会继承该值。 可以使用 auto。
|
||||
*/
|
||||
labelWidth?: string
|
||||
/**
|
||||
* 表单域标签的后缀
|
||||
*/
|
||||
labelSuffix?: string
|
||||
/**
|
||||
* 星号的位置。
|
||||
*/
|
||||
requireAsteriskPosition?: 'left' | 'right'
|
||||
|
||||
color?: Array<ColorItem>
|
||||
|
||||
[propName: string]: any
|
||||
}
|
||||
interface PropsInfo {
|
||||
/**
|
||||
* 表格选择的card
|
||||
*/
|
||||
view_card?: Array<ViewCardItem>
|
||||
/**
|
||||
* 表格选择
|
||||
*/
|
||||
table_columns?: Array<TableColumn>
|
||||
/**
|
||||
* 选中 message
|
||||
*/
|
||||
active_msg?: string
|
||||
|
||||
/**
|
||||
* 组件样式
|
||||
*/
|
||||
style?: Dict<any>
|
||||
|
||||
/**
|
||||
* el-form-item 样式
|
||||
*/
|
||||
item_style?: Dict<any>
|
||||
/**
|
||||
* 表单校验 这个和element校验一样
|
||||
*/
|
||||
rules?: Dict<any>
|
||||
/**
|
||||
* 默认 不为空校验提示
|
||||
*/
|
||||
err_msg?: string
|
||||
/**
|
||||
*tabs的时候使用
|
||||
*/
|
||||
tabs_label?: string
|
||||
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
interface FormField {
|
||||
field: string
|
||||
/**
|
||||
* 输入框类型
|
||||
*/
|
||||
input_type: string
|
||||
/**
|
||||
* 提示
|
||||
*/
|
||||
label?: string | any
|
||||
/**
|
||||
* 是否 必填
|
||||
*/
|
||||
required?: boolean
|
||||
/**
|
||||
* 默认值
|
||||
*/
|
||||
default_value?: any
|
||||
/**
|
||||
* 是否显示默认值
|
||||
*/
|
||||
show_default_value?: boolean
|
||||
/**
|
||||
* {field:field_value_list} 表示在 field有值 ,并且值在field_value_list中才显示
|
||||
*/
|
||||
relation_show_field_dict?: Dict<Array<any>>
|
||||
/**
|
||||
* {field:field_value_list} 表示在 field有值 ,并且值在field_value_list中才 执行函数获取 数据
|
||||
*/
|
||||
relation_trigger_field_dict?: Dict<Array<any>>
|
||||
/**
|
||||
* 执行器类型 OPTION_LIST请求Option_list数据 CHILD_FORMS请求子表单
|
||||
*/
|
||||
trigger_type?: 'OPTION_LIST' | 'CHILD_FORMS'
|
||||
/**
|
||||
* 前端attr数据
|
||||
*/
|
||||
attrs?: Attrs
|
||||
/**
|
||||
* 其他额外信息
|
||||
*/
|
||||
props_info?: PropsInfo
|
||||
/**
|
||||
* 下拉选字段field
|
||||
*/
|
||||
text_field?: string
|
||||
/**
|
||||
* 下拉选 value
|
||||
*/
|
||||
value_field?: string
|
||||
/**
|
||||
* 下拉选数据
|
||||
*/
|
||||
option_list?: Array<any>
|
||||
/**
|
||||
* 供应商
|
||||
*/
|
||||
provider?: string
|
||||
/**
|
||||
* 执行函数
|
||||
*/
|
||||
method?: string
|
||||
|
||||
children?: Array<FormField>
|
||||
}
|
||||
export type { FormField }
|
||||
|
|
@ -2,10 +2,14 @@ import { type App } from 'vue'
|
|||
import LogoFull from './logo/LogoFull.vue'
|
||||
import LogoIcon from './logo/LogoIcon.vue'
|
||||
import SendIcon from './logo/SendIcon.vue'
|
||||
import dynamicsForm from './dynamics-form'
|
||||
import AppIcon from './app-icon/AppIcon.vue'
|
||||
export default {
|
||||
install(app: App) {
|
||||
app.component('LogoFull', LogoFull)
|
||||
app.component('LogoIcon', LogoIcon)
|
||||
app.component('SendIcon', SendIcon)
|
||||
app.use(dynamicsForm)
|
||||
app.component('AppIcon', AppIcon)
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,15 +129,15 @@
|
|||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<CreateApplicationDialog ref="CreateApplicationDialogRef" @refresh="refresh" />
|
||||
<CreateDatasetDialog ref="CreateDatasetDialogRef" @refresh="refresh" />
|
||||
<!-- <CreateApplicationDialog ref="CreateApplicationDialogRef" @refresh="refresh" />
|
||||
<CreateDatasetDialog ref="CreateDatasetDialogRef" @refresh="refresh" /> -->
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { onBeforeRouteLeave, useRouter, useRoute } from 'vue-router'
|
||||
import CreateApplicationDialog from '@/views/application/component/CreateApplicationDialog.vue'
|
||||
import CreateDatasetDialog from '@/views/dataset/component/CreateDatasetDialog.vue'
|
||||
// import CreateApplicationDialog from '@/views/application/component/CreateApplicationDialog.vue'
|
||||
// import CreateDatasetDialog from '@/views/dataset/component/CreateDatasetDialog.vue'
|
||||
import { isAppIcon, isWorkFlow } from '@/utils/application'
|
||||
import useStore from '@/stores'
|
||||
const { common, dataset, application } = useStore()
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
export { default as Sidebar } from './sidebar/index.vue'
|
||||
export { default as AppMain } from './app-main/index.vue'
|
||||
export { default as TopBar } from './top-bar/index.vue'
|
||||
export { default as AppHeader } from './app-header/index.vue'
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<div class="sidebar p-8">
|
||||
<div v-if="showBreadcrumb">
|
||||
<!-- <div v-if="showBreadcrumb">
|
||||
<AppBreadcrumb />
|
||||
</div>
|
||||
</div> -->
|
||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||
<el-menu :default-active="activeMenu" router>
|
||||
<sidebar-item
|
||||
|
|
@ -23,7 +23,7 @@ import { computed } from 'vue'
|
|||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { getChildRouteListByPathAndName } from '@/router/index'
|
||||
import SidebarItem from './SidebarItem.vue'
|
||||
import AppBreadcrumb from './../breadcrumb/index.vue'
|
||||
// import AppBreadcrumb from './../breadcrumb/index.vue'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
<div class="logo">
|
||||
<LogoFull />
|
||||
</div>
|
||||
<div class="flex-between">
|
||||
<div class="flex-between w-full">
|
||||
<div></div>
|
||||
<TopMenu></TopMenu>
|
||||
<TopUrlMenu></TopUrlMenu>
|
||||
<TopAbout></TopAbout>
|
||||
</div>
|
||||
<Avatar></Avatar>
|
||||
</div>
|
||||
|
|
@ -15,9 +15,15 @@
|
|||
<script setup lang="ts">
|
||||
import TopMenu from './top-menu/index.vue'
|
||||
import Avatar from './avatar/index.vue'
|
||||
import TopUrlMenu from './top-url-menu/index.vue'
|
||||
import TopAbout from './top-about/index.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
<style lang="scss" scoped>
|
||||
.app-top-bar-container {
|
||||
height: var(--app-header-height);
|
||||
box-sizing: border-box;
|
||||
padding: var(--app-header-padding);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -69,19 +69,19 @@
|
|||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<ResetPassword ref="resetPasswordRef"></ResetPassword>
|
||||
<AboutDialog ref="AboutDialogRef"></AboutDialog>
|
||||
<APIKeyDialog :user-id="user.userInfo?.id" ref="APIKeyDialogRef" />
|
||||
<UserPwdDialog ref="UserPwdDialogRef" />
|
||||
<!-- <ResetPassword ref="resetPasswordRef"></ResetPassword> -->
|
||||
<!-- <AboutDialog ref="AboutDialogRef"></AboutDialog>
|
||||
<APIKeyDialog :user-id="user.userInfo?.id" ref="APIKeyDialogRef" /> -->
|
||||
<!-- <UserPwdDialog ref="UserPwdDialogRef" /> -->
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import useStore from '@/stores'
|
||||
import { useRouter } from 'vue-router'
|
||||
import ResetPassword from './ResetPassword.vue'
|
||||
import AboutDialog from './AboutDialog.vue'
|
||||
import UserPwdDialog from '@/views/user-manage/component/UserPwdDialog.vue'
|
||||
import APIKeyDialog from './APIKeyDialog.vue'
|
||||
// import ResetPassword from './ResetPassword.vue'
|
||||
// import AboutDialog from './AboutDialog.vue'
|
||||
// import UserPwdDialog from '@/views/user-manage/component/UserPwdDialog.vue'
|
||||
// import APIKeyDialog from './APIKeyDialog.vue'
|
||||
import { ComplexPermission } from '@/utils/permission/type'
|
||||
import { langList } from '@/locales/index'
|
||||
import { useLocale } from '@/locales/useLocale'
|
||||
|
|
@ -118,7 +118,7 @@ const logout = () => {
|
|||
|
||||
onMounted(() => {
|
||||
if (user.userInfo?.is_edit_password) {
|
||||
UserPwdDialogRef.value.open(user.userInfo)
|
||||
// UserPwdDialogRef.value.open(user.userInfo)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('layout.github')"
|
||||
placement="top"
|
||||
v-if="user.themeInfo?.showProject"
|
||||
>
|
||||
<AppIcon
|
||||
iconName="app-github"
|
||||
class="cursor color-secondary mr-8 ml-8"
|
||||
style="font-size: 20px"
|
||||
@click="toUrl(user.themeInfo?.projectUrl)"
|
||||
></AppIcon>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('layout.wiki')"
|
||||
placement="top"
|
||||
v-if="user.themeInfo?.showUserManual"
|
||||
>
|
||||
<AppIcon
|
||||
iconName="app-user-manual"
|
||||
class="cursor color-secondary mr-8 ml-8"
|
||||
style="font-size: 20px"
|
||||
@click="toUrl(user.themeInfo?.userManualUrl)"
|
||||
></AppIcon>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('layout.forum')"
|
||||
placement="top"
|
||||
v-if="user.themeInfo?.showForum"
|
||||
>
|
||||
<AppIcon
|
||||
iconName="app-help"
|
||||
class="cursor color-secondary mr-16 ml-8"
|
||||
style="font-size: 20px"
|
||||
@click="toUrl(user.themeInfo?.forumUrl)"
|
||||
></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import useStore from '@/stores'
|
||||
const { user } = useStore()
|
||||
function toUrl(url: string) {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
<template>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('layout.github')"
|
||||
placement="top"
|
||||
v-if="user.themeInfo?.showProject"
|
||||
>
|
||||
<AppIcon
|
||||
iconName="app-github"
|
||||
class="cursor color-secondary mr-8 ml-8"
|
||||
style="font-size: 20px"
|
||||
@click="toUrl(user.themeInfo?.projectUrl)"
|
||||
></AppIcon>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('layout.wiki')"
|
||||
placement="top"
|
||||
v-if="user.themeInfo?.showUserManual"
|
||||
>
|
||||
<AppIcon
|
||||
iconName="app-reading"
|
||||
class="cursor color-secondary mr-8 ml-8"
|
||||
style="font-size: 20px"
|
||||
@click="toUrl(user.themeInfo?.userManualUrl)"
|
||||
></AppIcon>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('layout.forum')"
|
||||
placement="top"
|
||||
v-if="user.themeInfo?.showForum"
|
||||
>
|
||||
<AppIcon
|
||||
iconName="app-help"
|
||||
class="cursor color-secondary mr-16 ml-8"
|
||||
style="font-size: 20px"
|
||||
@click="toUrl(user.themeInfo?.forumUrl)"
|
||||
></AppIcon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import useStore from '@/stores'
|
||||
const { user } = useStore()
|
||||
function toUrl(url: string) {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import UserHeader from './layout-header/UserHeader.vue'
|
||||
import useStore from '@/stores'
|
||||
const { user } = useStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-layout">
|
||||
<div class="app-header">
|
||||
<UserHeader />
|
||||
</div>
|
||||
<div class="app-main">
|
||||
<AppMain />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
@import './index.scss';
|
||||
</style>
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="main-layout h-full flex">
|
||||
<div class="sidebar-container">
|
||||
<Sidebar />
|
||||
</div>
|
||||
<div class="view-container">
|
||||
<AppMain />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Sidebar, AppMain } from '../components'
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
|
||||
</style>
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
<template>
|
||||
<div class="app-layout">
|
||||
<AppHeader />
|
||||
<div class="app-header">
|
||||
<UserHeader />
|
||||
</div>
|
||||
|
||||
<div class="app-main">
|
||||
<div class="main-layout h-full flex">
|
||||
<div class="sidebar-container">
|
||||
|
|
@ -15,7 +18,9 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { AppHeader, Sidebar, AppMain } from '../components'
|
||||
import UserHeader from '@/layout/layout-header/UserHeader.vue'
|
||||
import Sidebar from '@/layout/components/sidebar/index.vue'
|
||||
import AppMain from '@/layout/app-main/index.vue'
|
||||
import useStore from '@/stores'
|
||||
const { user } = useStore()
|
||||
</script>
|
||||
|
|
@ -6,7 +6,7 @@ import system from './system'
|
|||
import functionLib from './function-lib'
|
||||
import user from './user'
|
||||
import team from './team'
|
||||
import template from './template'
|
||||
import model from './model'
|
||||
import document from './document'
|
||||
import paragraph from './paragraph'
|
||||
import problem from './problem'
|
||||
|
|
@ -22,7 +22,7 @@ export default {
|
|||
functionLib,
|
||||
user,
|
||||
team,
|
||||
template,
|
||||
model,
|
||||
dataset,
|
||||
applicationWorkflow,
|
||||
document,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export default {
|
|||
IMAGE: 'Vision Model',
|
||||
TTI: 'Image Generation'
|
||||
},
|
||||
templateForm: {
|
||||
modelForm: {
|
||||
title: {
|
||||
baseInfo: 'Basic Information',
|
||||
advancedInfo: 'Advanced Settings',
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
export default {
|
||||
input_type_list: {
|
||||
TextInput: '文本框',
|
||||
PasswordInput: '密码框',
|
||||
Slider: '滑块',
|
||||
SwitchInput: '开关',
|
||||
SingleSelect: '单选框',
|
||||
MultiSelect: '多选框',
|
||||
DatePicker: '日期',
|
||||
JsonInput: 'JSON文本框',
|
||||
RadioCard: '选项卡',
|
||||
RadioRow: '单行选项卡'
|
||||
},
|
||||
default: {
|
||||
label: '默认值',
|
||||
placeholder: '请输入默认值',
|
||||
requiredMessage: '为必填属性',
|
||||
show: '显示默认值'
|
||||
},
|
||||
tip: {
|
||||
requiredMessage: '不能为空',
|
||||
jsonMessage: 'JSON格式不正确'
|
||||
},
|
||||
searchBar: {
|
||||
placeholder: '请输入关键字搜索'
|
||||
},
|
||||
paramForm: {
|
||||
field: {
|
||||
label: '参数',
|
||||
placeholder: '请输入参数',
|
||||
requiredMessage: '参数 为必填属性',
|
||||
requiredMessage2: '只能输入字母数字和下划线'
|
||||
},
|
||||
name: {
|
||||
label: '显示名称',
|
||||
placeholder: '请输入显示名称',
|
||||
requiredMessage: '显示名称 为必填属性'
|
||||
},
|
||||
tooltip: {
|
||||
label: '参数提示说明',
|
||||
placeholder: '请输入参数提示说明'
|
||||
},
|
||||
required: {
|
||||
label: '是否必填',
|
||||
requiredMessage: '是否必填 为必填属性'
|
||||
},
|
||||
input_type: {
|
||||
label: '组件类型',
|
||||
placeholder: '请选择组件类型',
|
||||
requiredMessage: '组建类型 为必填属性'
|
||||
}
|
||||
},
|
||||
DatePicker: {
|
||||
placeholder: '选择日期',
|
||||
year: '年',
|
||||
month: '月',
|
||||
date: '日期',
|
||||
datetime: '日期时间',
|
||||
dataType: {
|
||||
label: '时间类型',
|
||||
placeholder: '请选择时间类型'
|
||||
},
|
||||
format: {
|
||||
label: '格式',
|
||||
placeholder: '请选择格式'
|
||||
}
|
||||
},
|
||||
Select: {
|
||||
label: '选项值',
|
||||
placeholder: '请输入选项值'
|
||||
},
|
||||
tag: {
|
||||
label: '标签',
|
||||
placeholder: '请输入选项标签'
|
||||
},
|
||||
Slider: {
|
||||
showInput: {
|
||||
label: '是否带输入框'
|
||||
},
|
||||
valueRange: {
|
||||
label: '取值范围',
|
||||
minRequired: '最小值必填',
|
||||
maxRequired: '最大值必填'
|
||||
},
|
||||
step: {
|
||||
label: '步长值',
|
||||
requiredMessage1: '步长值必填',
|
||||
requiredMessage2: '步长不能为0'
|
||||
}
|
||||
},
|
||||
TextInput: {
|
||||
length: {
|
||||
label: '文本长度',
|
||||
minRequired: '最小长度必填',
|
||||
maxRequired: '最大长度必填',
|
||||
requiredMessage1: '长度在',
|
||||
requiredMessage2: '到',
|
||||
requiredMessage3: '个字符',
|
||||
requiredMessage4: '文本长度为必填参数'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,15 @@ import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
|||
// import components from './components'
|
||||
import views from './views'
|
||||
import theme from './theme'
|
||||
import layout from './layout'
|
||||
import dynamicsForm from './dynamics-form'
|
||||
// import common from './common'
|
||||
// import dynamicsForm from './dynamics-form'
|
||||
// import chat from './ai-chat'
|
||||
export default {
|
||||
lang: '简体中文',
|
||||
zhCn,
|
||||
views,
|
||||
theme
|
||||
theme,
|
||||
layout,
|
||||
dynamicsForm,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
export default {
|
||||
github: '项目地址',
|
||||
wiki: '用户手册',
|
||||
forum: '论坛求助',
|
||||
logout: '退出',
|
||||
apiKey: 'API Key 管理',
|
||||
apiServiceAddress: 'API 服务地址',
|
||||
language: '语言',
|
||||
isExpire: '未上传 License 或 License 已过期。',
|
||||
about: {
|
||||
title: '关于',
|
||||
expiredTime: '到期时间',
|
||||
edition: {
|
||||
label: '版本',
|
||||
community: '社区版',
|
||||
professional: '专业版'
|
||||
},
|
||||
version: '版本号',
|
||||
serialNo: '序列号',
|
||||
remark: '备注',
|
||||
update: '更新',
|
||||
authorize: '授权给'
|
||||
},
|
||||
time: {
|
||||
daysLater: '天后',
|
||||
hoursLater: '小时后',
|
||||
expired: '已过期',
|
||||
expiringSoon: '即将到期'
|
||||
},
|
||||
copyright: '版权所有 © 2014-2025 杭州飞致云信息科技有限公司',
|
||||
userManualUrl: 'https://maxkb.cn/docs/',
|
||||
forumUrl: 'https://bbs.fit2cloud.com/c/mk/11'
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import login from './login'
|
||||
import model from './model'
|
||||
// import notFound from './404'
|
||||
// import application from './application'
|
||||
// import applicationOverview from './application-overview'
|
||||
|
|
@ -6,15 +8,17 @@
|
|||
// import functionLib from './function-lib'
|
||||
// import user from './user'
|
||||
// import team from './team'
|
||||
// import template from './template'
|
||||
|
||||
// import document from './document'
|
||||
// import paragraph from './paragraph'
|
||||
// import problem from './problem'
|
||||
// import log from './log'
|
||||
// import applicationWorkflow from './application-workflow'
|
||||
import login from './login'
|
||||
|
||||
// import operateLog from './operate-log'
|
||||
export default {
|
||||
login,
|
||||
model,
|
||||
// notFound,
|
||||
// application,
|
||||
// applicationOverview,
|
||||
|
|
@ -23,12 +27,11 @@ export default {
|
|||
// functionLib,
|
||||
// user,
|
||||
// team,
|
||||
// template,
|
||||
// document,
|
||||
// paragraph,
|
||||
// problem,
|
||||
// log,
|
||||
// applicationWorkflow,
|
||||
login,
|
||||
|
||||
// operateLog
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
export default {
|
||||
title: '模型',
|
||||
provider: '供应商',
|
||||
providerPlaceholder: '选择供应商',
|
||||
addModel: '添加模型',
|
||||
searchBar: {
|
||||
placeholder: '按名称搜索'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: '删除模型',
|
||||
confirmMessage: '是否删除模型:'
|
||||
},
|
||||
tip: {
|
||||
createSuccessMessage: '创建模型成功',
|
||||
createErrorMessage: '基础信息有填写错误',
|
||||
errorMessage: '变量已存在: ',
|
||||
emptyMessage1: '请先选择基础信息的模型类型和基础模型',
|
||||
emptyMessage2: '所选模型不支持参数设置',
|
||||
updateSuccessMessage: '修改模型成功',
|
||||
saveSuccessMessage: '模型参数保存成功',
|
||||
downloadError: '下载失败',
|
||||
noModel: '模型在Ollama不存在'
|
||||
},
|
||||
modelType: {
|
||||
allModel: '全部模型',
|
||||
publicModel: '公有模型',
|
||||
privateModel: '私有模型',
|
||||
LLM: '大语言模型',
|
||||
EMBEDDING: '向量模型',
|
||||
RERANKER: '重排模型',
|
||||
STT: '语音识别',
|
||||
TTS: '语音合成',
|
||||
IMAGE: '视觉模型',
|
||||
TTI: '图片生成'
|
||||
},
|
||||
modelForm: {
|
||||
title: {
|
||||
baseInfo: '基础信息',
|
||||
advancedInfo: '高级设置',
|
||||
modelParams: '模型参数',
|
||||
editParam: '编辑参数',
|
||||
addParam: '添加参数',
|
||||
paramSetting: '模型参数设置',
|
||||
apiParamPassing: '接口传参'
|
||||
},
|
||||
form: {
|
||||
templateName: {
|
||||
label: '模型名称',
|
||||
placeholder: '请给基础模型设置一个名称',
|
||||
tooltip: 'MaxKB 中自定义的模型名称',
|
||||
requiredMessage: '模型名称不能为空'
|
||||
},
|
||||
permissionType: {
|
||||
label: '权限',
|
||||
privateDesc: '仅当前用户使用',
|
||||
publicDesc: '所有用户都可使用',
|
||||
requiredMessage: '权限不能为空'
|
||||
},
|
||||
model_type: {
|
||||
label: '模型类型',
|
||||
placeholder: '请选择模型类型',
|
||||
tooltip1: '大语言模型:在应用中与AI对话的推理模型。',
|
||||
tooltip2: '向量模型:在知识库中对文档内容进行向量化的模型。',
|
||||
tooltip3: '语音识别:在应用中开启语音识别后用于语音转文字的模型。',
|
||||
tooltip4: '语音合成:在应用中开启语音播放后用于文字转语音的模型。',
|
||||
tooltip5: '重排模型:在高级编排应用中使用多路召回时,对候选分段进行重新排序的模型。',
|
||||
tooltip6: '视觉模型:在高级编排应用中用于图片理解的视觉模型。',
|
||||
tooltip7: '图片生成:在高级编排应用中用于图片生成的视觉模型。',
|
||||
requiredMessage: '模型类型不能为空'
|
||||
},
|
||||
base_model: {
|
||||
label: '基础模型',
|
||||
tooltip: '列表中未列出的模型,直接输入模型名称,回车即可添加',
|
||||
placeholder: '自定义输入基础模型后回车即可',
|
||||
requiredMessage: '基础模型不能为空'
|
||||
}
|
||||
}
|
||||
},
|
||||
download: {
|
||||
downloading: '正在下载中',
|
||||
cancelDownload: '取消下载'
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import system from './system'
|
|||
import functionLib from './function-lib'
|
||||
import user from './user'
|
||||
import team from './team'
|
||||
import template from './template'
|
||||
import model from './model'
|
||||
import document from './document'
|
||||
import paragraph from './paragraph'
|
||||
import problem from './problem'
|
||||
|
|
@ -22,7 +22,7 @@ export default {
|
|||
functionLib,
|
||||
user,
|
||||
team,
|
||||
template,
|
||||
model,
|
||||
dataset,
|
||||
applicationWorkflow,
|
||||
document,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
export default {
|
||||
title: '模型設定',
|
||||
title: '模型',
|
||||
provider: '供應商',
|
||||
providerPlaceholder: '選擇供應商',
|
||||
addModel: '新增模型',
|
||||
|
|
@ -33,7 +33,7 @@ export default {
|
|||
IMAGE: '圖片理解',
|
||||
TTI: '圖片生成'
|
||||
},
|
||||
templateForm: {
|
||||
modelForm: {
|
||||
title: {
|
||||
baseInfo: '基礎資訊',
|
||||
advancedInfo: '進階設定',
|
||||
|
|
@ -3,7 +3,7 @@ const ModelRouter = {
|
|||
name: 'model',
|
||||
meta: { title: 'views.model.title', permission: 'MODEL:READ' },
|
||||
redirect: '/model',
|
||||
component: () => import('@/layout/layout-template/AppLayout.vue'),
|
||||
component: () => import('@/layout/layout-template/MainLayout.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '/model',
|
||||
|
|
|
|||
|
|
@ -36,10 +36,9 @@ const useLoginStore = defineStore('user', {
|
|||
return !this.themeInfo?.theme || this.themeInfo?.theme === '#3370FF'
|
||||
},
|
||||
async profile(loading?: Ref<boolean>) {
|
||||
return UserApi.getUserProfile(loading).then((ok: { data: User }) => {
|
||||
this.userInfo = ok.data
|
||||
useLocalStorage<string>(localeConfigKey, 'en-US').value =
|
||||
ok.data?.language || this.getLanguage()
|
||||
return UserApi.getUserProfile(loading).then((ok) => {
|
||||
this.userInfo = ok
|
||||
useLocalStorage<string>(localeConfigKey, 'en-US').value = ok?.language || this.getLanguage()
|
||||
// return this.asyncGetProfile()
|
||||
})
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
export const defaultIcon = '/ui/favicon.ico'
|
||||
|
||||
// 是否显示字母 / icon
|
||||
export function isAppIcon(url: String | undefined) {
|
||||
return url === defaultIcon ? '' : url
|
||||
}
|
||||
|
||||
export function isWorkFlow(type: string | undefined) {
|
||||
return type === 'WORK_FLOW'
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import mitt from "mitt";
|
||||
const bus: any = {};
|
||||
const emitter = mitt();
|
||||
bus.on = emitter.on;
|
||||
bus.off = emitter.off;
|
||||
bus.emit = emitter.emit;
|
||||
|
||||
export default bus;
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import Clipboard from 'vue-clipboard3'
|
||||
import { MsgSuccess, MsgError } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
/*
|
||||
复制粘贴
|
||||
*/
|
||||
export async function copyClick(info: string) {
|
||||
const { toClipboard } = Clipboard()
|
||||
try {
|
||||
await toClipboard(info)
|
||||
MsgSuccess(t('common.copySuccess'))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
MsgError(t('common.copyError'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* 拆分数组 每n个拆分为一个数组
|
||||
* @param sourceDataList 资源数据
|
||||
* @param splitNum 每多少个拆分为一个数组
|
||||
* @returns 拆分后数组
|
||||
*/
|
||||
export function splitArray<T>(sourceDataList: Array<T>, splitNum: number) {
|
||||
const count =
|
||||
sourceDataList.length % splitNum == 0
|
||||
? sourceDataList.length / splitNum
|
||||
: sourceDataList.length / splitNum + 1
|
||||
const arrayList: Array<Array<T>> = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
let index = i * splitNum
|
||||
const list: Array<T> = []
|
||||
let j = 0
|
||||
while (j < splitNum && index < sourceDataList.length) {
|
||||
list.push(sourceDataList[index++])
|
||||
j++
|
||||
}
|
||||
arrayList.push(list)
|
||||
}
|
||||
return arrayList
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<el-drawer
|
||||
v-model="drawer"
|
||||
:direction="direction"
|
||||
size="600"
|
||||
:destroy-on-close="true"
|
||||
:before-close="cancelClick"
|
||||
>
|
||||
<template #header>
|
||||
<h4>
|
||||
{{
|
||||
isEdit
|
||||
? $t('views.model.modelForm.title.editParam')
|
||||
: $t('views.model.modelForm.title.addParam')
|
||||
}}
|
||||
</h4>
|
||||
</template>
|
||||
<template #default>
|
||||
<DynamicsFormConstructor
|
||||
v-model="currentItem"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
ref="DynamicsFormConstructorRef"
|
||||
></DynamicsFormConstructor>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div style="flex: auto">
|
||||
<el-button @click="cancelClick">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirmClick()">{{
|
||||
isEdit ? $t('common.save') : $t('common.add')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import type { DrawerProps } from 'element-plus'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import DynamicsFormConstructor from '@/components/dynamics-form/constructor/index.vue'
|
||||
|
||||
const drawer = ref(false)
|
||||
const direction = ref<DrawerProps['direction']>('rtl')
|
||||
const isEdit = ref(false)
|
||||
const DynamicsFormConstructorRef = ref<InstanceType<typeof DynamicsFormConstructor>>()
|
||||
|
||||
const currentItem = ref(null)
|
||||
const currentIndex = ref(null)
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const open = (row: any, index: any) => {
|
||||
if (row) {
|
||||
currentItem.value = cloneDeep(row)
|
||||
currentIndex.value = index
|
||||
isEdit.value = true
|
||||
}
|
||||
drawer.value = true
|
||||
}
|
||||
|
||||
function cancelClick() {
|
||||
drawer.value = false
|
||||
isEdit.value = false
|
||||
currentItem.value = null
|
||||
currentIndex.value = null
|
||||
}
|
||||
|
||||
function confirmClick() {
|
||||
const formEl = DynamicsFormConstructorRef.value
|
||||
formEl?.validate().then((valid) => {
|
||||
if (valid) {
|
||||
emit('refresh', formEl?.getData(), currentIndex.value)
|
||||
drawer.value = false
|
||||
isEdit.value = false
|
||||
currentItem.value = null
|
||||
currentIndex.value = null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,498 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
:before-close="close"
|
||||
append-to-body
|
||||
>
|
||||
<template #header="{ close, titleId, titleClass }">
|
||||
<el-breadcrumb separator=">">
|
||||
<el-breadcrumb-item>
|
||||
<span @click="toSelectProvider" class="select-provider">
|
||||
{{ $t('views.model.providerPlaceholder') }}
|
||||
</span>
|
||||
</el-breadcrumb-item>
|
||||
<el-breadcrumb-item
|
||||
><span class="active-breadcrumb">{{
|
||||
`${$t('common.add')} ${providerValue?.name}`
|
||||
}}</span></el-breadcrumb-item
|
||||
>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane :label="$t('views.model.modelForm.title.baseInfo')" name="base-info">
|
||||
<DynamicsForm
|
||||
v-model="form_data"
|
||||
:render_data="model_form_field"
|
||||
:model="form_data"
|
||||
ref="dynamicsFormRef"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
class="mb-24"
|
||||
label-width="auto"
|
||||
>
|
||||
<template #default>
|
||||
<el-form-item prop="name" :rules="base_form_data_rule.name">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="mr-4">
|
||||
<span> {{ $t('views.model.modelForm.form.templateName.label') }} </span>
|
||||
</div>
|
||||
<el-tooltip effect="dark" placement="right">
|
||||
<template #content>
|
||||
<p>{{ $t('views.model.modelForm.form.templateName.tooltip') }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input
|
||||
v-model="base_form_data.name"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
:placeholder="$t('views.model.modelForm.form.templateName.placeholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="permission_type" :rules="base_form_data_rule.permission_type">
|
||||
<template #label>
|
||||
<span>{{ $t('views.model.modelForm.form.permissionType.label') }}</span>
|
||||
</template>
|
||||
<el-radio-group v-model="base_form_data.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="base_form_data.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-item prop="model_type" :rules="base_form_data_rule.model_type">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<span class="mr-4"
|
||||
>{{ $t('views.model.modelForm.form.model_type.label') }}
|
||||
</span>
|
||||
<el-tooltip effect="dark" placement="right">
|
||||
<template #content>
|
||||
<p>{{ $t('views.model.modelForm.form.model_type.tooltip1') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.form.model_type.tooltip2') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.form.model_type.tooltip3') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.form.model_type.tooltip4') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.form.model_type.tooltip5') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.form.model_type.tooltip6') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.form.model_type.tooltip7') }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-select
|
||||
v-loading="model_type_loading"
|
||||
@change="list_base_model($event, true)"
|
||||
v-model="base_form_data.model_type"
|
||||
class="w-full m-2"
|
||||
:placeholder="$t('views.model.modelForm.form.model_type.placeholder')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in model_type_list"
|
||||
:key="item.value"
|
||||
:label="item.key"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="model_name" :rules="base_form_data_rule.model_name">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="mr-4">
|
||||
<span>{{ $t('views.model.modelForm.form.base_model.label') }} </span>
|
||||
<span class="danger ml-4">{{
|
||||
$t('views.model.modelForm.form.base_model.tooltip')
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-select
|
||||
@change="getModelForm($event)"
|
||||
v-loading="base_model_loading"
|
||||
v-model="base_form_data.model_name"
|
||||
class="w-full m-2"
|
||||
:placeholder="$t('views.model.modelForm.form.base_model.placeholder')"
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
>
|
||||
<el-option v-for="item in base_model_list" :key="item.name" :value="item.name">
|
||||
<template #default>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="flex-between mr-4">
|
||||
<span>{{ item.name }} </span>
|
||||
</div>
|
||||
<el-tooltip effect="dark" placement="right" v-if="item.desc">
|
||||
<template #content>
|
||||
<p class="w-280">{{ item.desc }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</DynamicsForm>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane
|
||||
:label="$t('views.model.modelForm.title.advancedInfo')"
|
||||
name="advanced-info"
|
||||
>
|
||||
<el-empty
|
||||
v-if="!base_form_data.model_type || !base_form_data.model_name"
|
||||
:description="$t('views.model.tip.emptyMessage1')"
|
||||
/>
|
||||
<el-empty
|
||||
v-else-if="
|
||||
base_form_data.model_type === 'RERANKER' ||
|
||||
base_form_data.model_type === 'EMBEDDING' ||
|
||||
base_form_data.model_type === 'STT'
|
||||
"
|
||||
:description="$t('views.model.tip.emptyMessage2')"
|
||||
/>
|
||||
<div class="flex-between mb-8" v-else>
|
||||
<h5>{{ $t('views.model.modelForm.title.modelParams') }}</h5>
|
||||
<el-button
|
||||
type="text"
|
||||
@click.stop="openAddDrawer()"
|
||||
:disabled="
|
||||
base_form_data.model_type !== 'TTS' &&
|
||||
base_form_data.model_type !== 'LLM' &&
|
||||
base_form_data.model_type !== 'IMAGE' &&
|
||||
base_form_data.model_type !== 'TTI'
|
||||
"
|
||||
>
|
||||
<AppIcon iconName="Plus" class="add-icon" />{{ $t('common.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
:data="base_form_data.model_params_form"
|
||||
v-if="base_form_data.model_params_form?.length > 0"
|
||||
class="mb-16"
|
||||
>
|
||||
<el-table-column
|
||||
prop="label"
|
||||
:label="$t('dynamicsForm.paramForm.name.label')"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.label && row.label.input_type === 'TooltipLabel'">{{
|
||||
row.label.label
|
||||
}}</span>
|
||||
<span v-else>{{ row.label }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="field"
|
||||
:label="$t('dynamicsForm.paramForm.field.label')"
|
||||
show-overflow-tooltip
|
||||
width="95px"
|
||||
/>
|
||||
<el-table-column :label="$t('dynamicsForm.paramForm.input_type.label')" width="110px">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="info" class="info-tag">{{
|
||||
input_type_list.find((item) => item.value === row.input_type)?.label
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="default_value"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<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="openAddDrawer(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="deleteParam($index)">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="close">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit" :loading="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<AddParamDrawer ref="AddParamRef" @refresh="refresh" />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import type { Provider, BaseModel } from '@/api/type/model'
|
||||
import type { Dict, KeyValue } from '@/api/type/common'
|
||||
import ModelApi from '@/api/model/model'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { MsgError, MsgSuccess, MsgWarning } from '@/utils/message'
|
||||
import { PermissionType, PermissionDesc } from '@/enums/model'
|
||||
import { input_type_list } from '@/components/dynamics-form/constructor/data'
|
||||
import AddParamDrawer from '@/views/template/component/AddParamDrawer.vue'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const providerValue = ref<Provider>()
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
const emit = defineEmits(['change', 'submit'])
|
||||
const loading = ref<boolean>(false)
|
||||
const model_type_loading = ref<boolean>(false)
|
||||
const base_model_loading = ref<boolean>(false)
|
||||
const model_type_list = ref<Array<KeyValue<string, string>>>([])
|
||||
|
||||
const base_model_list = ref<Array<BaseModel>>()
|
||||
const model_form_field = ref<Array<FormField>>([])
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const activeName = ref('base-info')
|
||||
const AddParamRef = ref()
|
||||
|
||||
const base_form_data_rule = ref<FormRules>({
|
||||
name: {
|
||||
required: true,
|
||||
trigger: 'blur',
|
||||
message: t('views.model.modelForm.form.templateName.requiredMessage')
|
||||
},
|
||||
permission_type: {
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
message: t('views.model.modelForm.form.permissionType.requiredMessage')
|
||||
},
|
||||
model_type: {
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
message: t('views.model.modelForm.form.model_type.requiredMessage')
|
||||
},
|
||||
model_name: {
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
message: t('views.model.modelForm.form.base_model.requiredMessage')
|
||||
}
|
||||
})
|
||||
|
||||
const base_form_data = ref<{
|
||||
name: string
|
||||
permission_type: string
|
||||
model_type: string
|
||||
model_name: string
|
||||
model_params_form: any
|
||||
}>({ name: '', model_type: '', model_name: '', permission_type: 'PRIVATE', model_params_form: [] })
|
||||
|
||||
const credential_form_data = ref<Dict<any>>({})
|
||||
|
||||
const form_data = computed({
|
||||
get: () => {
|
||||
return {
|
||||
...credential_form_data.value,
|
||||
name: base_form_data.value.name,
|
||||
model_type: base_form_data.value.model_type,
|
||||
model_name: base_form_data.value.model_name,
|
||||
permission_type: base_form_data.value.permission_type,
|
||||
model_params_form: base_form_data.value.model_params_form
|
||||
}
|
||||
},
|
||||
set: (event: any) => {
|
||||
credential_form_data.value = event
|
||||
}
|
||||
})
|
||||
|
||||
const getModelForm = (model_name: string) => {
|
||||
if (!form_data.value.model_type) {
|
||||
MsgWarning(t('views.model.modelForm.form.model_type.requiredMessage'))
|
||||
base_form_data.value.model_name = ''
|
||||
return
|
||||
}
|
||||
if (providerValue.value) {
|
||||
ModelApi.getModelCreateForm(
|
||||
providerValue.value.provider,
|
||||
form_data.value.model_type,
|
||||
model_name
|
||||
).then((ok) => {
|
||||
model_form_field.value = ok.data
|
||||
// 渲染动态表单
|
||||
dynamicsFormRef.value?.render(model_form_field.value, undefined)
|
||||
})
|
||||
|
||||
ModelApi.listBaseModelParamsForm(
|
||||
providerValue.value.provider,
|
||||
form_data.value.model_type,
|
||||
model_name,
|
||||
base_model_loading
|
||||
).then((ok) => {
|
||||
base_form_data.value.model_params_form = ok.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const open = (provider: Provider, model_type?: string) => {
|
||||
ModelApi.listModelType(provider.provider, model_type_loading).then((ok) => {
|
||||
model_type_list.value = ok.data
|
||||
})
|
||||
providerValue.value = provider
|
||||
dialogVisible.value = true
|
||||
base_form_data.value.model_type = model_type || ''
|
||||
activeName.value = 'base-info'
|
||||
if (model_type) {
|
||||
list_base_model(model_type)
|
||||
}
|
||||
}
|
||||
|
||||
const list_base_model = (model_type: any, change?: boolean) => {
|
||||
if (change) {
|
||||
base_form_data.value.model_name = ''
|
||||
base_form_data.value.model_params_form = []
|
||||
}
|
||||
if (providerValue.value) {
|
||||
ModelApi.listBaseModel(providerValue.value.provider, model_type, base_model_loading).then(
|
||||
(ok) => {
|
||||
base_model_list.value = ok.data
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
base_form_data.value = {
|
||||
name: '',
|
||||
model_type: '',
|
||||
model_name: '',
|
||||
permission_type: 'PRIVATE',
|
||||
model_params_form: []
|
||||
}
|
||||
credential_form_data.value = {}
|
||||
model_form_field.value = []
|
||||
base_model_list.value = []
|
||||
loading.value = false
|
||||
dialogVisible.value = false
|
||||
}
|
||||
const submit = () => {
|
||||
dynamicsFormRef.value
|
||||
?.validate()
|
||||
.then(() => {
|
||||
if (providerValue.value) {
|
||||
ModelApi.createModel(
|
||||
{
|
||||
...base_form_data.value,
|
||||
credential: credential_form_data.value,
|
||||
provider: providerValue.value.provider
|
||||
},
|
||||
loading
|
||||
).then((ok) => {
|
||||
close()
|
||||
MsgSuccess(t('views.model.tip.createSuccessMessage'))
|
||||
emit('submit')
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
MsgError(t('views.model.tip.createErrorMessage'))
|
||||
})
|
||||
}
|
||||
|
||||
function openAddDrawer(data?: any, index?: any) {
|
||||
AddParamRef.value?.open(data, index)
|
||||
}
|
||||
|
||||
function deleteParam(index: any) {
|
||||
base_form_data.value.model_params_form.splice(index, 1)
|
||||
}
|
||||
|
||||
function refresh(data: any, index: any) {
|
||||
for (let i = 0; i < base_form_data.value.model_params_form.length; i++) {
|
||||
let field = base_form_data.value.model_params_form[i].field
|
||||
let label = base_form_data.value.model_params_form[i].label
|
||||
if (label && label.input_type === 'TooltipLabel') {
|
||||
label = label.label
|
||||
}
|
||||
let label2 = data.label
|
||||
if (label2 && label2.input_type === 'TooltipLabel') {
|
||||
label2 = label2.label
|
||||
}
|
||||
|
||||
if (field === data.field && index !== i) {
|
||||
MsgError(t('views.model.tip.errorMessage') + data.field)
|
||||
return
|
||||
}
|
||||
if (label === label2 && index !== i) {
|
||||
MsgError(t('views.model.tip.errorMessage') + label)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (index !== null) {
|
||||
base_form_data.value.model_params_form.splice(index, 1, data)
|
||||
} else {
|
||||
base_form_data.value.model_params_form.push(data)
|
||||
}
|
||||
}
|
||||
|
||||
const toSelectProvider = () => {
|
||||
close()
|
||||
emit('change')
|
||||
}
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.select-provider {
|
||||
font-size: 16px;
|
||||
color: rgba(100, 106, 115, 1);
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.active-breadcrumb {
|
||||
font-size: 16px;
|
||||
color: rgba(31, 35, 41, 1);
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
<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) => {
|
||||
//1、判断文件大小是否合法,文件限制不能大于10MB
|
||||
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>
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
:before-close="close"
|
||||
>
|
||||
<template #header="{ close, titleId, titleClass }">
|
||||
<el-breadcrumb separator=">">
|
||||
<el-breadcrumb-item
|
||||
><span class="active-breadcrumb">{{
|
||||
`${$t('common.edit')} ${providerValue?.name}`
|
||||
}}</span></el-breadcrumb-item
|
||||
>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<DynamicsForm
|
||||
v-loading="formLoading"
|
||||
v-model="form_data"
|
||||
:render_data="model_form_field"
|
||||
:model="form_data"
|
||||
ref="dynamicsFormRef"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
>
|
||||
<template #default>
|
||||
<el-form-item prop="name" :rules="base_form_data_rule.name">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="mr-4">
|
||||
<span>{{ $t('views.model.modelForm.form.templateName.label') }} </span>
|
||||
</div>
|
||||
<el-tooltip effect="dark" placement="right">
|
||||
<template #content>
|
||||
<p>{{ $t('views.model.modelForm.form.templateName.tooltip') }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input
|
||||
v-model="base_form_data.name"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
:placeholder="$t('views.model.modelForm.form.templateName.placeholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="permission_type" :rules="base_form_data_rule.permission_type">
|
||||
<template #label>
|
||||
<span>{{ $t('views.model.modelForm.form.permissionType.label') }}</span>
|
||||
</template>
|
||||
|
||||
<el-radio-group v-model="base_form_data.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="base_form_data.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-item prop="model_type" :rules="base_form_data_rule.model_type">
|
||||
<template #label>
|
||||
<span>{{ $t('views.model.modelForm.form.model_type.label') }}</span>
|
||||
</template>
|
||||
<el-select
|
||||
disabled
|
||||
v-loading="model_type_loading"
|
||||
@change="list_base_model($event, true)"
|
||||
v-model="base_form_data.model_type"
|
||||
class="w-full m-2"
|
||||
:placeholder="$t('views.model.modelForm.form.model_type.placeholder')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in model_type_list"
|
||||
:key="item.value"
|
||||
:label="item.key"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="model_name" :rules="base_form_data_rule.model_name">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="mr-4">
|
||||
<span>{{ $t('views.model.modelForm.form.base_model.label') }} </span>
|
||||
<span class="danger ml-4">{{
|
||||
$t('views.model.modelForm.form.base_model.tooltip')
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-select
|
||||
@change="getModelForm($event)"
|
||||
v-loading="base_model_loading"
|
||||
v-model="base_form_data.model_name"
|
||||
class="w-full m-2"
|
||||
:placeholder="$t('views.model.modelForm.form.base_model.requiredMessage')"
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
>
|
||||
<el-option v-for="item in base_model_list" :key="item.name" :value="item.name">
|
||||
<template #default>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="flex-between mr-4">
|
||||
<span>{{ item.name }} </span>
|
||||
</div>
|
||||
<el-tooltip effect="dark" placement="right" v-if="item.desc">
|
||||
<template #content>
|
||||
<p>{{ item.desc }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</DynamicsForm>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="close">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit" :loading="loading">
|
||||
{{ $t('common.modify') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import type { Provider, BaseModel, Model } from '@/api/type/model'
|
||||
import type { Dict, KeyValue } from '@/api/type/common'
|
||||
import ModelApi from '@/api/model/model'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import { PermissionType, PermissionDesc } from '@/enums/model'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const providerValue = ref<Provider>()
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
const emit = defineEmits(['change', 'submit'])
|
||||
const loading = ref<boolean>(false)
|
||||
const formLoading = ref<boolean>(false)
|
||||
const model_type_loading = ref<boolean>(false)
|
||||
const base_model_loading = ref<boolean>(false)
|
||||
const model_type_list = ref<Array<KeyValue<string, string>>>([])
|
||||
const modelValue = ref<Model>()
|
||||
const base_model_list = ref<Array<BaseModel>>([])
|
||||
const model_form_field = ref<Array<FormField>>([])
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
const base_form_data_rule = ref<FormRules>({
|
||||
name: {
|
||||
required: true,
|
||||
trigger: 'blur',
|
||||
message: t('views.model.modelForm.form.templateName.requiredMessage')
|
||||
},
|
||||
model_type: {
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
message: t('views.model.modelForm.form.model_type.requiredMessage')
|
||||
},
|
||||
model_name: {
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
message: t('views.model.modelForm.form.base_model.requiredMessage')
|
||||
}
|
||||
})
|
||||
|
||||
const base_form_data = ref<{
|
||||
name: string
|
||||
permission_type: string
|
||||
model_type: string
|
||||
|
||||
model_name: string
|
||||
}>({ name: '', model_type: '', model_name: '', permission_type: 'PRIVATE' })
|
||||
|
||||
const credential_form_data = ref<Dict<any>>({})
|
||||
|
||||
const form_data = computed({
|
||||
get: () => {
|
||||
return { ...credential_form_data.value, ...base_form_data.value }
|
||||
},
|
||||
set: (event: any) => {
|
||||
credential_form_data.value = event
|
||||
}
|
||||
})
|
||||
|
||||
const getModelForm = (model_name: string) => {
|
||||
if (providerValue.value) {
|
||||
ModelApi.getModelCreateForm(
|
||||
providerValue.value.provider,
|
||||
form_data.value.model_type,
|
||||
model_name
|
||||
).then((ok) => {
|
||||
model_form_field.value = ok.data
|
||||
if (modelValue.value) {
|
||||
// 渲染动态表单
|
||||
dynamicsFormRef.value?.render(model_form_field.value, modelValue.value.credential)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
const list_base_model = (model_type: any, change?: boolean) => {
|
||||
if (change) {
|
||||
base_form_data.value.model_name = ''
|
||||
}
|
||||
if (providerValue.value) {
|
||||
ModelApi.listBaseModel(providerValue.value.provider, model_type, base_model_loading).then(
|
||||
(ok) => {
|
||||
base_model_list.value = ok.data
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
const open = (provider: Provider, model: Model) => {
|
||||
modelValue.value = model
|
||||
ModelApi.getModelById(model.id, formLoading).then((ok) => {
|
||||
modelValue.value = ok.data
|
||||
ModelApi.listModelType(model.provider, model_type_loading).then((ok) => {
|
||||
model_type_list.value = ok.data
|
||||
list_base_model(model.model_type)
|
||||
})
|
||||
providerValue.value = provider
|
||||
|
||||
base_form_data.value = {
|
||||
name: model.name,
|
||||
permission_type: model.permission_type,
|
||||
model_type: model.model_type,
|
||||
model_name: model.model_name
|
||||
}
|
||||
form_data.value = model.credential
|
||||
getModelForm(model.model_name)
|
||||
})
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
base_form_data.value = { name: '', model_type: '', model_name: '', permission_type: '' }
|
||||
dynamicsFormRef.value?.ruleFormRef?.resetFields()
|
||||
credential_form_data.value = {}
|
||||
model_form_field.value = []
|
||||
base_model_list.value = []
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const submit = () => {
|
||||
dynamicsFormRef.value?.validate().then(() => {
|
||||
if (modelValue.value) {
|
||||
ModelApi.updateModel(
|
||||
modelValue.value.id,
|
||||
{
|
||||
...base_form_data.value,
|
||||
credential: credential_form_data.value
|
||||
},
|
||||
loading
|
||||
).then((ok) => {
|
||||
MsgSuccess(t('views.model.tip.updateSuccessMessage'))
|
||||
close()
|
||||
emit('submit')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.select-provider {
|
||||
font-size: 16px;
|
||||
color: rgba(100, 106, 115, 1);
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.active-breadcrumb {
|
||||
font-size: 16px;
|
||||
color: rgba(31, 35, 41, 1);
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -1,518 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
<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 functionLibApi from '@/api/function-lib'
|
||||
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(() => {
|
||||
functionLibApi.putFunctionLib(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>
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
<template>
|
||||
<card-box :title="model.name" shadow="hover" class="model-card">
|
||||
<template #header>
|
||||
<div class="flex">
|
||||
<span style="height: 32px; width: 32px" :innerHTML="icon" class="mr-12"></span>
|
||||
<div style="width: calc(100% - 32px - 4px - var(--app-base-px))">
|
||||
<div class="flex" style="height: 22px">
|
||||
<auto-tooltip :content="model.name" style="max-width: 40%">
|
||||
{{ model.name }}
|
||||
</auto-tooltip>
|
||||
<span v-if="currentModel.status === 'ERROR'">
|
||||
<el-tooltip effect="dark" :content="errMessage" placement="top">
|
||||
<el-icon class="danger ml-4" size="18"><Warning /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<span v-if="currentModel.status === 'PAUSE_DOWNLOAD'">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="`${$t('views.model.modelForm.form.base_model.label')}: ${props.model.model_name} ${$t('views.model.tip.downloadError')}`"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon class="danger ml-4" size="18"><Warning /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<el-tag v-if="model.permission_type === 'PRIVATE'" type="danger" class="danger-tag">{{
|
||||
$t('common.private')
|
||||
}}</el-tag>
|
||||
<el-tag v-else type="info" class="info-tag"> {{ $t('common.public') }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="mt-16">
|
||||
<ul>
|
||||
<li class="flex mt-16">
|
||||
<el-text type="info">{{
|
||||
$t('views.model.modelForm.form.model_type.label')
|
||||
}}</el-text>
|
||||
<span class="ellipsis ml-16">
|
||||
{{ $t(modelType[model.model_type as keyof typeof modelType]) }}</span
|
||||
>
|
||||
</li>
|
||||
<li class="flex mt-12">
|
||||
<el-text type="info">{{
|
||||
$t('views.model.modelForm.form.base_model.label')
|
||||
}}</el-text>
|
||||
<span class="ellipsis-1 ml-16" style="height: 20px; width: 70%">
|
||||
{{ model.model_name }}</span
|
||||
>
|
||||
</li>
|
||||
<li class="flex mt-12">
|
||||
<el-text type="info">{{ $t('common.creator') }}</el-text>
|
||||
<span class="ellipsis-1 ml-16" style="height: 20px; width: 70%">
|
||||
{{ model.username }}</span
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- progress -->
|
||||
<div class="progress-mask" v-if="currentModel.status === 'DOWNLOAD'">
|
||||
<DownloadLoading class="percentage" />
|
||||
|
||||
<div class="percentage-label flex-center">
|
||||
{{ $t('views.model.download.downloading') }} <span class="dotting"></span>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
class="ml-16"
|
||||
:disabled="!is_permisstion"
|
||||
@click.stop="cancelDownload"
|
||||
>{{ $t('views.model.download.cancelDownload') }}</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #mouseEnter>
|
||||
<div class="operation-button">
|
||||
<el-tooltip effect="dark" :content="$t('common.modify')" placement="top">
|
||||
<el-button text :disabled="!is_permisstion" @click.stop="openEditModel">
|
||||
<el-icon>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<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="
|
||||
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
|
||||
icon="Delete"
|
||||
:disabled="!is_permisstion"
|
||||
text
|
||||
@click.stop="deleteModel"
|
||||
>
|
||||
{{ $t('common.delete') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
<EditModel ref="editModelRef" @submit="emit('change')"></EditModel>
|
||||
<ParamSettingDialog ref="paramSettingRef" :model="model" />
|
||||
</card-box>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { Provider, Model } from '@/api/type/model'
|
||||
import ModelApi from '@/api/model/model'
|
||||
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import EditModel from '@/views/template/component/EditModel.vue'
|
||||
import DownloadLoading from '@/components/loading/DownloadLoading.vue'
|
||||
import { MsgConfirm } from '@/utils/message'
|
||||
import { modelType } from '@/enums/model'
|
||||
import useStore from '@/stores'
|
||||
import ParamSettingDialog from './ParamSettingDialog.vue'
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps<{
|
||||
model: Model
|
||||
provider_list: Array<Provider>
|
||||
updateModelById: (model_id: string, model: Model) => void
|
||||
}>()
|
||||
|
||||
const { user } = useStore()
|
||||
const downModel = ref<Model>()
|
||||
|
||||
const is_permisstion = computed(() => {
|
||||
return user.userInfo?.id == props.model.user_id
|
||||
})
|
||||
const currentModel = computed(() => {
|
||||
if (downModel.value) {
|
||||
return downModel.value
|
||||
} else {
|
||||
return props.model
|
||||
}
|
||||
})
|
||||
|
||||
const errMessage = computed(() => {
|
||||
if (currentModel.value.meta && currentModel.value.meta.message) {
|
||||
if (currentModel.value.meta.message === 'pull model manifest: file does not exist') {
|
||||
return `${currentModel.value.model_name} ${t('views.model.tip.noModel')}`
|
||||
}
|
||||
return currentModel.value.meta.message
|
||||
}
|
||||
return ''
|
||||
})
|
||||
const emit = defineEmits(['change', 'update:model'])
|
||||
const editModelRef = ref<InstanceType<typeof EditModel>>()
|
||||
let interval: any
|
||||
const deleteModel = () => {
|
||||
MsgConfirm(
|
||||
t('views.model.delete.confirmTitle'),
|
||||
`${t('views.model.delete.confirmMessage')}${props.model.name} ?`,
|
||||
{
|
||||
confirmButtonText: t('common.confirm'),
|
||||
confirmButtonClass: 'danger'
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
ModelApi.deleteModel(props.model.id).then(() => {
|
||||
emit('change')
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const cancelDownload = () => {
|
||||
ModelApi.pauseDownload(props.model.id).then(() => {
|
||||
downModel.value = undefined
|
||||
emit('change')
|
||||
})
|
||||
}
|
||||
const openEditModel = () => {
|
||||
const provider = props.provider_list.find((p) => p.provider === props.model.provider)
|
||||
if (provider) {
|
||||
editModelRef.value?.open(provider, props.model)
|
||||
}
|
||||
}
|
||||
const icon = computed(() => {
|
||||
return props.provider_list.find((p) => p.provider === props.model.provider)?.icon
|
||||
})
|
||||
|
||||
/**
|
||||
* 初始化轮询
|
||||
*/
|
||||
const initInterval = () => {
|
||||
interval = setInterval(() => {
|
||||
if (currentModel.value.status === 'DOWNLOAD') {
|
||||
ModelApi.getModelMetaById(props.model.id).then((ok) => {
|
||||
downModel.value = ok.data
|
||||
})
|
||||
} else {
|
||||
if (downModel.value) {
|
||||
props.updateModelById(props.model.id, downModel.value)
|
||||
downModel.value = undefined
|
||||
}
|
||||
}
|
||||
}, 6000)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭轮询
|
||||
*/
|
||||
const closeInterval = () => {
|
||||
if (interval) {
|
||||
clearInterval(interval)
|
||||
}
|
||||
}
|
||||
|
||||
const paramSettingRef = ref<InstanceType<typeof ParamSettingDialog>>()
|
||||
const openParamSetting = () => {
|
||||
paramSettingRef.value?.open()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initInterval()
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
// 清除定时任务
|
||||
closeInterval()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.model-card {
|
||||
min-height: 135px;
|
||||
min-width: auto;
|
||||
.operation-button {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 18px;
|
||||
height: auto;
|
||||
.el-button + .el-button {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
.progress-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 99;
|
||||
text-align: center;
|
||||
.percentage {
|
||||
margin-top: 55px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
// .percentage-value {
|
||||
// display: flex;
|
||||
// font-size: 13px;
|
||||
// align-items: center;
|
||||
// color: var(--app-text-color-secondary);
|
||||
// }
|
||||
.percentage-label {
|
||||
margin-top: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 13px;
|
||||
color: var(--app-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
:title="$t('views.model.modelForm.title.paramSetting')"
|
||||
v-model="dialogVisible"
|
||||
width="800px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
:before-close="close"
|
||||
>
|
||||
<el-button type="primary" @click="openAddDrawer()" class="mb-12">
|
||||
{{ $t('views.model.modelForm.title.addParam') }}
|
||||
</el-button>
|
||||
<el-table :data="modelParamsForm" class="mb-16">
|
||||
<el-table-column prop="label" :label="$t('dynamicsForm.paramForm.name.label')" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.label && row.label.input_type === 'TooltipLabel'">{{
|
||||
row.label.label
|
||||
}}</span>
|
||||
<span v-else>{{ row.label }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="field" :label="$t('dynamicsForm.paramForm.field.label')" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('dynamicsForm.paramForm.input_type.label')" width="110px">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="info" class="info-tag">{{
|
||||
input_type_list.find((item) => item.value === row.input_type)?.label
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="default_value"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<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="openAddDrawer(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="deleteParam($index)">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="close">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit" :loading="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<AddParamDrawer ref="AddParamRef" @refresh="refresh" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Model } from '@/api/type/model'
|
||||
import { ref } from 'vue'
|
||||
import AddParamDrawer from './AddParamDrawer.vue'
|
||||
import { MsgError, MsgSuccess } from '@/utils/message'
|
||||
import ModelApi from '@/api/model/model'
|
||||
import { input_type_list } from '@/components/dynamics-form/constructor/data'
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps<{
|
||||
model: Model
|
||||
}>()
|
||||
|
||||
const loading = ref<boolean>(false)
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const modelParamsForm = ref<any[]>([])
|
||||
const AddParamRef = ref()
|
||||
|
||||
const open = () => {
|
||||
dialogVisible.value = true
|
||||
loading.value = true
|
||||
ModelApi.getModelParamsForm(props.model.id, loading)
|
||||
.then((ok) => {
|
||||
loading.value = false
|
||||
modelParamsForm.value = ok.data
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
function openAddDrawer(data?: any, index?: any) {
|
||||
AddParamRef.value?.open(data, index)
|
||||
}
|
||||
|
||||
function deleteParam(index: any) {
|
||||
modelParamsForm.value.splice(index, 1)
|
||||
}
|
||||
|
||||
function refresh(data: any, index: any) {
|
||||
for (let i = 0; i < modelParamsForm.value.length; i++) {
|
||||
let field = modelParamsForm.value[i].field
|
||||
let label = modelParamsForm.value[i].label
|
||||
if (label && label.input_type === 'TooltipLabel') {
|
||||
label = label.label
|
||||
}
|
||||
let label2 = data.label
|
||||
if (label2 && label2.input_type === 'TooltipLabel') {
|
||||
label2 = label2.label
|
||||
}
|
||||
|
||||
if (field === data.field && index !== i) {
|
||||
MsgError(t('views.model.tip.errorMessage') + data.field)
|
||||
return
|
||||
}
|
||||
if (label === label2 && index !== i) {
|
||||
MsgError(t('views.model.tip.errorMessage') + label)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (index !== null) {
|
||||
modelParamsForm.value.splice(index, 1, data)
|
||||
} else {
|
||||
modelParamsForm.value.push(data)
|
||||
}
|
||||
}
|
||||
|
||||
function submit() {
|
||||
ModelApi.updateModelParamsForm(props.model.id, modelParamsForm.value, loading).then((ok) => {
|
||||
MsgSuccess(t('views.model.tip.saveSuccessMessage'))
|
||||
close()
|
||||
// emit('submit')
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
:before-close="close"
|
||||
append-to-body
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex-between">
|
||||
<h4>{{ $t('views.model.providerPlaceholder') }}</h4>
|
||||
<el-dropdown>
|
||||
<span class="cursor">
|
||||
{{ currentModelType || $t('views..model.modelType.allModel') }}
|
||||
<el-icon class="el-icon--right">
|
||||
<arrow-down />
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="item in modelTypeOptions"
|
||||
:key="item.value"
|
||||
@click="checkModelType(item.value)"
|
||||
>
|
||||
<span>{{ item.text }}</span>
|
||||
<el-icon v-if="currentModelType === item.text"><Check /></el-icon>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
<el-row :gutter="12" v-loading="loading">
|
||||
<el-col :span="12" class="mb-16" v-for="(data, index) in list_provider" :key="index">
|
||||
<el-card shadow="hover" @click="go_create(data)">
|
||||
<div class="flex align-center cursor">
|
||||
<span :innerHTML="data.icon" alt="" style="height: 24px; width: 24px" class="mr-8" />
|
||||
<span>{{ data.name }}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import ModelApi from '@/api/model/model'
|
||||
import type { Provider } from '@/api/type/model'
|
||||
import { modelTypeList } from './data'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const loading = ref<boolean>(false)
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const list_provider = ref<Array<Provider>>([])
|
||||
const currentModelType = ref('')
|
||||
const selectModelType = ref('')
|
||||
const modelTypeOptions = [{ text: t('views.model.modelType.allModel'), value: '' }, ...modelTypeList]
|
||||
|
||||
const open = (model_type?: string) => {
|
||||
dialogVisible.value = true
|
||||
const option = modelTypeOptions.find((item) => item.text === currentModelType.value)
|
||||
checkModelType(model_type ? model_type : option ? option.value : '')
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const checkModelType = (model_type: string) => {
|
||||
selectModelType.value = model_type
|
||||
currentModelType.value = modelTypeOptions.filter((item) => item.value === model_type)[0].text
|
||||
ModelApi.getProviderByModelType(model_type, loading).then((ok) => {
|
||||
list_provider.value = ok.data
|
||||
list_provider.value.sort((a, b) => a.provider.localeCompare(b.provider))
|
||||
})
|
||||
}
|
||||
|
||||
const emit = defineEmits(['change'])
|
||||
const go_create = (provider: Provider) => {
|
||||
close()
|
||||
emit('change', provider, selectModelType.value)
|
||||
}
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { modelType } from '@/enums/model'
|
||||
import { t } from '@/locales'
|
||||
export const modelTypeList = [
|
||||
{ text: t(modelType['LLM']), value: 'LLM' },
|
||||
{ text: t(modelType['EMBEDDING']), value: 'EMBEDDING' },
|
||||
{ text: t(modelType['RERANKER']), value: 'RERANKER' },
|
||||
{ text: t(modelType['STT']), value: 'STT' },
|
||||
{ text: t(modelType['TTS']), value: 'TTS' },
|
||||
{ text: t(modelType['IMAGE']), value: 'IMAGE' },
|
||||
{ text: t(modelType['TTI']), value: 'TTI' }
|
||||
]
|
||||
|
|
@ -1,623 +1,255 @@
|
|||
<template>
|
||||
<div class="function-lib-list-container p-24" style="padding-top: 16px">
|
||||
<el-tabs v-model="functionType" @tab-change="tabChangeHandle">
|
||||
<el-tab-pane :label="$t('views.functionLib.title')" name="PUBLIC"></el-tab-pane>
|
||||
<el-tab-pane :label="$t('views.functionLib.internalTitle')" name="INTERNAL"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="flex-between mb-16">
|
||||
<h4></h4>
|
||||
<div class="flex-between">
|
||||
<el-select
|
||||
v-if="functionType === 'PUBLIC'"
|
||||
v-model="selectUserId"
|
||||
class="mr-12"
|
||||
style="max-width: 240px; width: 150px"
|
||||
@change="searchHandle"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input
|
||||
v-model="searchValue"
|
||||
@change="searchHandle"
|
||||
:placeholder="$t('views.functionLib.searchBar.placeholder')"
|
||||
prefix-icon="Search"
|
||||
class="w-240"
|
||||
style="max-width: 240px"
|
||||
clearable
|
||||
/>
|
||||
1111111111
|
||||
<!-- <LayoutContainer :header="$t('views.model.title')">
|
||||
<div class="model-manage flex main-calc-height">
|
||||
<div class="model-manage__left p-8 border-r">
|
||||
<h4 class="p-16">{{ $t('views.model.provider') }}</h4>
|
||||
<div class="model-list-height-left">
|
||||
<div
|
||||
class="all-mode flex cursor"
|
||||
@click="clickListHandle(allObj as Provider)"
|
||||
:class="!active_provider?.provider ? 'all-mode-active' : ''"
|
||||
>
|
||||
<AppIcon
|
||||
class="mr-8"
|
||||
style="height: 20px; width: 20px"
|
||||
:iconName="'app-all-menu-active'"
|
||||
></AppIcon>
|
||||
<span>{{ $t('views.model.modelType.allModel') }}</span>
|
||||
</div>
|
||||
|
||||
<el-scrollbar>
|
||||
<el-collapse class="model-collapse">
|
||||
<el-collapse-item :title="$t('views.model.modelType.publicModel')" name="1">
|
||||
<template #title>
|
||||
<img src="@/assets/icon_file-folder_colorful.svg" class="mr-8" />
|
||||
{{ $t('views.model.modelType.publicModel') }}
|
||||
</template>
|
||||
<common-list
|
||||
:data="online_provider_list"
|
||||
v-loading="loading"
|
||||
@click="clickListHandle"
|
||||
value-key="provider"
|
||||
default-active=""
|
||||
ref="commonList1"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div class="flex align-center">
|
||||
<span
|
||||
:innerHTML="row.icon"
|
||||
alt=""
|
||||
style="height: 20px; width: 20px"
|
||||
class="mr-8"
|
||||
/>
|
||||
<span>{{ row.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</common-list>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="$t('views.model.modelType.privateModel')" name="2">
|
||||
<template #title>
|
||||
<img src="@/assets/icon_file-folder_colorful.svg" class="mr-8" />
|
||||
{{ $t('views.model.modelType.privateModel') }}
|
||||
</template>
|
||||
<common-list
|
||||
:data="local_provider_list"
|
||||
v-loading="loading"
|
||||
@click="clickListHandle"
|
||||
value-key="provider"
|
||||
default-active=""
|
||||
ref="commonList2"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div class="flex align-center">
|
||||
<span
|
||||
:innerHTML="row.icon"
|
||||
alt=""
|
||||
style="height: 20px; width: 20px"
|
||||
class="mr-8"
|
||||
/>
|
||||
<span>{{ row.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</common-list>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="model-manage__right w-full" v-loading="list_model_loading">
|
||||
<div class="p-24 pb-0">
|
||||
<h4>{{ active_provider?.name }}</h4>
|
||||
<div class="flex-between mt-16 mb-16">
|
||||
<el-button type="primary" @click="openCreateModel(active_provider)">
|
||||
{{ $t('views.model.addModel') }}</el-button
|
||||
>
|
||||
<div class="flex-between complex-search">
|
||||
<el-select
|
||||
class="complex-search__left"
|
||||
v-model="search_type"
|
||||
style="width: 120px"
|
||||
@change="search_type_change"
|
||||
>
|
||||
<el-option :label="$t('common.creator')" value="create_user" />
|
||||
<el-option
|
||||
:label="$t('views.model.modelForm.form.permissionType.label')"
|
||||
value="permission_type"
|
||||
/>
|
||||
<el-option
|
||||
:label="$t('views.model.modelForm.form.model_type.label')"
|
||||
value="model_type"
|
||||
/>
|
||||
<el-option
|
||||
:label="$t('views.model.modelForm.form.templateName.label')"
|
||||
value="name"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input
|
||||
v-if="search_type === 'name'"
|
||||
v-model="model_search_form.name"
|
||||
@change="list_model"
|
||||
:placeholder="$t('views.model.searchBar.placeholder')"
|
||||
prefix-icon="Search"
|
||||
style="width: 220px"
|
||||
clearable
|
||||
/>
|
||||
<el-select
|
||||
v-else-if="search_type === 'create_user'"
|
||||
v-model="model_search_form.create_user"
|
||||
@change="list_model"
|
||||
clearable
|
||||
style="width: 220px"
|
||||
>
|
||||
<el-option
|
||||
v-for="u in user_options"
|
||||
:key="u.id"
|
||||
:value="u.id"
|
||||
:label="u.username"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select
|
||||
v-else-if="search_type === 'permission_type'"
|
||||
v-model="model_search_form.permission_type"
|
||||
clearable
|
||||
@change="list_model"
|
||||
style="width: 220px"
|
||||
>
|
||||
<el-option :label="$t('common.public')" value="PUBLIC" />
|
||||
<el-option :label="$t('common.private')" value="PRIVATE" />
|
||||
</el-select>
|
||||
<el-select
|
||||
v-else-if="search_type === 'model_type'"
|
||||
v-model="model_search_form.model_type"
|
||||
clearable
|
||||
@change="list_model"
|
||||
style="width: 220px"
|
||||
>
|
||||
<template v-for="item in modelTypeList" :key="item.value">
|
||||
<el-option :label="item.text" :value="item.value" />
|
||||
</template>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="model-list-height">
|
||||
<el-scrollbar>
|
||||
<div class="p-24 pt-0">
|
||||
<el-row v-if="model_split_list.length > 0" :gutter="15">
|
||||
<template v-for="(row, index) in model_split_list" :key="index">
|
||||
<el-col
|
||||
:xs="24"
|
||||
:sm="24"
|
||||
:md="24"
|
||||
:lg="12"
|
||||
:xl="12"
|
||||
class="mb-16"
|
||||
v-for="(model, i) in row"
|
||||
:key="i"
|
||||
>
|
||||
<ModelCard
|
||||
@change="list_model"
|
||||
:updateModelById="updateModelById"
|
||||
:model="model"
|
||||
:provider_list="provider_list"
|
||||
>
|
||||
</ModelCard>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
<el-empty :description="$t('common.noData')" v-else />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-loading.fullscreen.lock="
|
||||
(paginationConfig.current_page === 1 && loading) || changeStateloading
|
||||
"
|
||||
>
|
||||
<InfiniteScroll
|
||||
:size="functionLibList.length"
|
||||
:total="paginationConfig.total"
|
||||
:page_size="paginationConfig.page_size"
|
||||
v-model:current_page="paginationConfig.current_page"
|
||||
@load="getList"
|
||||
:loading="loading"
|
||||
>
|
||||
<el-row :gutter="15">
|
||||
<el-col
|
||||
:xs="24"
|
||||
:sm="12"
|
||||
:md="8"
|
||||
:lg="6"
|
||||
:xl="6"
|
||||
class="mb-16"
|
||||
v-if="functionType === 'PUBLIC'"
|
||||
>
|
||||
<el-card shadow="hover" class="application-card-add" style="--el-card-padding: 8px">
|
||||
<div class="card-add-button flex align-center cursor p-8" @click="openCreateDialog()">
|
||||
<AppIcon iconName="app-add-application" class="mr-8"></AppIcon>
|
||||
{{ $t('views.functionLib.createFunction') }}
|
||||
</div>
|
||||
<el-divider style="margin: 8px 0" />
|
||||
<el-upload
|
||||
ref="elUploadRef"
|
||||
:file-list="[]"
|
||||
action="#"
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:limit="1"
|
||||
:on-change="(file: any, fileList: any) => importFunctionLib(file)"
|
||||
class="card-add-button"
|
||||
>
|
||||
<div class="flex align-center cursor p-8">
|
||||
<AppIcon iconName="app-import" class="mr-8"></AppIcon>
|
||||
{{ $t('views.functionLib.importFunction') }}
|
||||
</div>
|
||||
</el-upload>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col
|
||||
:xs="24"
|
||||
:sm="12"
|
||||
:md="8"
|
||||
:lg="6"
|
||||
:xl="6"
|
||||
v-for="(item, index) in functionLibList"
|
||||
:key="index"
|
||||
class="mb-16"
|
||||
>
|
||||
<CardBox
|
||||
v-if="functionType === 'PUBLIC'"
|
||||
:title="item.name"
|
||||
:description="item.desc"
|
||||
class="function-lib-card"
|
||||
@click="openCreateDialog(item)"
|
||||
:class="item.permission_type === 'PUBLIC' && !canEdit(item) ? '' : 'cursor'"
|
||||
>
|
||||
<template #icon>
|
||||
<AppAvatar
|
||||
v-if="isAppIcon(item?.icon)"
|
||||
shape="square"
|
||||
:size="32"
|
||||
style="background: none"
|
||||
class="mr-8"
|
||||
>
|
||||
<img :src="item?.icon" alt="" />
|
||||
</AppAvatar>
|
||||
<AppAvatar
|
||||
v-else-if="item?.name"
|
||||
:name="item?.name"
|
||||
pinyinColor
|
||||
shape="square"
|
||||
:size="32"
|
||||
class="mr-8"
|
||||
/>
|
||||
</template>
|
||||
<template #subTitle>
|
||||
<el-text class="color-secondary" size="small">
|
||||
<auto-tooltip :content="item.username">
|
||||
{{ $t('common.creator') }}: {{ item.username }}
|
||||
</auto-tooltip>
|
||||
</el-text>
|
||||
</template>
|
||||
<div class="status-button">
|
||||
<el-tag
|
||||
class="info-tag"
|
||||
v-if="item.permission_type === 'PUBLIC'"
|
||||
style="height: 22px"
|
||||
>
|
||||
{{ $t('common.public') }}</el-tag
|
||||
>
|
||||
<el-tag
|
||||
class="danger-tag"
|
||||
v-else-if="item.permission_type === 'PRIVATE'"
|
||||
style="height: 22px"
|
||||
>
|
||||
{{ $t('common.private') }}</el-tag
|
||||
>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="footer-content flex-between">
|
||||
<div>
|
||||
<span v-if="item.template_id"> {{ $t('common.author') }}: MaxKB</span>
|
||||
</div>
|
||||
<div @click.stop>
|
||||
<el-switch
|
||||
:disabled="item.permission_type === 'PUBLIC' && !canEdit(item)"
|
||||
v-model="item.is_active"
|
||||
@change="changeState($event, 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"
|
||||
:disabled="item.permission_type === 'PUBLIC' && !canEdit(item)"
|
||||
@click.stop="addInternalFunction(item, true)"
|
||||
>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
{{ $t('common.edit') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="!item.template_id"
|
||||
:disabled="item.permission_type === 'PUBLIC' && !canEdit(item)"
|
||||
@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"
|
||||
:disabled="item.permission_type === 'PUBLIC' && !canEdit(item)"
|
||||
@click.stop="configInitParams(item)"
|
||||
>
|
||||
<AppIcon iconName="app-operation" class="mr-4"></AppIcon>
|
||||
{{ $t('common.param.initParam') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
:disabled="item.permission_type === 'PUBLIC' && !canEdit(item)"
|
||||
@click.stop="configPermission(item)"
|
||||
>
|
||||
<el-icon><User /></el-icon>
|
||||
{{ $t('views.functionLib.functionForm.form.permission_type.label') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
:disabled="item.permission_type === 'PUBLIC' && !canEdit(item)"
|
||||
v-if="!item.template_id"
|
||||
@click.stop="exportFunctionLib(item)"
|
||||
>
|
||||
<AppIcon iconName="app-export"></AppIcon>
|
||||
{{ $t('common.export') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
:disabled="item.permission_type === 'PUBLIC' && !canEdit(item)"
|
||||
@click.stop="deleteFunctionLib(item)"
|
||||
>
|
||||
<el-icon><Delete /></el-icon>
|
||||
{{ $t('common.delete') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</CardBox>
|
||||
<CardBox
|
||||
v-if="functionType === 'INTERNAL'"
|
||||
:title="item.name"
|
||||
:description="item.desc"
|
||||
class="function-lib-card"
|
||||
@click="openDescDrawer(item)"
|
||||
:class="item.permission_type === 'PUBLIC' && !canEdit(item) ? '' : 'cursor'"
|
||||
>
|
||||
<template #icon>
|
||||
<AppAvatar
|
||||
v-if="isAppIcon(item?.icon)"
|
||||
shape="square"
|
||||
:size="32"
|
||||
style="background: none"
|
||||
class="mr-8"
|
||||
>
|
||||
<img :src="item?.icon" alt="" />
|
||||
</AppAvatar>
|
||||
<AppAvatar
|
||||
v-else-if="item?.name"
|
||||
:name="item?.name"
|
||||
pinyinColor
|
||||
shape="square"
|
||||
:size="32"
|
||||
class="mr-8"
|
||||
/>
|
||||
</template>
|
||||
<div class="status-button"></div>
|
||||
<template #footer>
|
||||
<div class="footer-content flex-between">
|
||||
<div>{{ $t('common.author') }}: MaxKB</div>
|
||||
<div @click.stop>
|
||||
<el-button type="primary" link @click="addInternalFunction(item)">
|
||||
{{ $t('common.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</CardBox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
<FunctionFormDrawer ref="FunctionFormDrawerRef" @refresh="refresh" :title="title" />
|
||||
<PermissionDialog ref="PermissionDialogRef" @refresh="refresh" />
|
||||
<AddInternalFunctionDialog
|
||||
ref="AddInternalFunctionDialogRef"
|
||||
@refresh="confirmAddInternalFunction"
|
||||
/>
|
||||
<InitParamDrawer ref="InitParamDrawerRef" @refresh="refresh" />
|
||||
<InternalDescDrawer ref="InternalDescDrawerRef" @addFunction="addInternalFunction" />
|
||||
</div>
|
||||
<CreateModelDialog
|
||||
ref="createModelRef"
|
||||
@submit="list_model"
|
||||
@change="openCreateModel($event)"
|
||||
></CreateModelDialog>
|
||||
|
||||
<SelectProviderDialog
|
||||
ref="selectProviderRef"
|
||||
@change="(provider, modelType) => openCreateModel(provider, modelType)"
|
||||
></SelectProviderDialog>
|
||||
</LayoutContainer> -->
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, reactive, watch, nextTick } from 'vue'
|
||||
import { cloneDeep, get } from 'lodash'
|
||||
import functionLibApi from '@/api/function-lib'
|
||||
import FunctionFormDrawer from './component/FunctionFormDrawer.vue'
|
||||
import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
|
||||
import useStore from '@/stores'
|
||||
import applicationApi from '@/api/application'
|
||||
import { t } from '@/locales'
|
||||
import PermissionDialog from '@/views/function-lib/component/PermissionDialog.vue'
|
||||
import InitParamDrawer from '@/views/function-lib/component/InitParamDrawer.vue'
|
||||
import InternalDescDrawer from '@/views/function-lib/component/InternalDescDrawer.vue'
|
||||
import { isAppIcon } from '@/utils/application'
|
||||
import InfiniteScroll from '@/components/infinite-scroll/index.vue'
|
||||
import CardBox from '@/components/card-box/index.vue'
|
||||
import AddInternalFunctionDialog from '@/views/function-lib/component/AddInternalFunctionDialog.vue'
|
||||
|
||||
const { user } = useStore()
|
||||
<script lang="ts" setup>
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const InternalDescDrawerRef = ref()
|
||||
const FunctionFormDrawerRef = ref()
|
||||
const PermissionDialogRef = ref()
|
||||
const AddInternalFunctionDialogRef = ref()
|
||||
const InitParamDrawerRef = ref()
|
||||
|
||||
const functionLibList = ref<any[]>([])
|
||||
|
||||
const paginationConfig = reactive({
|
||||
current_page: 1,
|
||||
page_size: 30,
|
||||
total: 0
|
||||
})
|
||||
|
||||
const searchValue = ref('')
|
||||
const title = ref('')
|
||||
const changeStateloading = ref(false)
|
||||
|
||||
interface UserOption {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
const userOptions = ref<UserOption[]>([])
|
||||
|
||||
const selectUserId = ref('all')
|
||||
const elUploadRef = ref<any>()
|
||||
|
||||
const functionType = ref('PUBLIC')
|
||||
|
||||
watch(
|
||||
functionType,
|
||||
(val) => {
|
||||
paginationConfig.total = 0
|
||||
paginationConfig.current_page = 1
|
||||
functionLibList.value = []
|
||||
getList()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
function tabChangeHandle() {
|
||||
selectUserId.value = 'all'
|
||||
searchValue.value = ''
|
||||
}
|
||||
|
||||
const canEdit = (row: any) => {
|
||||
return user.userInfo?.id === row?.user_id
|
||||
}
|
||||
|
||||
function openCreateDialog(data?: any) {
|
||||
// 有template_id的不允许编辑,是模板转换来的
|
||||
if (data?.template_id) {
|
||||
return
|
||||
}
|
||||
// console.log(data)
|
||||
title.value = data ? t('views.functionLib.editFunction') : t('views.functionLib.createFunction')
|
||||
if (data) {
|
||||
if (data?.permission_type !== 'PUBLIC' || canEdit(data)) {
|
||||
functionLibApi.getFunctionLibById(data?.id, changeStateloading).then((res) => {
|
||||
FunctionFormDrawerRef.value.open(res.data)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
FunctionFormDrawerRef.value.open(data)
|
||||
}
|
||||
}
|
||||
|
||||
async function openDescDrawer(row: any) {
|
||||
const index = row.icon.replace('icon.png', 'detail.md')
|
||||
const response = await fetch(index)
|
||||
const content = await response.text()
|
||||
InternalDescDrawerRef.value.open(content, row)
|
||||
}
|
||||
|
||||
function addInternalFunction(data?: any, isEdit?: boolean) {
|
||||
AddInternalFunctionDialogRef.value.open(data, isEdit)
|
||||
}
|
||||
|
||||
function confirmAddInternalFunction(data?: any, isEdit?: boolean) {
|
||||
if (isEdit) {
|
||||
functionLibApi.putFunctionLib(data?.id as string, data, loading).then((res) => {
|
||||
MsgSuccess(t('common.saveSuccess'))
|
||||
searchHandle()
|
||||
})
|
||||
} else {
|
||||
functionLibApi
|
||||
.addInternalFunction(data.id, { name: data.name }, changeStateloading)
|
||||
.then((res) => {
|
||||
MsgSuccess(t('common.addSuccess'))
|
||||
searchHandle()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function searchHandle() {
|
||||
if (user.userInfo) {
|
||||
localStorage.setItem(user.userInfo.id + 'function', selectUserId.value)
|
||||
}
|
||||
paginationConfig.total = 0
|
||||
paginationConfig.current_page = 1
|
||||
functionLibList.value = []
|
||||
getList()
|
||||
}
|
||||
|
||||
async function changeState(bool: Boolean, 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
|
||||
}
|
||||
functionLibApi.putFunctionLib(row.id, obj, changeStateloading).then((res) => {})
|
||||
})
|
||||
.catch(() => {
|
||||
row.is_active = true
|
||||
})
|
||||
} else {
|
||||
const res = await functionLibApi.getFunctionLibById(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
|
||||
) {
|
||||
InitParamDrawerRef.value.open(res.data, bool)
|
||||
row.is_active = false
|
||||
return
|
||||
}
|
||||
const init_params = res.data.init_field_list.reduce((acc: any, item: any) => {
|
||||
acc[item.field] = item.default_value
|
||||
return acc
|
||||
}, {})
|
||||
const obj = {
|
||||
is_active: bool,
|
||||
init_params: init_params,
|
||||
init_field_list: res.data.init_field_list
|
||||
}
|
||||
functionLibApi.putFunctionLib(row.id, obj, changeStateloading).then((res) => {})
|
||||
}
|
||||
}
|
||||
|
||||
function deleteFunctionLib(row: any) {
|
||||
MsgConfirm(
|
||||
`${t('views.functionLib.delete.confirmTitle')}${row.name} ?`,
|
||||
t('views.functionLib.delete.confirmMessage'),
|
||||
{
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
confirmButtonClass: 'danger'
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
functionLibApi.delFunctionLib(row.id, loading).then(() => {
|
||||
const index = functionLibList.value.findIndex((v) => v.id === row.id)
|
||||
functionLibList.value.splice(index, 1)
|
||||
MsgSuccess(t('common.deleteSuccess'))
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
function copyFunctionLib(row: any) {
|
||||
title.value = t('views.functionLib.copyFunction')
|
||||
const obj = cloneDeep(row)
|
||||
delete obj['id']
|
||||
obj['name'] = obj['name'] + ` ${t('views.functionLib.functionForm.title.copy')}`
|
||||
FunctionFormDrawerRef.value.open(obj)
|
||||
}
|
||||
|
||||
function exportFunctionLib(row: any) {
|
||||
functionLibApi.exportFunctionLib(row.id, row.name, loading).catch((e: any) => {
|
||||
if (e.response.status !== 403) {
|
||||
e.response.data.text().then((res: string) => {
|
||||
MsgError(`${t('views.application.tip.ExportError')}:${JSON.parse(res).message}`)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function configPermission(item: any) {
|
||||
PermissionDialogRef.value.open(item)
|
||||
}
|
||||
|
||||
function configInitParams(item: any) {
|
||||
functionLibApi.getFunctionLibById(item?.id, changeStateloading).then((res) => {
|
||||
InitParamDrawerRef.value.open(res.data)
|
||||
})
|
||||
}
|
||||
|
||||
function importFunctionLib(file: any) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file.raw, file.name)
|
||||
elUploadRef.value.clearFiles()
|
||||
functionLibApi
|
||||
.importFunctionLib(formData, loading)
|
||||
.then(async (res: any) => {
|
||||
if (res?.data) {
|
||||
searchHandle()
|
||||
}
|
||||
})
|
||||
.catch((e: any) => {
|
||||
if (e.code === 400) {
|
||||
MsgConfirm(t('common.tip'), t('views.application.tip.professionalMessage'), {
|
||||
cancelButtonText: t('common.confirm'),
|
||||
confirmButtonText: t('common.professional')
|
||||
}).then(() => {
|
||||
window.open('https://maxkb.cn/pricing.html', '_blank')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function getList() {
|
||||
if (userOptions.value?.length === 0) {
|
||||
await getUserList()
|
||||
}
|
||||
const params = {
|
||||
...(searchValue.value && { name: searchValue.value }),
|
||||
...(functionType.value && { function_type: functionType.value }),
|
||||
...(selectUserId.value &&
|
||||
selectUserId.value !== 'all' && { select_user_id: selectUserId.value })
|
||||
}
|
||||
functionLibApi.getFunctionLib(paginationConfig, params, loading).then((res: any) => {
|
||||
res.data.records.forEach((item: any) => {
|
||||
if (user.userInfo && item.user_id === user.userInfo.id) {
|
||||
item.username = user.userInfo.username
|
||||
} else {
|
||||
item.username = userOptions.value.find((v) => v.value === item.user_id)?.label
|
||||
}
|
||||
})
|
||||
functionLibList.value = [...functionLibList.value, ...res.data.records]
|
||||
paginationConfig.total = res.data.total
|
||||
})
|
||||
}
|
||||
|
||||
function refresh(data: any) {
|
||||
if (data) {
|
||||
const index = functionLibList.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
|
||||
}
|
||||
functionLibList.value.splice(index, 1, data)
|
||||
}
|
||||
paginationConfig.total = 0
|
||||
paginationConfig.current_page = 1
|
||||
functionLibList.value = []
|
||||
getList()
|
||||
}
|
||||
|
||||
async function getUserList() {
|
||||
const res = await applicationApi.getUserList('FUNCTION', loading)
|
||||
if (res.data) {
|
||||
userOptions.value = res.data.map((item: any) => {
|
||||
return {
|
||||
label: item.username,
|
||||
value: item.id
|
||||
}
|
||||
})
|
||||
if (user.userInfo) {
|
||||
const selectUserIdValue = localStorage.getItem(user.userInfo.id + 'function')
|
||||
if (selectUserIdValue && userOptions.value.find((v) => v.value === selectUserIdValue)) {
|
||||
selectUserId.value = selectUserIdValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.application-card-add {
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
min-height: var(--card-min-height);
|
||||
border: 1px dashed var(--el-border-color);
|
||||
background: var(--el-disabled-bg-color);
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid var(--el-card-bg-color);
|
||||
background-color: var(--el-card-bg-color);
|
||||
.model-manage {
|
||||
&__left {
|
||||
box-sizing: border-box;
|
||||
width: var(--setting-left-width);
|
||||
min-width: var(--setting-left-width);
|
||||
}
|
||||
|
||||
.card-add-button {
|
||||
&:hover {
|
||||
border-radius: 4px;
|
||||
background: var(--app-text-color-light-1);
|
||||
.model-list-height {
|
||||
height: calc(var(--create-dataset-height) - 80px);
|
||||
}
|
||||
|
||||
.model-list-height-left {
|
||||
height: calc(var(--create-dataset-height) - 40px);
|
||||
}
|
||||
.all-mode {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
.all-mode-active {
|
||||
background: var(--el-color-primary-light-9);
|
||||
border-radius: 4px;
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
.template-collapse {
|
||||
border-top: none !important;
|
||||
border-bottom: none !important;
|
||||
:deep(.el-collapse-item__header) {
|
||||
border-bottom: none !important;
|
||||
padding-left: 16px;
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
&:hover {
|
||||
background: var(--app-text-color-light-1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-upload) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
color: var(--el-text-color-regular);
|
||||
:deep(.el-collapse-item) {
|
||||
margin-top: 2px;
|
||||
}
|
||||
:deep(.common-list) {
|
||||
li {
|
||||
padding-left: 30px !important;
|
||||
}
|
||||
}
|
||||
:deep(.el-collapse-item__wrap) {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
:deep(.el-collapse-item__content) {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.application-card {
|
||||
.status-tag {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.function-lib-list-container {
|
||||
.status-button {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 15px;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue