AI算法画面
|
After Width: | Height: | Size: 307 B |
|
After Width: | Height: | Size: 186 B |
|
After Width: | Height: | Size: 859 B |
|
After Width: | Height: | Size: 347 B |
|
After Width: | Height: | Size: 410 B |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 802 B |
|
After Width: | Height: | Size: 968 B |
|
|
@ -0,0 +1,486 @@
|
|||
<template>
|
||||
<div class="title-div">
|
||||
<div class="title-span-div">
|
||||
<div class="title-icon"></div>
|
||||
<div class="title-span">创建算法</div>
|
||||
</div>
|
||||
<div class="close-button" @click="emits('changeAddModal',false)"></div>
|
||||
</div>
|
||||
<div class="interval"></div>
|
||||
<div class="modal-content">
|
||||
<div class="left-content">
|
||||
<div class="item-title">模型名称</div>
|
||||
<a-input class="name-input" v-model:value="modelName" placeholder="请输入相关名称" />
|
||||
<div class="item-title">模型描述</div>
|
||||
<a-textarea class="item-desc" v-model:value="modelDescription" placeholder="请输入相关描述" :rows="4" />
|
||||
<div class="item-title">模型封面</div>
|
||||
<div class="item-image">
|
||||
<div 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="modelType" :options="modelTypeOptions"></a-segmented>
|
||||
<template v-if="modelType == '0'">
|
||||
<div class="item-title">模型规模</div>
|
||||
<a-segmented class="item-type" v-model:value="modelScale" :options="modelScaleOptions"></a-segmented>
|
||||
<div class="item-title">模型文件</div>
|
||||
<a-upload
|
||||
v-model:file-list="modelFile"
|
||||
accept=".zip"
|
||||
:maxCount="1"
|
||||
:custom-request="customRequest"
|
||||
>
|
||||
<a-button class="select-model-file-button" type="primary" :icon="h(PlusOutlined)">选择模型文件</a-button>
|
||||
<!-- <template #itemRender="{ file, actions }">
|
||||
<a-space>
|
||||
<span>{{ file.name }}</span>
|
||||
</a-space>
|
||||
</template> -->
|
||||
</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 modelLabelList" :key="index">
|
||||
<div class="table-item">
|
||||
<a-input class="table-item-input" v-model:value="item.test"/>
|
||||
</div>
|
||||
<div class="table-item">
|
||||
<a-input class="table-item-input" />
|
||||
</div>
|
||||
<div class="table-item">
|
||||
<a-input class="table-item-input" />
|
||||
</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="modelPushAddress" placeholder="请输入地址" />
|
||||
<div class="item-title">拉流地址</div>
|
||||
<a-input class="name-input" v-model:value="modelPullAddress" placeholder="请输入地址" />
|
||||
<div class="item-title">服务地址</div>
|
||||
<a-input class="name-input" v-model:value="modelServeAddress" placeholder="请输入地址" />
|
||||
<div class="item-title">密钥</div>
|
||||
<a-textarea class="item-key" v-model:value="modelKey" 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 class="save-button" type="primary">确定</a-button>
|
||||
</div>
|
||||
<a-modal v-model:open="selectImageModal" title="选择封面" width="1000px" :footer="null" :destroyOnClose="true">
|
||||
<SelectImageModal @changeSelectImageModal="changeSelectImageModal"/>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, h, defineEmits, defineProps } from "vue"
|
||||
import { uploadFile } from '@/api/formrender/index';
|
||||
import { PlusOutlined, } from '@ant-design/icons-vue';
|
||||
import SelectImageModal from "./SelectImageModal.vue";
|
||||
const props = defineProps([''])
|
||||
const emits = defineEmits(['changeAddModal'])
|
||||
const modelName = ref('')
|
||||
const modelDescription = ref('')
|
||||
const modelType = ref('0')
|
||||
const modelScale = ref('N')
|
||||
const modelPullAddress = ref('')
|
||||
const modelPushAddress = ref('')
|
||||
const modelServeAddress = ref('')
|
||||
const modelKey = ref('')
|
||||
const modelFile = ref([])
|
||||
const modelFilePath = ref()
|
||||
const modelLabelList = ref([])
|
||||
const selectImageModal = 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) => {
|
||||
const formData = new FormData()
|
||||
formData.append('files', file.file)
|
||||
uploadFile(formData).then(res => {
|
||||
modelFilePath.value = res[0].filePath
|
||||
// emits('update:shppath',res[0].filePath)
|
||||
})
|
||||
}
|
||||
const addLabelRow = () => {
|
||||
// TODO
|
||||
modelLabelList.value.push({
|
||||
test:''
|
||||
})
|
||||
}
|
||||
const delLabelRow = (index) => {
|
||||
modelLabelList.value.splice(index,1)
|
||||
}
|
||||
const changeSelectImageModal = (type: boolean) => {
|
||||
selectImageModal.value = type
|
||||
}
|
||||
</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);
|
||||
.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;
|
||||
}
|
||||
.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>
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
<template>
|
||||
<div class="cropper-tool">
|
||||
<div class="container">
|
||||
<div class="left">
|
||||
<div style="padding-left: 20px;">
|
||||
<a-upload :fileList="[]" accept="image/*" :beforeUpload="onFileChange">
|
||||
<a-button size="small" type="primary">选择图片</a-button>
|
||||
</a-upload>
|
||||
</div>
|
||||
<div style="margin-top:8px">
|
||||
<img style="width: 640px;height: 266px;" ref="sourceImg" crossorigin="anonymous" />
|
||||
</div>
|
||||
<div class="controls">
|
||||
<button @click="zoomIn">放大</button>
|
||||
<button @click="zoomOut">缩小</button>
|
||||
<button @click="rotateLeft">左旋</button>
|
||||
<button @click="rotateRight">右旋</button>
|
||||
<button @click="flipHorizontal">水平翻转</button>
|
||||
<button @click="flipVertical">垂直翻转</button>
|
||||
<button @click="reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div style="margin-bottom:10px">裁切预览(固定 300×200)</div>
|
||||
<div class="preview" ref="previewBox" style="width:300px;height:200px;">
|
||||
<span v-if="!croppedUrl">(无)</span>
|
||||
<img v-if="croppedUrl" :src="croppedUrl" alt="预览" />
|
||||
</div>
|
||||
<div style="margin-top:8px; display:flex; gap:8px;">
|
||||
<a v-if="croppedUrl" :href="croppedUrl" download="cropped.png">下载裁切图</a>
|
||||
<button @click="clear">清空</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<a-button style="margin-right: 15px;" @click="emits('changeSelectImageModal',false)">取消</a-button>
|
||||
<a-button type="primary" @click="submitImage">确定</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineEmits } from 'vue';
|
||||
import Cropper from 'cropperjs';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
import { dataURLtoBlob } from '@/utils/file/base64Conver';
|
||||
import { uploadFile } from '@/api/formrender/index';
|
||||
const emits = defineEmits(['changeSelectImageModal'])
|
||||
const sourceImg = ref(null);
|
||||
const cropper = ref(null);
|
||||
const flipH = ref(1);
|
||||
const flipV = ref(1);
|
||||
const zoomValue = ref(1);
|
||||
const croppedUrl = ref('');
|
||||
|
||||
const onFileChange = (e) => {
|
||||
console.log(e)
|
||||
const file = e
|
||||
if (!file) return;
|
||||
const url = URL.createObjectURL(file);
|
||||
sourceImg.value.src = url;
|
||||
sourceImg.value.onload = () => {
|
||||
if (cropper.value) {
|
||||
cropper.value.destroy();
|
||||
}
|
||||
cropper.value = new Cropper(sourceImg.value, {
|
||||
viewMode: 1,
|
||||
aspectRatio: 3 / 2, // 固定比例 300:200
|
||||
autoCropArea: 1,
|
||||
movable: true,
|
||||
zoomable: true,
|
||||
rotatable: true,
|
||||
scalable: true,
|
||||
responsive: true,
|
||||
background: true,
|
||||
cropBoxResizable: false,
|
||||
cropBoxMovable: false,
|
||||
dragMode: 'move',
|
||||
ready() {
|
||||
zoomValue.value = 1;
|
||||
flipH.value = 1;
|
||||
flipV.value = 1;
|
||||
croppedUrl.value = '';
|
||||
getCropped()
|
||||
},
|
||||
crop() {
|
||||
getCropped()
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const zoomIn = () => cropper.value?.zoom(0.1);
|
||||
const zoomOut = () => cropper.value?.zoom(-0.1);
|
||||
const rotateLeft = () => cropper.value?.rotate(-90);
|
||||
const rotateRight = () => cropper.value?.rotate(90);
|
||||
const flipHorizontal = () => {
|
||||
flipH.value = -flipH.value;
|
||||
cropper.value?.scaleX(flipH.value);
|
||||
};
|
||||
const flipVertical = () => {
|
||||
flipV.value = -flipV.value;
|
||||
cropper.value?.scaleY(flipV.value);
|
||||
};
|
||||
const reset = () => {
|
||||
cropper.value?.reset();
|
||||
zoomValue.value = 1;
|
||||
flipH.value = 1;
|
||||
flipV.value = 1;
|
||||
};
|
||||
|
||||
const getCropped = () => {
|
||||
const canvas = cropper.value.getCroppedCanvas({ width: 300, height: 200 });
|
||||
if (!canvas) return;
|
||||
croppedUrl.value = canvas.toDataURL('image/png');
|
||||
console.log('croppedUrl.value',croppedUrl.value)
|
||||
};
|
||||
|
||||
const clear = () => {
|
||||
if (cropper.value) {
|
||||
cropper.value.destroy();
|
||||
cropper.value = null;
|
||||
}
|
||||
sourceImg.value.src = '';
|
||||
croppedUrl.value = '';
|
||||
};
|
||||
const submitImage = (format='image/jpeg', quality = 0.9) => {
|
||||
// const blob = dataURLtoBlob(croppedUrl.value);
|
||||
// const formData = new FormData();
|
||||
// formData.append('files', blob);
|
||||
// uploadFile(formData).then(res => {
|
||||
// console.log(res)
|
||||
// })
|
||||
if (!cropper.value) return;
|
||||
cropper.value.getCroppedCanvas({ width: 300, height: 200 })
|
||||
.toBlob(async (blob) => {
|
||||
if (!blob) return;
|
||||
|
||||
// 用 FormData 上传
|
||||
const formData = new FormData();
|
||||
formData.append('files', blob, `cropped.jpeg`);
|
||||
|
||||
uploadFile(formData).then(res => {
|
||||
console.log(res)
|
||||
})
|
||||
}, format, quality);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container { display: flex; gap: 20px; }
|
||||
.left { width: 640px; }
|
||||
.right { width: 320px; }
|
||||
img { max-width: 100%; display: block; max-height: 480px; background: #f3f3f3; }
|
||||
.controls { margin-top: 10px; display:flex; flex-wrap:wrap; gap:8px; }
|
||||
.preview { border:1px solid #ddd; display:flex; align-items:center; justify-content:center; overflow:hidden; background:#fafafa }
|
||||
.footer{
|
||||
margin-top: 12px;
|
||||
height: 53px;
|
||||
border-top: 1px solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
padding-right: 40px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,136 +1,403 @@
|
|||
<template>
|
||||
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
|
||||
<div class="w-1/4 xl:w-1/5 leftbox flex column">
|
||||
<div class="flex ai-c jc-sb">
|
||||
<div class="textbox">
|
||||
<p>算法库</p>
|
||||
<span>行业生态算法厂商</span>
|
||||
<div class="w-1/4 xl:w-1/5 leftbox">
|
||||
<div class="left-title-div">
|
||||
<div class="span-div">
|
||||
<div class="span-title">算法库</div>
|
||||
<div class="span-subtitle">行业生态算法厂商</div>
|
||||
</div>
|
||||
<a-button type="primary" size="small" @click="createAddClick">
|
||||
<template #icon><PlusOutlined /></template>
|
||||
创建
|
||||
</a-button>
|
||||
<a-button class="add-algorithm" type="primary" :icon="h(PlusOutlined)" @click="changeAddModal(true)">创建</a-button>
|
||||
</div>
|
||||
<div class="flex ai-c jc-c column flex-1">
|
||||
<div class="descbox">
|
||||
<p>请先创建自定义算法,基于算法新增实例<br />了解更多:<BookOutlined :style="{fontSize: '14px', color: '#0A99EB'}" /> 说明书</p>
|
||||
<div class="left-interval"></div>
|
||||
<div class="show-algorithm-list-div">
|
||||
<div class="empty-list">
|
||||
<div class="empty-image"></div>
|
||||
<div class="empty-span-title">暂无数据</div>
|
||||
<div class="empty-span-subtitle">请先创建自定义算法,基于算法新增实例</div>
|
||||
<div style="display: flex;align-items: center;margin-bottom: 28px;">
|
||||
<div class="empty-span-subtitle" style="display: inline;">了解更多:</div>
|
||||
<div class="empty-icon-image"></div>
|
||||
<div class="empty-span-subtitle" style="display: inline;">说明书 </div>
|
||||
</div>
|
||||
<a-button type="primary" @click="createAddClick">
|
||||
<template #icon><PlusOutlined /></template>
|
||||
创建自定义算法
|
||||
</a-button>
|
||||
<a-button class="empty-add-algorithm" type="primary" :icon="h(PlusOutlined)" @click="changeAddModal(true)">创建自定义算法</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<BasicTable
|
||||
class="w-3/4 xl:w-4/5"
|
||||
@register="registerTable"
|
||||
@fetch-success="onFetchSuccess"
|
||||
:searchInfo="searchInfo"
|
||||
</div>
|
||||
<div class="w-3/4 xl:w-4/5 right-out-div">
|
||||
<div class="search-div">
|
||||
<div class="search-span-icon"></div>
|
||||
<div class="search-span">算法库</div>
|
||||
<div class="search-input-div">
|
||||
<a-input-search
|
||||
class="search-input"
|
||||
v-model:value="searchValue"
|
||||
placeholder="按照实例搜索"
|
||||
enter-button="搜索"
|
||||
@search="onSearch"
|
||||
>
|
||||
|
||||
</BasicTable>
|
||||
<Modal
|
||||
@submitsuccess="submitsuccess"
|
||||
@register="registerModal"
|
||||
@submit-reload="submitReload"
|
||||
<template #prefix>
|
||||
<div class="search-input-icon"></div>
|
||||
</template>
|
||||
</a-input-search>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-interval">
|
||||
<div class="interval-icon"></div>
|
||||
</div>
|
||||
<div class="show-list-div">
|
||||
<div class="list-div">
|
||||
<div class="item" v-for="value in 8">
|
||||
<div class="image-div">
|
||||
<img class="image-item" src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">
|
||||
<div class="image-span">
|
||||
<div class="image-span-icon"></div>
|
||||
<div class="image-span-info">#排水沟盖板缺</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-div">
|
||||
<div class="info-icon"></div>
|
||||
<div class="info-span-div">
|
||||
<div class="info-span-title">高速排水沟盖板缺失检测算法</div>
|
||||
<div class="info-span-subtitle">识别高速公路两侧的排水沟盖板缺……</div>
|
||||
</div>
|
||||
<a-button class="show-info-button" type="primary">查看</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination-div">
|
||||
<a-pagination
|
||||
size="small"
|
||||
:total="50"
|
||||
show-size-changer
|
||||
show-quick-jumper
|
||||
:show-total="total => `共 ${total} 条数据`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-modal width="631px" v-model:open="addAlgorithmModal" :footer="null" :closable="false" :destroyOnClose="true" :maskClosable="false" :keyboard="false">
|
||||
<AddAlgorithmModal @changeAddModal="changeAddModal"/>
|
||||
</a-modal>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, nextTick, ref } from 'vue';
|
||||
import { PlusOutlined, BookOutlined } from '@ant-design/icons-vue';
|
||||
import { BasicTable, useTable } from '@/components/Table';
|
||||
import { getButtonList, getMenuDetail, deleteButton } from '@/api/demo/system';
|
||||
import { ref,h } from 'vue';
|
||||
import { PlusOutlined, } from '@ant-design/icons-vue';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import { columns, searchFormSchema } from './index.data';
|
||||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
import Modal from './modal.vue';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import AddAlgorithmModal from './AddAlgorithmModal.vue';
|
||||
|
||||
const { createConfirm, createMessage } = useMessage();
|
||||
defineOptions({ name: 'MenuManagement' });
|
||||
const searchInfo = reactive<Recordable>({});
|
||||
|
||||
const [registerTable, { reload, expandAll, getSelectRows, clearSelectedRowKeys }] = useTable({
|
||||
title: '算法列表',
|
||||
// api: getButtonList,
|
||||
columns,
|
||||
rowKey: 'id',
|
||||
formConfig: {
|
||||
labelWidth: 120,
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
isTreeTable: true,
|
||||
striped: false,
|
||||
useSearchForm: true,
|
||||
showTableSetting: true,
|
||||
bordered: true,
|
||||
showIndexColumn: false,
|
||||
rowSelection: {
|
||||
//多选框
|
||||
// type: 'checkbox',
|
||||
type: 'radio',
|
||||
},
|
||||
handleSearchInfoFn(info) {
|
||||
return info;
|
||||
},
|
||||
});
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
function createAddClick(){
|
||||
openModal(true, {
|
||||
|
||||
});
|
||||
const searchValue = ref('');
|
||||
const addAlgorithmModal = ref(false)
|
||||
const onSearch = () => {
|
||||
}
|
||||
const changeAddModal = (type: boolean) => {
|
||||
addAlgorithmModal.value = type
|
||||
}
|
||||
|
||||
function onFetchSuccess() {
|
||||
// 演示默认展开所有表项
|
||||
nextTick(expandAll);
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.flex{
|
||||
display: flex;
|
||||
}
|
||||
.flex-1{
|
||||
flex: 1;
|
||||
}
|
||||
.column{
|
||||
flex-direction: column;
|
||||
}
|
||||
.ai-c{
|
||||
align-items: center;
|
||||
}
|
||||
.jc-sb{
|
||||
justify-content: space-between;
|
||||
}
|
||||
.jc-c{
|
||||
justify-content: center;
|
||||
}
|
||||
<style lang="scss" scoped>
|
||||
.leftbox{
|
||||
background: #fff;
|
||||
margin: 16px 0 16px 16px;
|
||||
padding: 16px;
|
||||
.textbox{
|
||||
p{
|
||||
.left-title-div{
|
||||
width: 100%;
|
||||
height: 82px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 16px;
|
||||
padding-right: 33px;
|
||||
justify-content: space-between;
|
||||
.span-div{
|
||||
width: 104px;
|
||||
height: 42px;
|
||||
.span-title{
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #060606;
|
||||
line-height: 22px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
span{
|
||||
.span-subtitle{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
color: #393939;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
.descbox{
|
||||
.add-algorithm{
|
||||
width: 80px;
|
||||
height: 30px;
|
||||
background: #0B60BD;
|
||||
border-radius: 0px;
|
||||
}
|
||||
}
|
||||
.left-interval{
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border: 1px solid rgba(28,29,34,0.08);
|
||||
opacity: 0.46;
|
||||
}
|
||||
.show-algorithm-list-div{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100% - 84px );
|
||||
.empty-list{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 280px;
|
||||
height: 311px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 5px 18px 32px 0px rgba(0,0,0,0.1);
|
||||
border: 2px dashed rgba(28,29,34,0.08);
|
||||
border-radius: 10px;
|
||||
padding-top: 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.empty-image{
|
||||
width: 114px;
|
||||
height: 120px;
|
||||
background-image: url('/public/ailist/empty_image.png');
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.empty-span-title{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
color: #000000;
|
||||
line-height: 18px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.empty-span-subtitle{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
color: #393939;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
.empty-icon-image{
|
||||
width: 16px;
|
||||
height: 14px;
|
||||
background-image: url('/public/ailist/empty_icon_image.png');
|
||||
line-height: 18px;
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
}
|
||||
.empty-add-algorithm{
|
||||
width: 167px;
|
||||
height: 30px;
|
||||
background: #0D68CB;
|
||||
border-radius: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.right-out-div{
|
||||
padding: 16px 16px 16px 33px;
|
||||
.search-div{
|
||||
position: relative;
|
||||
height: 57px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.search-span-icon{
|
||||
width: 20px;
|
||||
height: 18px;
|
||||
background-image: url('/public/ailist/search_span_icon.png');
|
||||
margin-right: 10px;
|
||||
}
|
||||
.search-span{
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #060606;
|
||||
line-height: 22px;
|
||||
}
|
||||
.search-input-div{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
width: 304px;
|
||||
height: 38px;
|
||||
.search-input{
|
||||
:deep(.ant-input-affix-wrapper){
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
height: 38px;
|
||||
border-top-left-radius: 19px;
|
||||
border-bottom-left-radius: 19px;
|
||||
}
|
||||
:deep(.ant-input-search-button,){
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #FFFFFF;
|
||||
line-height: 28px;
|
||||
height: 38px;
|
||||
border-top-right-radius: 19px;
|
||||
border-bottom-right-radius: 19px;
|
||||
}
|
||||
:deep(.ant-input){
|
||||
padding-left: 20px;
|
||||
}
|
||||
.search-input-icon{
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-image: url('/public/ailist/search_input_icon.png');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-interval{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background:rgba(28,29,34,0.08);
|
||||
margin-bottom: 22px;
|
||||
.interval-icon{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 137px;
|
||||
height: 2px;
|
||||
background: #0B60BD;
|
||||
}
|
||||
}
|
||||
.show-list-div{
|
||||
width: 100%;
|
||||
height: calc( 100% - 81px );
|
||||
background: #FFFFFF;
|
||||
border: 2px dashed rgba(28,29,34,0.08);
|
||||
border-radius: 10px;
|
||||
padding: 32px;
|
||||
.list-div{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 90px;
|
||||
.item{
|
||||
width: 300px;
|
||||
height: 268px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 5px 18px 32px 0px rgba(28,29,34,0.1);
|
||||
border-radius: 10px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 20px;
|
||||
.image-div{
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
margin-bottom: 12px;
|
||||
.image-item{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
.image-span{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
width: 205px;
|
||||
height: 20px;
|
||||
background: linear-gradient( 270deg, rgba(7,7,7,0) 0%, #111111 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 9px;
|
||||
.image-span-icon{
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: #FFA048;
|
||||
border-radius: 50%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.image-span-info{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
color: #FFFFFF;
|
||||
line-height: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.info-div{
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 7px;
|
||||
.info-icon{
|
||||
width: 3px;
|
||||
height: 34px;
|
||||
background: #0B60BD;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.info-span-div{
|
||||
width: 187px;
|
||||
margin-right: 22px;
|
||||
.info-span-title{
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: #1C1D22;
|
||||
line-height: 20px;
|
||||
margin-bottom: 5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.info-span-subtitle{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
color: rgba(28,29,34,0.5);
|
||||
line-height: 15px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.show-info-button{
|
||||
width: 54px;
|
||||
height: 23px;
|
||||
border-radius: 12px;
|
||||
background: #0B60BD;
|
||||
:deep(span){
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
color: #FFFFFF;
|
||||
line-height: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.item:nth-child(4n){
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-div{
|
||||
padding-right: 32px;
|
||||
width: 100%;
|
||||
height: 66px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
}
|
||||
}
|
||||
.right-box{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,184 +0,0 @@
|
|||
<template>
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
@register="registerModal"
|
||||
:canFullscreen="false"
|
||||
:defaultFullscreen="false"
|
||||
:showCancelBtn="true"
|
||||
:showOkBtn="true"
|
||||
:draggable="false"
|
||||
title="创建算法"
|
||||
@ok="submitClick"
|
||||
>
|
||||
<div class="flex titlesbox">
|
||||
<div class="li" v-for="(item,index) in tabList">
|
||||
<span :class="index==tabIndex?'active':''" @click="tabsClick(index)">{{item}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 视频算法 -->
|
||||
<div class="formsbox" v-if="tabIndex == 0">
|
||||
<a-form
|
||||
:model="formState"
|
||||
ref="formRef"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 18 }"
|
||||
autocomplete="off"
|
||||
>
|
||||
<a-form-item
|
||||
label="算法名称"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="概要描述"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-textarea v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="算力名称"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="推流地址"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="拉流地址"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="服务地址"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="秘钥"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<!-- 图片算法 -->
|
||||
<div class="formsbox" v-if="tabIndex == 1">
|
||||
<a-form
|
||||
:model="formState"
|
||||
ref="formRef"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 18 }"
|
||||
autocomplete="off"
|
||||
>
|
||||
<a-form-item
|
||||
label="算法名称"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="概要描述"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-textarea v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="算力名称"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="服务地址"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="秘钥"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, defineEmits, reactive, toRaw } from 'vue';
|
||||
import { BasicModal, useModalInner } from '@/components/Modal';
|
||||
const tabIndex = ref(0);
|
||||
const tabList = ["视频算法","图片算法"];
|
||||
const tabsClick = (index) =>{
|
||||
tabIndex.value = index
|
||||
}
|
||||
const formRef = ref();
|
||||
interface FormState {
|
||||
username: string;
|
||||
password: string;
|
||||
remember: boolean;
|
||||
}
|
||||
|
||||
const formState = reactive<FormState>({
|
||||
username: '',
|
||||
password: '',
|
||||
remember: true,
|
||||
});
|
||||
const submitClick = ()=>{
|
||||
console.log('submit')
|
||||
formRef.value.validate().then(() => {
|
||||
console.log('values', formState, toRaw(formState));
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('error', error);
|
||||
});
|
||||
}
|
||||
const [registerModal, { closeModal }] = useModalInner((data: any) => {
|
||||
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.titlesbox{
|
||||
width: 92%;
|
||||
margin-left: 4%;
|
||||
line-height: 40px;
|
||||
border-bottom: 1px solid #F5F6FA;
|
||||
.li{
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
span{
|
||||
color: #222738;
|
||||
cursor: pointer;
|
||||
line-height: 40px;
|
||||
display: inline-block;
|
||||
}
|
||||
.active{
|
||||
border-bottom: 3px solid #3A57E8;
|
||||
}
|
||||
}
|
||||
}
|
||||
.formsbox{
|
||||
width: 92%;
|
||||
margin-left: 4%;
|
||||
padding-top: 20px;
|
||||
}
|
||||
</style>
|
||||