You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

599 lines
18 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="title-div">
<div class="title-span-div">
<div class="title-icon"></div>
<div class="title-span">{{props.modalType == 'insert'? '创建算法': '编辑算法'}}</div>
</div>
<div class="close-button" @click="emits('changeAddModal',false)"></div>
</div>
<div class="interval"></div>
<a-spin tip="加载中..." :spinning="loading">
<div class="modal-content">
<div class="left-content">
<div class="item-title">模型名称</div>
<a-input class="name-input" v-model:value="name" placeholder="请输入相关名称" />
<div class="item-title">模型描述</div>
<a-textarea class="item-desc" v-model:value="describe" placeholder="请输入相关描述" :rows="4" />
<div class="item-title">模型封面</div>
<div class="item-image">
<img v-if="pic" class="show-image" :src="`${VITE_GLOB_API_URL}/${pic}`" @click="changeSelectImageModal(true)"/>
<div v-else class="empty-image" @click="changeSelectImageModal(true)">
<div class="empty-image-content">
<div class="empty-image-icon"></div>
<div class="empty-image-span">请选择文件上传</div>
</div>
</div>
</div>
</div>
<div class="right-content">
<div class="item-title">模型类型</div>
<a-segmented class="item-type" v-model:value="type" :options="modelTypeOptions"></a-segmented>
<template v-if="type == 0">
<div class="item-title">模型规模</div>
<a-segmented class="item-type" v-model:value="size" :options="modelScaleOptions"></a-segmented>
<div class="item-title">模型文件</div>
<a-upload
:file-list="modelFile"
accept=".zip,.pt"
:max-count="1"
:custom-request="customRequest"
>
<a-button class="select-model-file-button" type="primary" :icon="h(PlusOutlined)">选择模型文件</a-button>
</a-upload>
<div class="upload-hint">*请上传模型压缩文件支持pt格式</div>
<div class="item-title">模型标签</div>
<div class="item-label-div">
<div class="label-title-div">
<div class="label-title-span">请根据模型实际情况填写信息</div>
<div class="add-button" @click="addLabelRow">
<div class="button-icon"></div>
<div class="button-span">添加行</div>
</div>
</div>
<div class="label-interval"></div>
<div class="label-table-title">
<div class="table-title-item" style="padding-left: 6px;">枚举值</div>
<div class="table-title-item">名称</div>
<div class="table-title-item">推荐置信度</div>
<div class="table-title-item" style="width: 55px;justify-content: center;">操作</div>
</div>
<div class="label-table-content">
<div class="table-row" v-for="(item,index) in modelLabels" :key="index">
<div class="table-item">
<a-input class="table-item-input" v-model:value="item.enumValue"/>
</div>
<div class="table-item">
<a-input class="table-item-input" v-model:value="item.name"/>
</div>
<div class="table-item">
<a-input class="table-item-input" v-model:value="item.reliability"/>
</div>
<div class="table-item" style="width: 55px; justify-content: center">
<div class="del-table-row" @click="delLabelRow(index)"></div>
</div>
</div>
</div>
</div>
</template>
<template v-else>
<div class="item-title">推流地址</div>
<a-input class="name-input" v-model:value="pushUrl" placeholder="请输入地址" />
<div class="item-title">拉流地址</div>
<a-input class="name-input" v-model:value="pullUrl" placeholder="请输入地址" />
<div class="item-title">服务地址</div>
<a-input class="name-input" v-model:value="serviceUrl" placeholder="请输入地址" />
<div class="item-title">密钥</div>
<a-textarea class="item-key" v-model:value="secretKey" placeholder="请输入密钥" :rows="4" />
</template>
</div>
</div>
<div class="interval"></div>
<div class="footer">
<a-button class="cancel-button" @click="emits('changeAddModal',false)">取消</a-button>
<a-button v-if="props.modalType == 'update'" class="delete-button" type="primary" @click="delData">删除</a-button>
<a-button class="save-button" type="primary" @click="submit">确定</a-button>
</div>
</a-spin>
<a-modal v-model:open="selectImageModal" title="选择封面" width="1000px" :footer="null" :destroyOnClose="true">
<SelectImageModal @changeSelectImageModal="changeSelectImageModal" @getResultImage="getResultImage"/>
</a-modal>
</template>
<script setup lang="ts">
import { ref, h, defineEmits, defineProps, onMounted, createVNode } from "vue"
import { uploadFile } from '@/api/formrender/index';
import { ExclamationCircleOutlined, PlusOutlined, } from '@ant-design/icons-vue';
import SelectImageModal from "./SelectImageModal.vue";
import { ModelLabelsType } from './utils'
import { getAppEnvConfig } from '@/utils/env';
import { AddAlgorithmsRepository, UpdateAlgorithmsRepository, DeleteAlgorithmsRepository } from '@/api/demo/ailist'
import { message, Modal } from "ant-design-vue";
const { VITE_GLOB_API_URL } = getAppEnvConfig();
const props = defineProps(['modalType', 'algorithmInfo'])
const emits = defineEmits(['changeAddModal', 'query'])
onMounted(() => {
if(props.modalType == 'update'){
id.value = props.algorithmInfo.id
name.value = props.algorithmInfo.name
describe.value = props.algorithmInfo.describe
pic.value = props.algorithmInfo.pic
type.value = props.algorithmInfo.type
size.value = props.algorithmInfo.size
pullUrl.value = props.algorithmInfo.pullUrl
pushUrl.value = props.algorithmInfo.pushUrl
serviceUrl.value = props.algorithmInfo.serviceUrl
secretKey.value = props.algorithmInfo.secretKey
path.value = props.algorithmInfo.path
modelLabels.value = props.algorithmInfo.modelLabels
modelFile.value?.push({
uid: '-1',
name: props.algorithmInfo.path,
status: 'done',
url: VITE_GLOB_API_URL + '/' + props.algorithmInfo.path,
});
}
})
const id = ref('')
const name = ref('')
const describe = ref('')
const pic = ref('')
const type = ref(0)
const size = ref('N')
const pullUrl = ref('')
const pushUrl = ref('')
const serviceUrl = ref('')
const secretKey = ref('')
const modelFile = ref<any>([])
const path = ref()
const modelLabels = ref<ModelLabelsType[]>([])
const selectImageModal = ref(false)
const loading = ref(false)
const modelTypeOptions = ref([
{ label: '本地模型', value: 0 },
{ label: '远程模型', value: 1 }
])
const modelScaleOptions = ref([
{ label: 'N', value: 'N' },
{ label: 'S', value: 'S' },
{ label: 'M', value: 'M' },
{ label: 'L', value: 'L' },
{ label: 'XI', value: 'XI' },
])
const customRequest = (file) => {
modelFile.value = []
const formData = new FormData()
formData.append('files', file.file)
uploadFile(formData).then(res => {
modelFile.value?.push({
uid: '-1',
name: res[0].filePath,
status: 'done',
url: VITE_GLOB_API_URL + '/' + res[0].filePath,
});
path.value = res[0].filePath
})
}
const addLabelRow = () => {
modelLabels.value.push({
id: '',
name: '',
enumValue: '',
reliability: '',
pId: ''
})
}
const delLabelRow = (index) => {
modelLabels.value.splice(index,1)
}
const changeSelectImageModal = (type: boolean) => {
selectImageModal.value = type
}
const getResultImage = (url: string) => {
pic.value = url
}
const submit = () => {
loading.value = true
let params = {
id: id.value,
name: name.value,
describe: describe.value,
pic: pic.value,
size: size.value,
type: type.value,
path: path.value,
pushUrl: pushUrl.value,
pullUrl: pullUrl.value,
serviceUrl: serviceUrl.value,
secretKey: secretKey.value,
modelLabels: modelLabels.value
}
console.log('params',params)
if(props.modalType == 'insert'){
AddAlgorithmsRepository(params).then(res => {
message.success('算法创建成功')
emits('query')
emits('changeAddModal',false)
}).finally(() => {
loading.value = false
})
}else{
UpdateAlgorithmsRepository(params).then(res => {
message.success('算法修改成功')
emits('query')
emits('changeAddModal',false)
}).finally(() => {
loading.value = false
})
}
}
const delData = () => {
Modal.confirm({
title: `确认删除该算法吗?`,
icon: createVNode(ExclamationCircleOutlined),
okText: '确认',
cancelText: '取消',
centered: true,
onOk() {
return DeleteAlgorithmsRepository({id: id.value}).then(res => {
message.success("删除成功")
emits('query')
emits('changeAddModal',false)
})
},
});
}
</script>
<style lang="scss" scoped>
.title-div{
width: 100%;
height: 64px;
padding-top: 15px;
padding-left: 26px;
padding-right: 35px;
padding-bottom: 14px;
display: flex;
justify-content: space-between;
align-items: center;
.title-span-div{
display: flex;
align-items: center;
.title-icon{
width: 3px;
height: 18px;
background: #0B60BD;
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
margin-right: 9px;
}
.title-span{
font-family: PingFangSC-Medium;
font-weight: 500;
font-size: 20px;
color: #11131B;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
}
}
.close-button{
width: 18px;
height: 18px;
background-image: url('/public/ailist/add_algorithm_close_button.png');
cursor: pointer;
}
}
.interval{
width: 631px;
height: 1px;
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border: 1px solid #DBDBDB;
opacity: 0.66;
}
.modal-content{
display: flex;
padding-top: 14px;
padding-left: 27px;
padding-right: 35px;
padding-bottom: 28px;
.item-title{
font-family: PingFangSC-Medium;
font-weight: 500;
font-size: 16px;
color: #222738;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
margin-bottom: 9px;
}
.name-input{
height: 40px;
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border-radius: 2px;
border: 1px solid #CCCCCC;
margin-bottom: 6px;
}
.left-content{
width: 253px;
margin-right: 46px;
.item-desc{
height: 151px;
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border-radius: 2px;
border: 1px solid #CCCCCC;
margin-bottom: 6px;
}
.item-image{
position: relative;
width: 100%;
height: 155px;
background: #F5F5F5;
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border: 2px dashed rgba(28,29,34,0.08);
.show-image{
width: 249px;
height: 151px;
cursor: pointer;
}
.empty-image{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 209px;
height: 119px;
background: #FFFFFF;
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15), 0px 8px 6px 0px rgba(28,29,34,0.06);
border-radius: 2px;
border: 1px solid #CCCCCC;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
.empty-image-content{
width: 98px;
height: 63px;
display: flex;
flex-direction: column;
align-items: center;
.empty-image-icon{
width: 26px;
height: 28px;
background-image: url('/public/ailist/algorithm_upload_icon.png');
margin-bottom: 1px;
}
.empty-image-span{
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 14px;
color: #222738;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
}
}
}
}
}
.right-content{
width: 269px;
.item-type{
width: 262px;
height: 40px;
background: rgba(28,29,34,0.04);
border-radius: 20px;
margin-bottom: 6px;
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
:deep(.ant-segmented-group){
height: 36px;
}
:deep(.ant-segmented-item){
width: 50%;
display: flex;
align-items: center;
justify-content: center;
border-radius: 18px;
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 14px;
color: rgba(28,29,34,0.5);
line-height: 20px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
}
:deep(.ant-segmented-item-selected){
font-weight: 500;
color: #1C1D22;
}
}
.select-model-file-button{
width: 151px;
height: 40px;
background: #0D68CB;
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border-radius: 2px;
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 16px;
color: #FFFFFF;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
}
.upload-hint{
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 12px;
color: #333333;
line-height: 28px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
}
.item-label-div{
width: 100%;
height: 155px;
background: #F5F5F5;
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border-radius: 2px;
padding-top: 3px;
padding-left: 8px;
padding-right: 10px;
.label-title-div{
width: 100%;
height: 34px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 4px;
.label-title-span{
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 12px;
color: #222738;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
}
.add-button{
width: 66px;
height: 26px;
background: #FFFFFF;
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15), 0px 8px 6px 0px rgba(28,29,34,0.06);
border: 1px solid rgba(28,29,34,0.06);
border-radius: 13px;
display: flex;
align-items: center;
padding-left: 8px;
cursor: pointer;
user-select: none;
.button-icon{
width: 8px;
height: 8px;
background-image: url('/public/ailist/algorithm_add_row_icon.png');
margin-right: 4px;
}
.button-span{
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 12px;
color: #0D68CB;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
}
}
}
.label-interval{
height: 1px;
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
background:#DBDBDB;
opacity: 0.66;
margin-left: -8px;
margin-right: -10px;
}
.label-table-title{
height: 30px;
display: flex;
margin-bottom: 4px;
.table-title-item{
display: flex;
width: 66px;
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 12px;
color: #222738;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
}
}
.label-table-content{
height: 75px;
overflow: auto;
scrollbar-width: none;
::-webkit-scrollbar {
width: 0;
height: 0;
}
.table-row{
width: 100%;
height: 26px;
display: flex;
margin-bottom: 1px;
.table-item{
width: 65px;
height: 26px;
background: #FFFFFF;
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15), 0px 8px 6px 0px rgba(28,29,34,0.06);
border-radius: 2px 0px 0px 2px;
margin-right: 1px;
display: flex;
align-items: center;
// padding-left: 9px;
.table-item-input{
height: 26px;
border: 0px;
}
.table-item-input:focus{
box-shadow: none
}
.del-table-row{
width: 14px;
height: 14px;
background-image: url('/public/ailist/del_table_row.png');
cursor: pointer;
}
}
}
}
}
.item-key{
height: 88px;
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border-radius: 2px;
border: 1px solid #CCCCCC;
}
}
}
.footer{
height: 85px;
padding-right: 34px;
display: flex;
align-items: center;
justify-content: end;
.cancel-button{
width: 101px;
height: 40px;
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border-radius: 4px;
border: 1px solid #979797;
font-family: PingFangSC-Medium;
font-weight: 500;
font-size: 16px;
color: #222738;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
margin-right: 14px;
}
.delete-button{
width: 146px;
height: 40px;
background: #ed6f6f;
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border-radius: 4px;
font-family: PingFangSC-Medium;
font-weight: 500;
font-size: 16px;
color: #FFFFFF;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
margin-right: 14px;
}
.save-button{
width: 146px;
height: 40px;
background: #0D68CB;
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
border-radius: 4px;
font-family: PingFangSC-Medium;
font-weight: 500;
font-size: 16px;
color: #FFFFFF;
line-height: 33px;
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
}
}
</style>