214 lines
7.8 KiB
Vue
214 lines
7.8 KiB
Vue
<script setup lang="ts">
|
|
import image1 from '~/assets/example/1.jpg';
|
|
import image2 from '~/assets/example/2.jpg';
|
|
import image3 from '~/assets/example/3.jpg';
|
|
import OptionBlock from "~/components/aigc/drawing/OptionBlock.vue";
|
|
import ResultBlock from "~/components/aigc/drawing/ResultBlock.vue";
|
|
import {useLoginState} from "~/composables/useLoginState";
|
|
import ModalAuthentication from "~/components/ModalAuthentication.vue";
|
|
import {type InferType, number, object, string} from "yup";
|
|
import type {FormSubmitEvent} from "#ui/types";
|
|
import RatioSelector from "~/components/aigc/RatioSelector.vue";
|
|
|
|
useHead({
|
|
title: '绘画 | XSH AI'
|
|
})
|
|
|
|
const modal = useModal()
|
|
const loginState = useLoginState()
|
|
|
|
const leftSection = ref<HTMLElement | null>(null)
|
|
const leftHandler = ref<HTMLElement | null>(null)
|
|
|
|
const handle_stick_mousedown = (e: MouseEvent, min: number = 240, max: number = 400) => {
|
|
const handler = leftHandler.value
|
|
if (handler) {
|
|
const startX = e.clientX
|
|
const startWidth = handler.parentElement?.offsetWidth || 0
|
|
const handle_mousemove = (e: MouseEvent) => {
|
|
let newWidth = startWidth + e.clientX - startX
|
|
if (newWidth < min || newWidth > max) {
|
|
newWidth = Math.min(Math.max(newWidth, min), max)
|
|
}
|
|
handler.parentElement!.style.width = `${newWidth}px`
|
|
}
|
|
const handle_mouseup = () => {
|
|
leftSection.value?.classList.add('transition-all')
|
|
leftHandler.value?.lastElementChild?.classList.remove('bg-indigo-300', 'dark:bg-indigo-700', 'w-[3px]')
|
|
window.removeEventListener('mousemove', handle_mousemove)
|
|
window.removeEventListener('mouseup', handle_mouseup)
|
|
}
|
|
leftSection.value?.classList.remove('transition-all')
|
|
leftHandler.value?.lastElementChild?.classList.add('bg-indigo-300', 'dark:bg-indigo-700', 'w-[3px]')
|
|
window.addEventListener('mousemove', handle_mousemove)
|
|
window.addEventListener('mouseup', handle_mouseup)
|
|
}
|
|
}
|
|
|
|
const defaultRatios = [
|
|
{
|
|
ratio: '4:3',
|
|
label: '横向',
|
|
value: '1024:768',
|
|
},
|
|
{
|
|
ratio: '3:4',
|
|
label: '竖向',
|
|
value: '768:1024',
|
|
},
|
|
{
|
|
ratio: '16:9',
|
|
label: '横向',
|
|
value: '1920:1080',
|
|
},
|
|
{
|
|
ratio: '9:16',
|
|
label: '竖向',
|
|
value: '1080:1920',
|
|
},
|
|
{
|
|
ratio: '1:1',
|
|
label: '方形',
|
|
value: '1024:1024',
|
|
},
|
|
{
|
|
ratio: '3:2',
|
|
label: '横向',
|
|
value: '960:640',
|
|
},
|
|
{
|
|
ratio: '2:3',
|
|
label: '竖向',
|
|
value: '640:960',
|
|
},
|
|
{
|
|
ratio: '16:10',
|
|
label: '横向',
|
|
value: '1920:1200',
|
|
},
|
|
{
|
|
ratio: '10:16',
|
|
label: '竖向',
|
|
value: '1200:1920',
|
|
},
|
|
{
|
|
ratio: '21:9',
|
|
label: '横向',
|
|
value: '2560:1080',
|
|
},
|
|
{
|
|
ratio: '9:21',
|
|
label: '竖向',
|
|
value: '1080:2560',
|
|
},
|
|
]
|
|
|
|
const defaultFormSchema = object({
|
|
prompts: string().required('请输入提示词'),
|
|
negative_prompts: string().required('请输入负面提示词'),
|
|
resolution: string().required('请选择分辨率'),
|
|
style: number().required('请选择风格')
|
|
})
|
|
|
|
type DefaultFormSchema = InferType<typeof defaultFormSchema>
|
|
|
|
const defaultFormState = reactive({
|
|
prompts: '',
|
|
negative_prompts: '',
|
|
resolution: '1024:768',
|
|
style: 100
|
|
})
|
|
|
|
const onDefaultFormSubmit = (event: FormSubmitEvent<DefaultFormSchema>) => {
|
|
console.log(event)
|
|
}
|
|
|
|
const images = [
|
|
image1,
|
|
image2,
|
|
image3,
|
|
'https://w.wallhaven.cc/full/jx/wallhaven-jxl31y.png',
|
|
'https://w.wallhaven.cc/full/6d/wallhaven-6d7xmx.jpg',
|
|
]
|
|
</script>
|
|
|
|
<template>
|
|
<div class="w-full flex">
|
|
<div ref="leftSection"
|
|
class="sticky hidden md:block h-[calc(100vh-4rem)] overflow-hidden bg-neutral-200 dark:bg-neutral-800 transition-all"
|
|
style="width: 320px">
|
|
<div ref="leftHandler"
|
|
class="absolute inset-0 left-auto hidden xl:flex flex-col justify-center items-center cursor-ew-resize px-1 group"
|
|
@dblclick="leftSection?.style.setProperty('width', '320px')"
|
|
@mousedown.prevent="handle_stick_mousedown">
|
|
<span
|
|
class="w-[1px] h-full bg-neutral-300 dark:bg-neutral-700 group-hover:bg-indigo-300 dark:group-hover:bg-indigo-700 group-hover:w-[3px] transition-all group-hover:delay-500 translate-x-1"></span>
|
|
</div>
|
|
<div class="h-full flex flex-col overflow-y-auto">
|
|
<UForm :schema="defaultFormSchema" :state="defaultFormState" @submit="onDefaultFormSubmit">
|
|
<div class="flex flex-col gap-2 p-4 pb-28">
|
|
<OptionBlock comment="Prompts" icon="i-tabler-article" label="提示词">
|
|
<template #actions>
|
|
<!-- <UBadge color="sky" size="xs">按钮A</UBadge>-->
|
|
<!-- <UBadge color="indigo" size="xs">按钮B</UBadge>-->
|
|
</template>
|
|
<UFormGroup name="prompts">
|
|
<UTextarea v-model="defaultFormState.prompts" :rows="2" autoresize
|
|
placeholder="请输入英文提示词,每个提示词之间用英文逗号隔开" resize/>
|
|
</UFormGroup>
|
|
</OptionBlock>
|
|
<OptionBlock comment="Negative Prompts" icon="i-tabler-article-off" label="负面提示词">
|
|
<UFormGroup name="negative_prompts">
|
|
<UTextarea v-model="defaultFormState.negative_prompts" :rows="2" autoresize
|
|
placeholder="请输入作品中不要出现的提示词,每个提示词之间用英文逗号隔开"
|
|
resize/>
|
|
</UFormGroup>
|
|
</OptionBlock>
|
|
<OptionBlock icon="i-tabler-article-off" label="图片比例">
|
|
<UFormGroup name="resolution">
|
|
<RatioSelector v-model="defaultFormState.resolution" :ratios="defaultRatios" />
|
|
</UFormGroup>
|
|
</OptionBlock>
|
|
</div>
|
|
<div class="absolute bottom-0 inset-x-0 flex flex-col items-center gap-2
|
|
bg-neutral-200 dark:bg-neutral-800 p-4 border-t border-neutral-400
|
|
dark:border-neutral-700">
|
|
<UButton type="submit" color="indigo" size="lg" class="font-bold" block>生成</UButton>
|
|
<p class="text-xs text-neutral-400 dark:text-neutral-500 font-bold">
|
|
生成即代表您同意<a href="https://baidu.com" target="_blank"
|
|
class="underline underline-offset-2">用户许可协议</a>
|
|
</p>
|
|
</div>
|
|
</UForm>
|
|
</div>
|
|
</div>
|
|
<div class="flex-1 h-screen flex flex-col gap-4 bg-neutral-100 dark:bg-neutral-900 p-4 pb-20 overflow-y-auto">
|
|
<div v-if="!loginState.is_logged_in"
|
|
class="w-full h-full flex flex-col justify-center items-center gap-2 bg-neutral-100 dark:bg-neutral-900">
|
|
<Icon name="i-tabler-user-circle" class="text-7xl text-neutral-300 dark:text-neutral-700"/>
|
|
<p class="text-sm text-neutral-500 dark:text-neutral-400">请登录后使用</p>
|
|
<UButton class="mt-2 font-bold" @click="modal.open(ModalAuthentication)" color="black" variant="solid"
|
|
size="xs">登录
|
|
</UButton>
|
|
</div>
|
|
<ResultBlock v-else :images="images" v-for="i in 1" :key="i"
|
|
title="XX大模型 · 文生图" :meta="{
|
|
id: 'd166429411dfc6722e54c032cdba97a2',
|
|
aspect: '9:16',
|
|
cost: '1500',
|
|
modal: '混元大模型',
|
|
ratio: '16:9',
|
|
datetime: 1709106270
|
|
}"
|
|
prompt="这是, 一组, 测试用的, 提示词, 很长, 很长很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长, 很长">
|
|
<template #header-right>
|
|
<UButton color="gray" size="xs" icon="i-tabler-trash" variant="ghost"></UButton>
|
|
</template>
|
|
</ResultBlock>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
|
|
</style> |