mcwl-pc/app/components/publishModel/EditVersion.vue

349 lines
11 KiB
Vue
Raw Blame History

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.

<script setup lang="ts">
import type { FormInst } from 'naive-ui'
import { commonApi } from '@/api/common'
import { uploadImagesInBatches } from '@/utils/uploadImg.ts'
import { Asterisk, Trash } from 'lucide-vue-next'
import { computed, onMounted, ref, watch } from 'vue'
// 可接受的文件类型
const props = defineProps({
modelValue: {
type: Object,
required: true,
},
})
const emit = defineEmits(['update:modelValue', 'createModelsNext'])
const acceptTypes = '.safetensors,.ckpt,.pt,.bin,.pth,.zip,.json,.flow,.lightflow,.yaml,.yml,.onnx,.gguf,.sft'
const modelVersionItem = {
versionName: '', // 版本名称
modelId: null, // 基础模型
versionDescription: '"<p>这是一个描述</p><p><img src=\"https://img1.baidu.com/it/u=3001150338,397170470&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422\" /></p><p>这是两张图片之间的一些文字说明</p><p><img src=\"https://img12.iqilu.com/10339/clue/202405/29/68ec17f5-9621-461f-ad22-a6820a3f9cf5.jpg\" /></p>"', // 版本描述
filePath: '', // 文件路径
fileName: '', // 文档里没有 ,表里没有
sampleImagePaths: 'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', // 第三部的图片路径最多20张,切割
triggerWords: '', // 触发词
isPublic: 1, // 权限是否公开权限 1公开 2自见
isFree: 0, // 是否免费 0免费 1会员
isOnlineUse: 1, // 是否允许在线使用
allowDownloadImage: 1, // 允许下载生图
allowSoftwareUse: 1, // 允许在软件旗下使用
allowFusion: 1, // 是否允许融合
allowCommercialUse: 1, // 是否允许商用
// allowUsage: 1, // 是否允许使用
// 允许模型转售或者融合手出售字段没找到?
isExclusiveModel: 0, // 是否为独家模型这个字段
}
const isPublicList = [
{
label: '公开',
value: 1,
},
{
label: '仅自己可见',
value: 2,
},
]
defineExpose({
addVersion,
})
const localForm = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
},
})
watch(
() => localForm.value,
(newVal) => {
console.log('newVal', newVal)
emit('update:modelValue', newVal)
},
{ immediate: true, deep: true },
)
const formRef = ref<FormInst | null>(null)
const rules = {
versionName: {
required: true,
message: '',
trigger: 'blur',
},
modelId: {
required: true,
message: '',
trigger: 'blur',
},
triggerWords: {
required: true,
message: '请输入模型名称',
trigger: 'blur',
},
}
function addVersion() {
localForm.value.modelVersionList.unshift(modelVersionItem)
}
const originalBtnList = ref([
{
label: '免费',
value: 0,
},
{
label: '会员下载',
value: 1,
},
])
function handleIsFree(index: number, value: number) {
localForm.value.modelVersionList[index].isFree = value
}
const model_category = ref([])
function nextStep() {
formRef.value?.validate((errors) => {
if (!errors) {
emit('createModelsNext')
}
else {
console.log('error', errors)
}
})
}
// 上传文件
const uploadFileIndex = ref(0)
const fileInput = ref<HTMLInputElement | null>(null)
function triggerFileInput(index: number) {
(fileInput.value as HTMLInputElement)?.click()
uploadFileIndex.value = index
}
async function handleFileChange(event: Event) {
const target = event.target as HTMLInputElement
const files = target.files
if (files && files.length > 0) {
const res = await uploadImagesInBatches(files)
localForm.value.modelVersionList[uploadFileIndex.value].filePath = res[0].url
localForm.value.modelVersionList[uploadFileIndex.value].fileName = res[0].fileName
}
target.value = ''
}
</script>
<template>
<div>
<div v-for="(item, index) in localForm.modelVersionList" :key="index" class="bg-gray-100 p-4 rounded-lg">
<n-form
ref="formRef"
:label-width="80"
:model="localForm"
:rules="rules"
size="large"
>
<n-form-item label="版本名称" path="versionName">
<n-input v-model:value="item.versionName" placeholder="请输入版本名" />
</n-form-item>
<n-form-item label="基础模型" path="modelId">
<n-select
v-model:value="item.modelId"
label-field="dictLabel"
value-field="dictValue"
placeholder="请选择基础模型"
:options="model_category"
/>
</n-form-item>
<div class="flex">
上传文件 <Asterisk :size="10" color="#ff0000" class="mt-1" />
</div>
<div v-if="item.fileName" class="flex justify-between items-center bg-white p-3 mt-2 rounded-lg">
<div class="bg-[#d8e5fd] text-[12px] text-[#3162ff] w-16 h-7 rounded-lg flex justify-center items-center">
100%
</div>
<div class="flex-1 flex items-center line-clamp">
{{
item.fileName
}}
</div>
<div>
<Trash class="cursor-pointer" @click="item.fileName = '', item.filePath = ''" />
</div>
</div>
<div v-else>
<div class="upload-content">
<div class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white">
<div class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center" @click="triggerFileInput(index)">
上传文件
</div>
<div class="my-3">
点击上传文件
</div>
<div class="text-[#999999] text-xs">
.safetensors/.ckpt/.pt/.bin/.pth/.zip/.json/.flow/.lightflow/.yaml/.yml/.onnx/.gguf/.sft
</div>
</div>
</div>
</div>
<div class="flex mt-6">
版本介绍 <Asterisk :size="10" color="#ff0000" class="mt-1" />
</div>
<div class="bg-white p-3 mt-2 rounded-lg">
<client-only>
<WangEditor v-model="item.versionDesc" />
</client-only>
</div>
<div v-html="item.versionDesc" />
<div class="mt-6">
触发词
</div>
<div class="-mb-5 text-gray-400 text-[12px]">
请输入您用来训练的单词
</div>
<n-form-item path="triggerWords">
<n-input v-model:value="item.triggerWords" placeholder="例如: 1boy" />
</n-form-item>
<div class="">
权限设置
</div>
<div class="mt-1 mb-2 text-gray-400 text-[12px]">
可见范围
</div>
<div>
<n-radio-group v-model:value="item.isPublic" name="radiogroup">
<n-space>
<n-radio v-for="(isPublicItem, isPublicIndex) in isPublicList" :key="isPublicIndex" :value="isPublicItem.value">
{{ isPublicItem.label }}
</n-radio>
</n-space>
</n-radio-group>
</div>
</n-form>
<div v-if="item.isPublic === 1">
<div class="mt-4 mb-1 text-gray-400 text-[12px]">
付费设置
</div>
<div class="flex justify-center items-center bg-white h-10 rounded-lg">
<div
v-for="(subItem, subIndex) in originalBtnList"
:key="subIndex"
:style="{
backgroundColor:
item.isFree === subItem.value
? 'rgba(49, 98, 255, 0.1)'
: '#fff',
color: item.isFree === subItem.value ? '#3162ff' : '#000',
}" class="flex-1 rounded-lg h-full flex items-center justify-center cursor-pointer" @click="handleIsFree(index, subItem.value)"
>
{{ subItem.label }}
</div>
</div>
<div class="mt-1 mb-2 text-gray-500 text-[12px]">
选择会员专属或会员下载视为您已经阅读 <span class="text-[#3162ff] cursor-pointer underline">《会员模型许可协议》</span> 并同意其中条款
</div>
<div v-if="item.isFree === 1" class="text-[12px]">
<div>会员下载模型</div>
<div class="text-gray-500">
下载模型需购买会员,在线生图对所有人开放,无生图次数限制;会员下载的模型版本生成图片默认可商用。
</div>
</div>
</div>
<div class="text-gray-400 text-[12px] my-4">
许可范围
</div>
<div class="flex flex-wrap">
<div class="w-[50%] mb-2">
<n-checkbox
v-model:checked="item.isOnlineUse"
:checked-value="1"
:unchecked-value="0" label="允许在魔创未来在线使用"
/>
</div>
<div class="w-[50%] mb-2">
<n-checkbox
v-model:checked="item.allowDownloadImage"
:checked-value="1"
:unchecked-value="0" label="允许下载生图"
/>
</div>
<div class="w-[50%] mb-2">
<n-checkbox
v-model:checked="item.allowSoftwareUse"
:checked-value="1"
:unchecked-value="0" label="允许在魔创未来旗下其他产品在线使用"
/>
</div>
<div class="w-[50%] mb-2">
<n-checkbox
v-model:checked="item.allowFusion"
:checked-value="1"
:unchecked-value="0" label="允许进行融合"
/>
</div>
</div>
<div class="text-gray-400 text-[12px] my-4">
商用许可范围
</div>
<div class="flex flex-wrap">
<div class="w-[50%] mb-2">
<n-checkbox
v-model:checked="item.allowCommercialUse"
:checked-value="1"
:unchecked-value="0" label="生成图片可出售或用于商业目的"
/>
</div>
<div class="w-[50%] mb-2">
<n-checkbox
v-model:checked="item.allowDownloadImage"
:checked-value="1"
:unchecked-value="0" label="允许模型转售或融合后出售"
/>
</div>
</div>
<div class="mb-4">
<div class="text-gray-400 text-[12px] my-4">
独家设置
</div>
<div class="flex items-center mb-2">
<n-checkbox
v-model:checked="item.isExclusiveModel"
:checked-value="1"
:unchecked-value="0"
/>
<div class="ml-3 text-[12px] text-gray-500">
此版本为魔创未来独家模型 *获取更多流量:独家模型规则
</div>
</div>
</div>
</div>
<div class="flex items-center justify-center mt-5">
<div class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer" @click="nextStep">
上一步
</div>
<div class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="nextStep">
</div>
</div>
</div>
<input
ref="fileInput"
type="file"
class="hidden"
:accept="acceptTypes"
@change="handleFileChange"
>
</template>
<style lang="scss" scoped>
.line-clamp {
margin: 0 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
color: rgb(72, 71, 71);
}
</style>