添加新组件
This commit is contained in:
parent
72a6e436b2
commit
ddb1c367b5
|
|
@ -26,6 +26,7 @@ declare module 'vue' {
|
|||
ImageUploader: typeof import('./src/components/dialogBox/imageUploader/index.vue')['default']
|
||||
Img: typeof import('./src/components/Img/index.vue')['default']
|
||||
Model: typeof import('./src/components/dialogBox/model/index.vue')['default']
|
||||
Popover: typeof import('./src/components/Popover/index.vue')['default']
|
||||
Proportion: typeof import('./src/components/dialogBox/proportion/index.vue')['default']
|
||||
Quantity: typeof import('./src/components/dialogBox/quantity/index.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
|
|
|||
|
|
@ -0,0 +1,213 @@
|
|||
<template>
|
||||
<div class="custom-popover" ref="popoverRef">
|
||||
<div class="popover-trigger" ref="triggerRef" @click.stop="togglePopover">
|
||||
<slot name="reference" />
|
||||
</div>
|
||||
<Teleport to="body">
|
||||
<div
|
||||
v-if="visible"
|
||||
ref="contentRef"
|
||||
class="popover-content"
|
||||
:class="[placement]"
|
||||
:style="contentStyle"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'top'
|
||||
},
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: 'auto'
|
||||
},
|
||||
trigger: {
|
||||
type: String,
|
||||
default: 'click'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const popoverRef = ref(null)
|
||||
const triggerRef = ref(null)
|
||||
const contentRef = ref(null)
|
||||
const visible = ref(props.modelValue)
|
||||
const position = ref({ top: 0, left: 0 })
|
||||
const popoverId = ref(Math.random().toString(36).substr(2, 9))
|
||||
|
||||
if (!window.__currentOpenPopoverId__) {
|
||||
window.__currentOpenPopoverId__ = null
|
||||
}
|
||||
|
||||
const contentStyle = computed(() => ({
|
||||
width: typeof props.width === 'number' ? `${props.width}px` : props.width,
|
||||
...position.value
|
||||
}))
|
||||
|
||||
const togglePopover = async () => {
|
||||
if (visible.value) {
|
||||
visible.value = false
|
||||
window.__currentOpenPopoverId__ = null
|
||||
} else {
|
||||
if (window.__currentOpenPopoverId__ && window.__currentOpenPopoverId__ !== popoverId.value) {
|
||||
window.dispatchEvent(new CustomEvent('close-other-popovers', { detail: { excludeId: popoverId.value } }))
|
||||
}
|
||||
if (window.__currentOpenSelectId__) {
|
||||
window.dispatchEvent(new CustomEvent('close-other-selects', { detail: { excludeId: null } }))
|
||||
}
|
||||
visible.value = true
|
||||
window.__currentOpenPopoverId__ = popoverId.value
|
||||
await nextTick()
|
||||
updatePosition()
|
||||
}
|
||||
emit('update:modelValue', visible.value)
|
||||
}
|
||||
|
||||
const updatePosition = () => {
|
||||
if (!triggerRef.value || !contentRef.value) return
|
||||
|
||||
const triggerRect = triggerRef.value.getBoundingClientRect()
|
||||
const contentRect = contentRef.value.getBoundingClientRect()
|
||||
const gap = 25
|
||||
|
||||
let top = 0
|
||||
let left = 0
|
||||
|
||||
switch (props.placement) {
|
||||
case 'top':
|
||||
top = triggerRect.top - contentRect.height - gap
|
||||
left = triggerRect.left + (triggerRect.width - contentRect.width) / 2
|
||||
break
|
||||
case 'bottom':
|
||||
top = triggerRect.bottom + gap
|
||||
left = triggerRect.left + (triggerRect.width - contentRect.width) / 2
|
||||
break
|
||||
case 'left':
|
||||
top = triggerRect.top + (triggerRect.height - contentRect.height) / 2
|
||||
left = triggerRect.left - contentRect.width - gap
|
||||
break
|
||||
case 'right':
|
||||
top = triggerRect.top + (triggerRect.height - contentRect.height) / 2
|
||||
left = triggerRect.right + gap
|
||||
break
|
||||
}
|
||||
|
||||
position.value = {
|
||||
top: `${top}px`,
|
||||
left: `${left}px`
|
||||
}
|
||||
}
|
||||
|
||||
const handleClickOutside = (e) => {
|
||||
if (!visible.value) return
|
||||
|
||||
const triggerEl = popoverRef.value
|
||||
const contentEl = contentRef.value
|
||||
|
||||
if (
|
||||
triggerEl &&
|
||||
!triggerEl.contains(e.target) &&
|
||||
contentEl &&
|
||||
!contentEl.contains(e.target)
|
||||
) {
|
||||
visible.value = false
|
||||
window.__currentOpenPopoverId__ = null
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCloseOtherPopovers = (e) => {
|
||||
if (e.detail.excludeId !== popoverId.value) {
|
||||
visible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleCloseOtherSelects = () => {
|
||||
visible.value = false
|
||||
window.__currentOpenPopoverId__ = null
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, async (val) => {
|
||||
visible.value = val
|
||||
if (val) {
|
||||
await nextTick()
|
||||
updatePosition()
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
window.addEventListener('resize', updatePosition)
|
||||
window.addEventListener('scroll', updatePosition, true)
|
||||
window.addEventListener('close-other-popovers', handleCloseOtherPopovers)
|
||||
window.addEventListener('close-other-selects', handleCloseOtherSelects)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', handleClickOutside)
|
||||
window.removeEventListener('resize', updatePosition)
|
||||
window.removeEventListener('scroll', updatePosition, true)
|
||||
window.removeEventListener('close-other-popovers', handleCloseOtherPopovers)
|
||||
window.removeEventListener('close-other-selects', handleCloseOtherSelects)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.custom-popover {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.popover-trigger {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.popover-content {
|
||||
position: fixed;
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08);
|
||||
border: 1px solid #e8e8e8;
|
||||
z-index: 2000;
|
||||
animation: popoverFadeIn 0.2s ease;
|
||||
}
|
||||
|
||||
.popover-content.top {
|
||||
transform-origin: bottom center;
|
||||
}
|
||||
|
||||
.popover-content.bottom {
|
||||
transform-origin: top center;
|
||||
}
|
||||
|
||||
.popover-content.left {
|
||||
transform-origin: right center;
|
||||
}
|
||||
|
||||
.popover-content.right {
|
||||
transform-origin: left center;
|
||||
}
|
||||
|
||||
@keyframes popoverFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
>
|
||||
<slot name="prefix" />
|
||||
<span class="select-text">{{ selectedOption || placeholder }}</span>
|
||||
<!-- <div v-if="props.isArrow" class="arrow-icon" :class="{ rotate: isOpen }"><i-ep-ArrowDown /></div> -->
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
|
@ -19,20 +18,45 @@
|
|||
:class="position"
|
||||
>
|
||||
<slot name="header" />
|
||||
<div
|
||||
v-for="(option, index) in options"
|
||||
:key="option.value || index"
|
||||
class="dropdown-item"
|
||||
:class="{ selected: option.value === selectedValue }"
|
||||
@click.stop="selectOption(option)"
|
||||
>
|
||||
<slot name="option" :option="option" :selected="option.value === selectedValue">
|
||||
<div class="option-content">
|
||||
<span class="option-label">{{ option.label }}</span>
|
||||
<span v-if="option.value === selectedValue" class="option-check">✓</span>
|
||||
<template v-if="groupedOptions.length > 0">
|
||||
<div
|
||||
v-for="(group, groupIndex) in groupedOptions"
|
||||
:key="groupIndex"
|
||||
class="option-group"
|
||||
>
|
||||
<div v-if="group.label" class="group-title">{{ group.label }}</div>
|
||||
<div
|
||||
v-for="(option, index) in group.options"
|
||||
:key="option.value || index"
|
||||
class="dropdown-item"
|
||||
:class="{ selected: option.value === selectedValue }"
|
||||
@click.stop="selectOption(option)"
|
||||
>
|
||||
<slot name="option" :option="option" :selected="option.value === selectedValue">
|
||||
<div class="option-content">
|
||||
<span class="option-label">{{ option.label }}</span>
|
||||
<span v-if="option.value === selectedValue" class="option-check">✓</span>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="(option, index) in options"
|
||||
:key="option.value || index"
|
||||
class="dropdown-item"
|
||||
:class="{ selected: option.value === selectedValue }"
|
||||
@click.stop="selectOption(option)"
|
||||
>
|
||||
<slot name="option" :option="option" :selected="option.value === selectedValue">
|
||||
<div class="option-content">
|
||||
<span class="option-label">{{ option.label }}</span>
|
||||
<span v-if="option.value === selectedValue" class="option-check">✓</span>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -53,6 +77,10 @@ const props = defineProps({
|
|||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
groupedOptions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
|
|
@ -96,7 +124,13 @@ const headerWidth = computed(() => {
|
|||
})
|
||||
|
||||
const selectedOption = computed(() => {
|
||||
const option = props.options.find((opt) => opt.value === selectedValue.value)
|
||||
let option = props.options.find((opt) => opt.value === selectedValue.value)
|
||||
if (!option && props.groupedOptions.length > 0) {
|
||||
for (const group of props.groupedOptions) {
|
||||
option = group.options.find((opt) => opt.value === selectedValue.value)
|
||||
if (option) break
|
||||
}
|
||||
}
|
||||
return option ? option.label : ''
|
||||
})
|
||||
|
||||
|
|
@ -108,6 +142,9 @@ const toggleDropdown = async () => {
|
|||
if (window.__currentOpenSelectId__ && window.__currentOpenSelectId__ !== selectId.value) {
|
||||
window.dispatchEvent(new CustomEvent('close-other-selects', { detail: { excludeId: selectId.value } }))
|
||||
}
|
||||
if (window.__currentOpenPopoverId__) {
|
||||
window.dispatchEvent(new CustomEvent('close-other-popovers', { detail: { excludeId: null } }))
|
||||
}
|
||||
isOpen.value = true
|
||||
window.__currentOpenSelectId__ = selectId.value
|
||||
await nextTick()
|
||||
|
|
@ -141,12 +178,19 @@ const handleCloseOtherSelects = (e) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleCloseOtherPopovers = () => {
|
||||
isOpen.value = false
|
||||
window.__currentOpenSelectId__ = null
|
||||
}
|
||||
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
window.addEventListener('close-other-selects', handleCloseOtherSelects)
|
||||
window.addEventListener('close-other-popovers', handleCloseOtherPopovers)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', handleClickOutside)
|
||||
window.removeEventListener('close-other-selects', handleCloseOtherSelects)
|
||||
window.removeEventListener('close-other-popovers', handleCloseOtherPopovers)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
@ -317,4 +361,20 @@ onBeforeUnmount(() => {
|
|||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.option-group {
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.group-title {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
padding: 5px 20px 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div v-if="localPreviewList.length < limit" class="upload-trigger" @click="triggerUpload">
|
||||
<i-ep-plus />
|
||||
<i-ep-plus color="#333333" />
|
||||
<span>参考内容</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -219,7 +219,8 @@ defineExpose({
|
|||
width: 56px;
|
||||
height: 56px;
|
||||
// border: 2px dashed #d1d5db;
|
||||
background-color: #F8F9FA;
|
||||
background: rgba(0, 15, 51, 0.04);
|
||||
backdrop-filter: blur(5px);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -231,7 +232,7 @@ defineExpose({
|
|||
transition: all 0.3s ease;
|
||||
|
||||
span {
|
||||
color: #999;
|
||||
color: #333;
|
||||
font-family: "Microsoft YaHei";
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<template>
|
||||
<Transition name="slide-up">
|
||||
<div class="input-container" :class="{ generate : !props.isGenerate }" @click="handleContainerClick">
|
||||
<div v-if="!props.isGenerate" class="title">AI绘画2026</div>
|
||||
<div v-if="!props.isGenerate && props.type === 'painting'" class="title">AI绘画2026</div>
|
||||
<div v-if="!props.isGenerate && props.type === 'video'" class="title">AI视频2026</div>
|
||||
|
||||
<div class="sender-top">
|
||||
<div v-if="useDisplay.Sender_variant === 'default'" class="scroll-to-bottom-text" @click.stop="handleScrollToBottom">回到底部<img src="@/assets/dialog/ArrowDown.svg"></div>
|
||||
|
|
@ -15,7 +16,13 @@
|
|||
|
||||
<Sender :key="useDisplay.Sender_variant" v-model="prompt" :variant="useDisplay.Sender_variant" :placeholder="promptPlaceholder" :submit-btn-disabled="isgerenate.value" :auto-size="autoSizeConfig">
|
||||
<template #prefix>
|
||||
<div v-show="useDisplay.Sender_variant !== 'default'" class="prefix-self-wrap">
|
||||
<div v-show="useDisplay.Sender_variant !== 'default' && props.type === 'painting'" class="prefix-self-wrap">
|
||||
<Model v-model="model" v-model:typeValue="type" />
|
||||
<Proportion v-model="proportion" v-model:resolution="resolution" />
|
||||
<Quantity v-model="quantity" />
|
||||
</div>
|
||||
|
||||
<div v-show="useDisplay.Sender_variant !== 'default' && props.type === 'video'" class="prefix-self-wrap">
|
||||
<Model v-model="model" v-model:typeValue="type" />
|
||||
<Proportion v-model="proportion" v-model:resolution="resolution" />
|
||||
<Quantity v-model="quantity" />
|
||||
|
|
@ -58,6 +65,10 @@ const props = defineProps({
|
|||
generate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'painting'
|
||||
}
|
||||
})
|
||||
const router = useRouter()
|
||||
|
|
@ -249,6 +260,10 @@ watch(() => type.value, (newValue) => {
|
|||
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
:deep(.el-popover.el-popper){
|
||||
border-radius: 20px;
|
||||
|
||||
}
|
||||
// 时间选择器
|
||||
.select{
|
||||
background: #ffffff;
|
||||
|
|
|
|||
|
|
@ -1,55 +1,19 @@
|
|||
<template>
|
||||
<el-popover trigger="click" placement="top" :width="180">
|
||||
<div class="select">
|
||||
<div class="model-group">
|
||||
<div class="group-title">生成模型</div>
|
||||
<div
|
||||
v-for="item in generateModels"
|
||||
:key="item.value"
|
||||
class="model-item"
|
||||
:class="{ active: model === item.value }"
|
||||
@click="selectModel(item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="model-group">
|
||||
<div class="group-title">编辑模型</div>
|
||||
<div
|
||||
v-for="item in editModels"
|
||||
:key="item.value"
|
||||
class="model-item"
|
||||
:class="{ active: model === item.value }"
|
||||
@click="selectModel(item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="model-group">
|
||||
<div class="group-title">视觉理解模型</div>
|
||||
<div
|
||||
v-for="item in visionModels"
|
||||
:key="item.value"
|
||||
class="model-item"
|
||||
:class="{ active: model === item.value }"
|
||||
@click="selectModel(item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #reference>
|
||||
<div class="choice-btn">
|
||||
<img src="@/assets/dialog/model.svg" alt="" style="width: 16px;">
|
||||
<span>{{ getModelLabel(model) }}</span>
|
||||
</div>
|
||||
<Select
|
||||
v-model="model"
|
||||
:grouped-options="modelGroups"
|
||||
class="model-select"
|
||||
position="top"
|
||||
>
|
||||
<template #prefix>
|
||||
<img src="@/assets/dialog/model.svg" alt="" style="width: 16px;">
|
||||
</template>
|
||||
</el-popover>
|
||||
</Select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Select from '@/components/Select/index.vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
|
|
@ -90,9 +54,20 @@ const visionModels = [
|
|||
{ value: 'Qwen3.5plus', label: 'Qwen3.5plus' }
|
||||
]
|
||||
|
||||
const selectModel = (value) => {
|
||||
model.value = value
|
||||
}
|
||||
const modelGroups = [
|
||||
{
|
||||
label: '生成模型',
|
||||
options: generateModels
|
||||
},
|
||||
{
|
||||
label: '编辑模型',
|
||||
options: editModels
|
||||
},
|
||||
{
|
||||
label: '视觉理解模型',
|
||||
options: visionModels
|
||||
}
|
||||
]
|
||||
|
||||
const getModelType = (value) => {
|
||||
if (generateModels.find(m => m.value === value)) {
|
||||
|
|
@ -106,74 +81,39 @@ const getModelType = (value) => {
|
|||
}
|
||||
return 'text'
|
||||
}
|
||||
|
||||
const getModelLabel = (value) => {
|
||||
const allModels = [...generateModels, ...editModels, ...visionModels]
|
||||
const model = allModels.find(item => item.value === value)
|
||||
return model ? model.label : value
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.choice-btn{
|
||||
display: flex;
|
||||
height: 40px;
|
||||
padding: 0 15px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.10);
|
||||
background: #ffffff;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.choice-btn:hover{
|
||||
background: #E5E7EB;
|
||||
}
|
||||
.model-select {
|
||||
:deep(.select-header) {
|
||||
height: 40px;
|
||||
padding: 0 15px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.10);
|
||||
background: #ffffff;
|
||||
|
||||
.select{
|
||||
padding: 10px;
|
||||
max-height: 510px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
&:hover {
|
||||
background: #E5E7EB;
|
||||
}
|
||||
}
|
||||
|
||||
.model-group{
|
||||
margin-bottom: 15px;
|
||||
:deep(.select-text) {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:last-child{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
:deep(.dropdown-menu) {
|
||||
max-height: 510px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.group-title{
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
:deep(.dropdown-item) {
|
||||
min-width: 120px;
|
||||
|
||||
.model-item{
|
||||
padding: 8px 10px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:last-child{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&:hover{
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
&.active{
|
||||
background: #e6f7ff;
|
||||
color: #1890ff;
|
||||
font-weight: 500;
|
||||
}
|
||||
&.active {
|
||||
background: rgba(0, 15, 51, 0.10);
|
||||
color: #000F33;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<el-popover trigger="click" placement="top" :width="400">
|
||||
<Popover placement="top" :width="400">
|
||||
<div class="proportion-container">
|
||||
<div class="section">
|
||||
<h3>选择比例</h3>
|
||||
|
|
@ -53,11 +53,12 @@
|
|||
<span>{{ proportion }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-popover>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import Popover from '@/components/Popover/index.vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
<template>
|
||||
<el-popover trigger="click" placement="top" :width="330">
|
||||
<div class="quantity-container">
|
||||
<div v-for="item in 4" :key="item" class="quantity-item" :class="{'selected': item == quantity}" @click="selectQuantity(item)">{{ item }}张</div>
|
||||
</div>
|
||||
<template #reference>
|
||||
<div class="choice-btn">
|
||||
<img src="@/assets/dialog/quantity.svg" alt="" style="width: 16px;">
|
||||
<span>{{ quantity }} 张</span>
|
||||
</div>
|
||||
<Select
|
||||
v-model="quantity"
|
||||
:options="quantityOptions"
|
||||
class="quantity-select"
|
||||
position="top"
|
||||
>
|
||||
<template #prefix>
|
||||
<img src="@/assets/dialog/quantity.svg" alt="" style="width: 16px;">
|
||||
</template>
|
||||
</el-popover>
|
||||
</Select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import Select from '@/components/Select/index.vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
|
|
@ -29,50 +28,39 @@ const quantity = computed({
|
|||
set: (value) => emit('update:modelValue', value)
|
||||
})
|
||||
|
||||
const selectQuantity = (value) => {
|
||||
quantity.value = value
|
||||
}
|
||||
const quantityOptions = [
|
||||
{ value: 1, label: '1 张' },
|
||||
{ value: 2, label: '2 张' },
|
||||
{ value: 3, label: '3 张' },
|
||||
{ value: 4, label: '4 张' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.choice-btn{
|
||||
display: flex;
|
||||
height: 40px;
|
||||
padding: 0 15px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.10);
|
||||
background: #ffffff;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.choice-btn:hover{
|
||||
background: #E5E7EB;
|
||||
}
|
||||
.quantity-container{
|
||||
display: flex;
|
||||
padding: 5px;
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
border-radius: 10px;
|
||||
background: #F8F9FA;
|
||||
}
|
||||
.quantity-item{
|
||||
display: flex;
|
||||
width: 80px;
|
||||
height: 32px;
|
||||
padding: 0 10px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.quantity-item.selected{
|
||||
background: #fff;
|
||||
}
|
||||
.quantity-item:hover{
|
||||
background: #E5E7EB;
|
||||
.quantity-select {
|
||||
:deep(.select-header) {
|
||||
height: 40px;
|
||||
padding: 0 15px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.10);
|
||||
background: #ffffff;
|
||||
|
||||
&:hover {
|
||||
background: #E5E7EB;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.select-text) {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(.dropdown-menu) {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
:deep(.dropdown-item) {
|
||||
min-width: 80px;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -7,13 +7,14 @@ const route = useRoute()
|
|||
const shouldShowDisplay = route.path === '/home'
|
||||
const loading = route.query.loading ? false : (route.path === '/home')
|
||||
const Generate = route.query.Generate || false
|
||||
const type = route.query.type || 'painting'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<dialogBox :is-generate="shouldShowDisplay" :generate="Generate" />
|
||||
<dialogBox :is-generate="shouldShowDisplay" :type="type" :generate="Generate" />
|
||||
|
||||
<display :if="shouldShowDisplay" :loading="loading" />
|
||||
<display :if="shouldShowDisplay" :type="type" :loading="loading" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue