feat: 应用

This commit is contained in:
wangdan-fit2cloud 2023-11-24 14:49:25 +08:00
parent cda71da7ce
commit 11f29317c8
13 changed files with 210 additions and 46 deletions

11
ui/package-lock.json generated
View File

@ -11,6 +11,7 @@
"axios": "^0.27.2", "axios": "^0.27.2",
"element-plus": "^2.3.14", "element-plus": "^2.3.14",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mitt": "^3.0.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pinia": "^2.1.6", "pinia": "^2.1.6",
"vue": "^3.3.4", "vue": "^3.3.4",
@ -3602,6 +3603,11 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
},
"node_modules/mlly": { "node_modules/mlly": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz",
@ -8411,6 +8417,11 @@
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
},
"mlly": { "mlly": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz",

View File

@ -1,5 +1,3 @@
import { SrvRecord } from 'dns'
interface modelRequest { interface modelRequest {
name: string name: string
model_type: string model_type: string

View File

@ -26,6 +26,7 @@ defineProps({
min-height: var(--card-min-height); min-height: var(--card-min-height);
border: 1px dashed var(--el-color-primary); border: 1px dashed var(--el-color-primary);
background: #eff0f1; background: #eff0f1;
border-radius: 8px;
.add-icon { .add-icon {
font-size: 14px; font-size: 14px;

View File

@ -54,6 +54,7 @@ function cardLeave() {
position: relative; position: relative;
min-height: var(--card-min-height); min-height: var(--card-min-height);
border: 1px solid #ffffff; border: 1px solid #ffffff;
border-radius: 8px;
.description { .description {
display: -webkit-box; display: -webkit-box;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;

View File

@ -221,5 +221,25 @@ export const iconMap: any = {
) )
]) ])
} }
},
'app-hide-password': {
iconReader: () => {
return h('i', [
h(
'svg',
{
viewBox: '0 0 16 16',
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg'
},
[
h('path', {
d: 'M7.99998 10.0002C7.56178 10.0002 7.13299 9.96572 6.7171 9.8997L6.38511 11.1387C6.33746 11.3165 6.15468 11.4221 5.97686 11.3744L5.33291 11.2019C5.15509 11.1542 5.04956 10.9714 5.09721 10.7936L5.4223 9.58034C4.87988 9.3961 4.37072 9.15543 3.90466 8.86678L2.84516 9.92629C2.71498 10.0565 2.50393 10.0565 2.37375 9.92629L1.90235 9.45489C1.77217 9.32471 1.77217 9.11366 1.90235 8.98348L2.8354 8.05043C2.35399 7.59967 1.95185 7.08569 1.64787 6.5247C1.64468 6.51881 1.64138 6.51264 1.63799 6.50624C1.51335 6.27086 1.55999 5.97623 1.75685 5.79684C1.92026 5.64792 2.03572 5.54659 2.13615 5.44616C2.14513 5.43717 2.15496 5.42715 2.16545 5.41632C2.31084 5.26609 2.55878 5.32201 2.64392 5.51294C3.47403 7.37447 5.46187 8.6669 7.99998 8.6669C10.4318 8.6669 12.4662 7.40921 13.2827 5.68288C13.3039 5.63796 13.3277 5.58139 13.3516 5.52133C13.4274 5.33113 13.6738 5.27374 13.8186 5.41849C13.9256 5.52556 14.0684 5.66833 14.2469 5.84678C14.4233 6.02319 14.471 6.29259 14.3557 6.51383C14.3277 6.56764 14.3004 6.61834 14.2771 6.65865C13.9636 7.20157 13.5569 7.69799 13.0751 8.13259L13.926 8.98348C14.0562 9.11366 14.0562 9.32471 13.926 9.45489L13.4546 9.92629C13.3245 10.0565 13.1134 10.0565 12.9832 9.92629L11.9885 8.93161C11.5518 9.1916 11.0789 9.41007 10.5777 9.58034L10.9027 10.7936C10.9504 10.9714 10.8449 11.1542 10.667 11.2019L10.0231 11.3744C9.84527 11.4221 9.66249 11.3165 9.61485 11.1387L9.28285 9.8997C8.86696 9.96572 8.43817 10.0002 7.99998 10.0002Z',
fill: 'currentColor'
})
]
)
])
}
} }
} }

View File

@ -14,7 +14,7 @@ const applicationRouter = {
path: '/application/create', path: '/application/create',
name: 'CreateApplication', name: 'CreateApplication',
meta: { activeMenu: '/application' }, meta: { activeMenu: '/application' },
component: () => import('@/views/application/CreateApplication.vue'), component: () => import('@/views/application/CreateAndSetting.vue'),
hidden: true hidden: true
}, },
{ {
@ -46,7 +46,7 @@ const applicationRouter = {
parentPath: '/application/:appId', parentPath: '/application/:appId',
parentName: 'ApplicationDetail' parentName: 'ApplicationDetail'
}, },
component: () => import('@/views/application/AppSetting.vue') component: () => import('@/views/application/CreateAndSetting.vue')
}, },
{ {
path: 'dialog', path: 'dialog',

View File

@ -1,6 +1,6 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import modelApi from '@/api/model' import modelApi from '@/api/model'
import type { modelRequest } from '@/api/type/model' import type { modelRequest, Provider } from '@/api/type/model'
const useModelStore = defineStore({ const useModelStore = defineStore({
id: 'model', id: 'model',
state: () => ({}), state: () => ({}),

View File

@ -93,7 +93,6 @@
} }
.el-card { .el-card {
--el-card-border-radius: 8px;
--el-card-padding: calc(var(--app-base-px) * 2); --el-card-padding: calc(var(--app-base-px) * 2);
} }
.el-dropdown { .el-dropdown {
@ -185,4 +184,6 @@
font-size: 13px; font-size: 13px;
} }
.el-select-group .el-select-dropdown__item {
padding-left: 11px;
}

View File

@ -1,8 +1,76 @@
<template> <template>
<div> <LayoutContainer header="概览" back-to="-1">
概览 <div class="main-calc-height p-24">
</div> <h4 class="title-decoration-1 mb-16">应用信息</h4>
<el-card shadow="never" class="overview-card">
<div class="title flex align-center">
<AppAvatar class="mr-12" shape="square" :size="32">
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
</AppAvatar>
<h4 class="ellipsis-1">应用</h4>
<div class="ml-8">
<el-tag class="warning-tag">已停用</el-tag>
<el-tag class="success-tag">运行中</el-tag>
</div>
</div>
<div class="active-button" @click.stop>
<el-switch />
</div>
<el-row class="mt-16">
<el-col :span="12">
<el-text type="info">公开访问链接</el-text>
<div class="mt-4">
<span class="vertical-middle lighter">
https:/fit2cloud.com/xlab-fit2cloud/smart-doc/16826
</span>
<el-button type="primary" text>
<el-icon style="font-size: 13px"><CopyDocument /></el-icon>
</el-button>
</div>
</el-col>
<el-col :span="12">
<el-text type="info">API访问凭据</el-text>
<div class="mt-4">
<span class="vertical-middle lighter">
API Key: OGZmZThlZjYyYzU2MWE1OTlkYTVjZTBi
</span>
<el-button type="primary" text>
<el-icon style="font-size: 13px"><CopyDocument /></el-icon>
</el-button>
</div>
<div class="mt-4">
<span class="vertical-middle lighter"> API Secret: ************** </span>
<span>
<el-button type="primary" text>
<el-icon style="font-size: 13px"><CopyDocument /></el-icon>
</el-button>
</span>
<span>
<el-button type="primary" text>
<AppIcon iconName="app-hide-password" />
</el-button>
</span>
</div>
</el-col>
</el-row>
<div class="mt-16">
<el-button type="primary"> 演示 </el-button>
<el-button> 嵌入第三方 </el-button>
</div>
</el-card>
</div>
</LayoutContainer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts"></script>
</script> <style lang="scss" scoped>
<style lang="scss" scoped></style> .overview-card {
position: relative;
.active-button {
position: absolute;
right: 16px;
top: 21px;
}
}
</style>

View File

@ -1,8 +0,0 @@
<template>
<div>
设置
</div>
</template>
<script setup lang="ts">
</script>
<style lang="scss" scoped></style>

View File

@ -1,5 +1,5 @@
<template> <template>
<LayoutContainer header="创建应用" back-to="-1" class="create-application"> <LayoutContainer :header="appId ? '设置' : '创建应用'" back-to="-1" class="create-application">
<el-row> <el-row>
<el-col :span="10"> <el-col :span="10">
<div class="p-24 mb-16" style="padding-bottom: 0"> <div class="p-24 mb-16" style="padding-bottom: 0">
@ -34,11 +34,12 @@
show-word-limit show-word-limit
/> />
</el-form-item> </el-form-item>
<div v-html="realatedProvider('model_azure_provider', 'icon')"></div>
<el-form-item label="选择模型" prop="model_id"> <el-form-item label="选择模型" prop="model_id">
<el-select v-model="applicationForm.model_id" placeholder="请选择模型"> <el-select
v-model="applicationForm.model_id"
placeholder="请选择模型"
style="width: 100%"
>
<el-option-group <el-option-group
v-for="(value, label) in modelOptions" v-for="(value, label) in modelOptions"
:key="value" :key="value"
@ -49,16 +50,30 @@
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
:value="item.id" :value="item.id"
class="flex-between"
> >
<div v-html="realatedProvider(label, 'icon')" class="model-icon"></div> <div class="flex">
<span>{{ item.name }}</span> <span
v-html="realatedProvider(label, 'icon')"
class="model-icon mr-8"
></span>
<span>{{ item.name }}</span>
</div>
<el-icon class="check-icon" v-if="item.id === applicationForm.model_id"
><Check
/></el-icon>
</el-option> </el-option>
</el-option-group> </el-option-group>
<div class="border-t" style="padding: 8px 11px">
<el-button type="primary" link>
<el-icon class="mr-4"><Plus /></el-icon>
</el-button>
</div>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="多轮对话"> <el-form-item label="多轮对话" @click.prevent>
<el-switch v-model="applicationForm.multiple_rounds_dialogue" /> <el-switch v-model="applicationForm.multiple_rounds_dialogue"></el-switch>
</el-form-item> </el-form-item>
<el-form-item label="关联数据集"> <el-form-item label="关联数据集">
<template #label> <template #label>
@ -131,13 +146,21 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, watch, onMounted } from 'vue' import { reactive, ref, watch, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { groupBy } from 'lodash' import { groupBy } from 'lodash'
import AiDialog from '@/components/ai-dialog/index.vue' import AiDialog from '@/components/ai-dialog/index.vue'
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import type { ApplicationFormType } from '@/api/type/application' import type { ApplicationFormType } from '@/api/type/application'
import type { Provider } from '@/api/type/model'
import useStore from '@/stores' import useStore from '@/stores'
const { model } = useStore() const { model } = useStore()
const router = useRouter()
const route = useRoute()
const {
params: { appId }
} = route as any
const applicationFormRef = ref<FormInstance>() const applicationFormRef = ref<FormInstance>()
const loading = ref(false) const loading = ref(false)
@ -162,8 +185,8 @@ const rules = reactive<FormRules<ApplicationFormType>>({
} }
] ]
}) })
const modelOptions = ref([]) const modelOptions = ref<any>(null)
const providerOptions = ref([]) const providerOptions = ref<Array<Provider>>([])
watch(exampleList.value, () => { watch(exampleList.value, () => {
applicationForm.example = exampleList.value.filter((v) => v) applicationForm.example = exampleList.value.filter((v) => v)
@ -173,9 +196,8 @@ function getModel() {
loading.value = true loading.value = true
model model
.asyncGetModel() .asyncGetModel()
.then((res) => { .then((res: any) => {
modelOptions.value = groupBy(res?.data, 'provider') modelOptions.value = groupBy(res?.data, 'provider')
console.log(modelOptions.value)
loading.value = false loading.value = false
}) })
.catch(() => { .catch(() => {
@ -187,7 +209,7 @@ function getProvider() {
loading.value = true loading.value = true
model model
.asyncGetProvider() .asyncGetProvider()
.then((res) => { .then((res: any) => {
providerOptions.value = res?.data providerOptions.value = res?.data
loading.value = false loading.value = false
}) })
@ -196,9 +218,10 @@ function getProvider() {
}) })
} }
function realatedProvider(val, attr) { function realatedProvider(val: string | number, attr: string) {
const filterProvider = providerOptions.value.filter((item) => item.provider === val)?.[0] const filterProvider: any = providerOptions.value.filter(
console.log(filterProvider) (item: any) => item.provider === val
)?.[0]
return filterProvider?.[attr] || '' return filterProvider?.[attr] || ''
} }
@ -220,16 +243,17 @@ onMounted(() => {
box-sizing: border-box; box-sizing: border-box;
} }
.scrollbar-height-left { .scrollbar-height-left {
height: calc(var(--app-main-height) - 100px); height: calc(var(--app-main-height) - 127px);
} }
.scrollbar-height { .scrollbar-height {
height: calc(var(--app-main-height) - 150px); height: calc(var(--app-main-height) - 150px);
} }
} }
.model-icon { .model-icon {
svg { width: 20px;
width: 30px; }
} .check-icon {
} position: absolute;
right: 10px;
}
</style> </style>

View File

@ -0,0 +1,48 @@
<template>
<el-dialog title="添加关联数据集" v-model="dialogVisible" width="600">
<el-row :gutter="12">
<el-col :span="12">
<el-card shadow="hover"> Hover </el-card>
</el-col>
<el-col :span="12">
<el-card shadow="hover"> Hover </el-card>
</el-col>
</el-row>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" @click="submitHandle"> 保存 </el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
const emit = defineEmits(['updateContent'])
const dialogVisible = ref<boolean>(false)
const detail = ref({})
const paragraphFormRef = ref()
watch(dialogVisible, (bool) => {
if (!bool) {
detail.value = {}
}
})
const open = (data: any) => {
dialogVisible.value = true
}
const submitHandle = async () => {
if (await paragraphFormRef.value?.validate()) {
emit('updateContent', paragraphFormRef.value?.form)
dialogVisible.value = false
}
}
defineExpose({ open })
</script>
<style lang="scss" scope></style>

View File

@ -128,9 +128,9 @@ function getList() {
.getApplication(pageConfig) .getApplication(pageConfig)
.then((res) => { .then((res) => {
const list = res.data?.records const list = res.data?.records
list.map((item) => { list.map((item: any) => {
applicationList.value.push({ applicationList.value.push({
value:item.provider, value: item.provider,
label: item.name label: item.name
}) })
}) })