892 lines
20 KiB
Vue
892 lines
20 KiB
Vue
<template>
|
||
<div :class="prefixCls">
|
||
<div class="left">
|
||
<div class="upload">
|
||
<div class="upload-title">
|
||
<div class="upload-title-left">
|
||
{{ $t('common.uploadImage') }}
|
||
</div>
|
||
<div class="upload-title-tip">
|
||
{{ $t('common.uploadImageTip') }}
|
||
</div>
|
||
</div>
|
||
<!-- 上传方式选择 -->
|
||
<div class="upload-type-select">
|
||
<a-radio-group v-model="uploadType" @change="handleUploadTypeChange">
|
||
<a-radio value="upload">{{ $t('common.uploadImage') }}</a-radio>
|
||
<a-radio value="template">{{ $t('common.selectTemplate') }}</a-radio>
|
||
</a-radio-group>
|
||
</div>
|
||
<!-- 上传图片方式 -->
|
||
<div v-if="uploadType === 'upload'" class="upload-content">
|
||
<mf-image-upload
|
||
listType="draggable"
|
||
uploadHeight="200px"
|
||
:show-file-list="false"
|
||
:content="$t('common.uploadPlaceholder')"
|
||
v-model="firstUrl" />
|
||
</div>
|
||
<!-- 选择模版方式 -->
|
||
<div v-else class="template-content">
|
||
<div v-if="selectedTemplatePreview" class="template-preview">
|
||
<a-image
|
||
:src="selectedTemplatePreview"
|
||
fit="contain"
|
||
:preview="false"
|
||
class="preview-image" />
|
||
<div class="template-preview-actions">
|
||
<a-button type="primary" @click="openTemplateDialog">
|
||
{{ $t('common.reselectTemplate') }}
|
||
</a-button>
|
||
</div>
|
||
</div>
|
||
<div v-else class="template-placeholder">
|
||
<mf-button type="primary" size="large" @click="openTemplateDialog">
|
||
{{ $t('common.selectTemplate') }}
|
||
</mf-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div
|
||
class="tags"
|
||
v-for="tag in tags">
|
||
<div class="tags-title">{{ tag.title }}</div>
|
||
<a-radio-group
|
||
:model-value="selectedTags[tag.id]"
|
||
@change="handleGroupChange(tag.id, $event)">
|
||
<a-radio
|
||
v-for="item in tag.children"
|
||
:value="item.value">
|
||
{{ item.title }}
|
||
</a-radio>
|
||
</a-radio-group>
|
||
</div>
|
||
<!-- 模型选择 -->
|
||
<div class="model-select">
|
||
<div class="model-title">{{ $t('common.selectModel') || '选择模型' }}</div>
|
||
<a-select v-model="selectedModel" style="width: 100%;">
|
||
<a-option
|
||
v-for="option in modelOptions"
|
||
:key="option.value"
|
||
:value="option.value">
|
||
{{ option.label }}
|
||
</a-option>
|
||
</a-select>
|
||
</div>
|
||
|
||
<!-- 富文本编辑器 -->
|
||
<RichTextEditor
|
||
v-model="editorContent"
|
||
:placeholder="$t('common.textPlaceholder') || '请输入文本生成图片...'"
|
||
:uploaded-images="uploadedImages"
|
||
@text-change="handleTextChange"
|
||
@image-upload="handleImageUpload"
|
||
/>
|
||
|
||
<mf-button
|
||
class="submit"
|
||
type="primary"
|
||
size="large"
|
||
:loading="generateLoading"
|
||
@click="generateImage">
|
||
{{
|
||
price
|
||
? $t('common.generateImage', { score: price })
|
||
: $t('common.generateImageNow')
|
||
}}
|
||
</mf-button>
|
||
<div class="submit-tip">
|
||
{{ $t('common.generateTip') }}
|
||
</div>
|
||
</div>
|
||
<div
|
||
class="right"
|
||
v-if="showResult">
|
||
<div class="right-close">
|
||
<mf-icon
|
||
value="icon-close"
|
||
@click="close" />
|
||
</div>
|
||
<a-image
|
||
class="result-image"
|
||
fit="contain"
|
||
:src="imageUrl" />
|
||
<div
|
||
class="action"
|
||
v-show="imageUrl">
|
||
<mf-button @click="saveImage">
|
||
<a-image
|
||
:width="20"
|
||
:height="20"
|
||
:preview="false"
|
||
src="/images/btn_bctp@2x.png" />
|
||
{{ $t('common.saveImage') }}
|
||
</mf-button>
|
||
<mf-button @click="jumpToVideo">
|
||
<a-image
|
||
:width="20"
|
||
:height="20"
|
||
:preview="false"
|
||
src="/images/btn_scsp@2x.png" />
|
||
{{ $t('common.generateVideo') }}
|
||
</mf-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 模版选择弹窗 -->
|
||
<a-modal
|
||
v-model:visible="templateDialogVisible"
|
||
:title="$t('common.selectTemplate')"
|
||
:footer="false"
|
||
width="50%"
|
||
@cancel="handleTemplateDialogClose">
|
||
<div class="template-dialog-wrapper">
|
||
<div class="template-dialog-content">
|
||
<a-spin :loading="templateLoading">
|
||
<div class="template-grid">
|
||
<div
|
||
class="template-item"
|
||
v-for="template in templateList"
|
||
:key="template.id"
|
||
:class="{ 'selected': selectedTemplate && selectedTemplate.id === template.id }"
|
||
@click="selectTemplate(template)">
|
||
<a-image
|
||
:src="getImageUrl(template.imageUrl || template.img_url)"
|
||
:preview="false"
|
||
fit="cover" />
|
||
</div>
|
||
</div>
|
||
<div v-if="templateList.length === 0" class="empty-template">
|
||
{{ $t('common.noTemplates') }}
|
||
</div>
|
||
</a-spin>
|
||
</div>
|
||
<div class="template-dialog-footer">
|
||
<a-button @click="handleTemplateDialogClose">{{ $t('common.cancel') }}</a-button>
|
||
<a-button type="primary" :disabled="!selectedTemplate" @click="handleConfirmTemplate">{{ $t('common.confirm') }}</a-button>
|
||
</div>
|
||
</div>
|
||
</a-modal>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { mapGetters } from 'vuex'
|
||
import RichTextEditor from '@/components/RichTextEditor.vue'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
prefixCls: 'image',
|
||
firstUrl: '',
|
||
text: '',
|
||
current: 1,
|
||
generateLoading: false,
|
||
imageUrl: '',
|
||
price: null,
|
||
tags: [],
|
||
selectedTags: {},
|
||
showResult: !this.$base.isMobile(),
|
||
id: null,
|
||
// 上传方式选择
|
||
uploadType: 'upload', // 'upload' 或 'template'
|
||
// 模版选择相关
|
||
templateDialogVisible: false,
|
||
templateList: [],
|
||
templateLoading: false,
|
||
selectedTemplate: null,
|
||
selectedTemplatePreview: '', // 选中的模版预览图URL
|
||
// 模型选择 - 支持 Seedance 2.0
|
||
modelOptions: [
|
||
{ label: 'Seedance 2.0', value: 'ep-20260326165811-dlkth' },
|
||
{ label: 'Seedance 2.0 Fast', value: 'ep-20260326170056-dkj9m' }
|
||
],
|
||
selectedModel: 'ep-20260326165811-dlkth',
|
||
// 已上传的图片列表(用于@功能)
|
||
uploadedImages: []
|
||
}
|
||
},
|
||
components: {
|
||
RichTextEditor
|
||
},
|
||
computed: {
|
||
...mapGetters(['lang']),
|
||
},
|
||
watch: {
|
||
$route: {
|
||
handler(from, to) {
|
||
let type = to?.query?.type || 1
|
||
this.current = type
|
||
},
|
||
deep: true,
|
||
immediate: true
|
||
},
|
||
lang() {
|
||
this.getTags()
|
||
}
|
||
},
|
||
mounted() {
|
||
let type = this.$datas.getQueryString('type', this.$route.fullPath)
|
||
if (type) {
|
||
this.current = type || 1
|
||
}
|
||
let { text } = this.$route.query || {}
|
||
if (text) {
|
||
this.text = text
|
||
}
|
||
|
||
this.$axios({
|
||
url: 'api/manager/selectInfo',
|
||
method: 'GET',
|
||
data: {
|
||
aiType: this.current == 1 ? '11' : '12'
|
||
}
|
||
}).then((res) => {
|
||
this.price = res.data?.price
|
||
this.id = res.data?.id;
|
||
this.getTags()
|
||
})
|
||
},
|
||
methods: {
|
||
handleGroupChange(id, value) {
|
||
this.selectedTags[id] = value
|
||
},
|
||
getTags(aiId) {
|
||
this.$axios({
|
||
url: 'api/tag/list',
|
||
method: 'GET',
|
||
data: {
|
||
aiId: this.id
|
||
}
|
||
}).then((res) => {
|
||
this.tags = this.$datas.recurrence(res.data)
|
||
if (!this.$datas.isEmpty(this.tags)) {
|
||
this.tags.map((item) => {
|
||
let children = item.children || []
|
||
let firstChild = children[0]
|
||
if (firstChild) {
|
||
this.selectedTags[item.id] = firstChild.id
|
||
}
|
||
})
|
||
}
|
||
})
|
||
},
|
||
// 上传方式改变
|
||
handleUploadTypeChange() {
|
||
// 切换上传方式时,清空之前的选择
|
||
if (this.uploadType === 'upload') {
|
||
this.selectedTemplatePreview = ''
|
||
this.selectedTemplate = null
|
||
this.firstUrl = ''
|
||
} else {
|
||
this.firstUrl = ''
|
||
}
|
||
},
|
||
// 打开模版选择弹窗
|
||
openTemplateDialog() {
|
||
this.templateDialogVisible = true
|
||
this.selectedTemplate = null
|
||
// 加载模板列表
|
||
this.loadTemplateList()
|
||
},
|
||
// 加载模板列表
|
||
loadTemplateList() {
|
||
this.templateLoading = true
|
||
// 根据当前功能类型传递 ai_id 参数
|
||
this.$axios({
|
||
url: 'api/template/getTemplateList',
|
||
method: 'GET',
|
||
data: {
|
||
position: 0,
|
||
aiId: 11
|
||
}
|
||
}).then(res => {
|
||
this.templateList = res.rows || []
|
||
// 如果之前已选择过模版,恢复选中状态
|
||
if (this.selectedTemplatePreview && this.templateList.length > 0) {
|
||
const prevTemplate = this.templateList.find(t =>
|
||
this.getImageUrl(t.imageUrl || t.img_url) === this.selectedTemplatePreview
|
||
)
|
||
if (prevTemplate) {
|
||
this.selectedTemplate = prevTemplate
|
||
}
|
||
}
|
||
}).catch(err => {
|
||
console.error('加载模板列表失败:', err)
|
||
this.templateList = []
|
||
}).finally(() => {
|
||
this.templateLoading = false
|
||
})
|
||
},
|
||
// 选择模板
|
||
selectTemplate(template) {
|
||
this.selectedTemplate = template
|
||
},
|
||
// 获取图片URL
|
||
getImageUrl(url) {
|
||
if (!url) return ''
|
||
if (url.startsWith('/admin')) {
|
||
return '/api' + url
|
||
} else if (url.startsWith('/api')) {
|
||
return url
|
||
} else if (url.startsWith('http://') || url.startsWith('https://')) {
|
||
return url
|
||
} else {
|
||
return '/api' + url
|
||
}
|
||
},
|
||
// 获取模板名称(根据当前语言)
|
||
getTemplateName(template) {
|
||
if (!template) return ''
|
||
// 繁体中文显示 chineseContent,其他语言显示 englishContent
|
||
if (this.lang === 'zh_HK') {
|
||
return template.chineseContent || template.name || ''
|
||
}
|
||
return template.englishContent || template.name || ''
|
||
},
|
||
// 确认选择模板
|
||
handleConfirmTemplate() {
|
||
if (this.selectedTemplate) {
|
||
const imageUrl = this.getImageUrl(this.selectedTemplate.imageUrl || this.selectedTemplate.img_url)
|
||
this.selectedTemplatePreview = imageUrl
|
||
this.firstUrl = {
|
||
url: imageUrl
|
||
}
|
||
this.templateDialogVisible = false
|
||
}
|
||
},
|
||
// 关闭模版选择弹窗
|
||
handleTemplateDialogClose() {
|
||
this.templateDialogVisible = false
|
||
// 不重置selectedTemplate,保持用户的选择状态,方便二次选择
|
||
},
|
||
// 处理富文本内容变化
|
||
handleTextChange(content) {
|
||
this.editorContent = content
|
||
// 同步到旧的 text 字段以保持兼容性
|
||
this.text = content
|
||
},
|
||
// 处理上传的图片(用于@功能)
|
||
handleImageUpload(imageInfo) {
|
||
if (imageInfo && imageInfo.url) {
|
||
this.uploadedImages.push({
|
||
url: imageInfo.url,
|
||
name: imageInfo.name || 'image'
|
||
})
|
||
}
|
||
},
|
||
close() {
|
||
this.showResult = false
|
||
},
|
||
jumpToVideo() {
|
||
this.$router.push(`/fast-video?url=${this.imageUrl}`)
|
||
},
|
||
async saveImage() {
|
||
try {
|
||
// 获取图片的 blob 数据
|
||
const response = await fetch(this.imageUrl)
|
||
const blob = await response.blob()
|
||
|
||
// 从 URL 中提取文件名,如果没有则使用默认名称
|
||
const urlParts = this.imageUrl.split('/')
|
||
const fileName = urlParts[urlParts.length - 1] || 'image.png'
|
||
|
||
// 创建下载链接
|
||
const url = window.URL.createObjectURL(blob)
|
||
const link = document.createElement('a')
|
||
link.href = url
|
||
link.download = fileName
|
||
link.style.display = 'none'
|
||
document.body.appendChild(link)
|
||
link.click()
|
||
document.body.removeChild(link)
|
||
window.URL.revokeObjectURL(url)
|
||
} catch (error) {
|
||
console.error('下载图片失败:', error)
|
||
this.$message.error(this.$t('common.downloadFailed') || '下载失败')
|
||
}
|
||
},
|
||
generateImage() {
|
||
if (!this.firstUrl || !this.firstUrl.url) {
|
||
this.$message.error(this.$t('common.uploadImageError'))
|
||
return
|
||
}
|
||
// if (!this.text && this.current == 2) {
|
||
// this.$message.error(this.$t('common.textError'))
|
||
// return
|
||
// }
|
||
let tags = []
|
||
Object.keys(this.selectedTags).map((key) => {
|
||
let tagValue = this.selectedTags[key]
|
||
let item = this.$datas.deepFind(
|
||
this.tags,
|
||
(d) => d.id == tagValue
|
||
)
|
||
let prompt = item.prompt
|
||
if (prompt) {
|
||
let arr = prompt.split(',')
|
||
const randomIndex = Math.floor(Math.random() * arr.length)
|
||
prompt = arr[randomIndex]
|
||
// tags.push(prompt)
|
||
} else {
|
||
// tags.push(item.title)
|
||
}
|
||
tags.push(item.id)
|
||
})
|
||
this.generateLoading = true
|
||
this.$axios({
|
||
url: 'api/ai/imgToImg',
|
||
method: 'POST',
|
||
data: {
|
||
text: this.editorContent || this.text,
|
||
firstUrl: this.firstUrl.url,
|
||
functionType: this.current == 1 ? '11' : '12',
|
||
tags: tags.join(','),
|
||
model: this.selectedModel // 新增模型参数
|
||
}
|
||
})
|
||
.then((res) => {
|
||
this.generateLoading = false
|
||
if (res.code == 200) {
|
||
this.imageUrl = res.msg
|
||
this.showResult = true
|
||
} else if (res.code == -1) {
|
||
this.$confirm({
|
||
title: this.$t('common.notice'),
|
||
content: this.$t('common.balenceLow'),
|
||
okText: this.$t('common.confirm'),
|
||
cancelText: this.$t('common.cancel'),
|
||
onOk: (_) => {
|
||
this.$router.push('/recharge')
|
||
}
|
||
})
|
||
} else if (res.code == -2) {
|
||
this.$modal.error({
|
||
title: this.$t('common.notice'),
|
||
content: this.$t('common.createFailed'),
|
||
okText: this.$t('common.confirm')
|
||
})
|
||
} else if (res.code == -3) {
|
||
this.$modal.error({
|
||
title: this.$t('common.notice'),
|
||
content: this.$t('common.createTagFailed'),
|
||
okText: this.$t('common.confirm')
|
||
})
|
||
}
|
||
})
|
||
.catch((_) => {
|
||
this.generateLoading = false
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.image {
|
||
display: flex;
|
||
height: 100%;
|
||
|
||
.left {
|
||
width: 400px;
|
||
padding: 20px 40px;
|
||
height: 100%;
|
||
overflow-y: auto;
|
||
flex-shrink: 0;
|
||
|
||
.submit {
|
||
width: 100%;
|
||
margin-top: 20px;
|
||
border-radius: 10px;
|
||
|
||
&-tip {
|
||
font-size: 12px;
|
||
color: #5c5d68;
|
||
margin-top: 20px;
|
||
text-align: center;
|
||
}
|
||
}
|
||
|
||
.arco-textarea-wrapper {
|
||
background: #1a1b20;
|
||
color: #fff;
|
||
height: 100px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.types {
|
||
display: flex;
|
||
padding-bottom: 20px;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||
.type {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 150px;
|
||
font-size: 14px;
|
||
color: #5c5d68;
|
||
height: 40px;
|
||
border-radius: 10px;
|
||
cursor: pointer;
|
||
|
||
&.active {
|
||
color: #ffffff;
|
||
background-color: rgb(var(--primary-6));
|
||
}
|
||
}
|
||
}
|
||
|
||
.upload {
|
||
// margin-top: 20px;
|
||
margin-bottom: 20px;
|
||
|
||
.model-select {
|
||
margin-bottom: 20px;
|
||
|
||
.model-title {
|
||
color: #fff;
|
||
margin-bottom: 8px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
:deep(.arco-select) {
|
||
background-color: #1a1b20;
|
||
border-color: rgba(255,255,255,0.1);
|
||
}
|
||
}
|
||
|
||
/* 富文本编辑器样式 */
|
||
.rich-editor-root {
|
||
margin-bottom: 20px;
|
||
|
||
.toolbar {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-bottom: 12px;
|
||
padding: 8px;
|
||
background-color: #1a1b20;
|
||
border-radius: 6px;
|
||
border: 1px solid rgba(255,255,255,0.1);
|
||
|
||
.tool-btn {
|
||
padding: 6px 12px;
|
||
background-color: rgba(255,255,255,0.05);
|
||
border: 1px solid rgba(255,255,255,0.1);
|
||
color: #fff;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 13px;
|
||
|
||
&:hover {
|
||
background-color: rgba(255,255,255,0.1);
|
||
border-color: rgba(255,255,255,0.2);
|
||
}
|
||
}
|
||
}
|
||
|
||
.rich-editor {
|
||
min-height: 160px;
|
||
padding: 16px;
|
||
background-color: #1a1b20;
|
||
border: 1px solid rgba(255,255,255,0.1);
|
||
border-radius: 6px;
|
||
color: #fff;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
outline: none;
|
||
resize: none;
|
||
|
||
&:focus {
|
||
border-color: rgb(var(--primary-6));
|
||
}
|
||
|
||
&[data-placeholder]:empty::before {
|
||
content: attr(data-placeholder);
|
||
color: #5c5d68;
|
||
pointer-events: none;
|
||
}
|
||
}
|
||
}
|
||
&-title {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 16px;
|
||
justify-content: space-between;
|
||
&-left {
|
||
font-size: 14px;
|
||
color: #ffffff;
|
||
}
|
||
|
||
&-tip {
|
||
font-size: 12px;
|
||
color: #5c5d68;
|
||
}
|
||
}
|
||
|
||
.upload-type-select {
|
||
margin-bottom: 16px;
|
||
:deep(.arco-radio-group) {
|
||
.arco-radio {
|
||
margin-right: 24px;
|
||
&-label {
|
||
font-size: 14px;
|
||
color: #5c5d68;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.template-content {
|
||
.template-preview {
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
background: #1a1b20;
|
||
|
||
.preview-image {
|
||
width: 100%;
|
||
height: 200px;
|
||
display: block;
|
||
|
||
:deep(.arco-image-img) {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: contain;
|
||
}
|
||
}
|
||
|
||
.template-preview-actions {
|
||
padding: 12px;
|
||
text-align: center;
|
||
}
|
||
}
|
||
|
||
.template-placeholder {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 200px;
|
||
border: 1px dashed rgba(255, 255, 255, 0.2);
|
||
border-radius: 8px;
|
||
background: #1a1b20;
|
||
}
|
||
}
|
||
}
|
||
|
||
.tags {
|
||
padding-top: 20px;
|
||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||
&-title {
|
||
color: #fff;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
:deep(.arco-radio-group) {
|
||
.arco-radio {
|
||
margin-bottom: 12px;
|
||
&-label {
|
||
font-size: 14px;
|
||
color: #5c5d68;
|
||
}
|
||
|
||
&:hover {
|
||
.arco-radio-icon-hover::before {
|
||
background-color: transparent;
|
||
}
|
||
}
|
||
.arco-icon-hover:hover::before {
|
||
background-color: transparent;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.right {
|
||
flex: 1;
|
||
height: 100%;
|
||
overflow: auto;
|
||
background-color: #000000;
|
||
padding: 0 100px 20px 100px;
|
||
|
||
&-close {
|
||
display: none;
|
||
}
|
||
|
||
:deep(.arco-image-error) {
|
||
background-color: transparent;
|
||
}
|
||
|
||
:deep(.result-image) {
|
||
width: 100%;
|
||
min-width: 600px;
|
||
height: calc(100% - 60px);
|
||
|
||
.arco-image-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
|
||
.action {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-top: 20px;
|
||
.mf-button {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 200px;
|
||
height: 40px;
|
||
background: #1a1b20;
|
||
border-radius: 10px;
|
||
color: #fff;
|
||
margin: 0 15px;
|
||
|
||
:deep(.arco-image) {
|
||
margin-right: 8px;
|
||
&-img {
|
||
vertical-align: unset;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 模版选择弹窗样式
|
||
.template-dialog-wrapper {
|
||
display: flex;
|
||
flex-direction: column;
|
||
max-height: 70vh;
|
||
min-height: 350px;
|
||
}
|
||
|
||
.template-dialog-content {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
min-height: 0;
|
||
|
||
.template-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 20%);
|
||
gap: 16px;
|
||
padding: 10px 0;
|
||
|
||
.template-item {
|
||
cursor: pointer;
|
||
border: 2px solid transparent;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
transition: all 0.3s;
|
||
position: relative;
|
||
|
||
&:hover {
|
||
border-color: var(--color-primary-light-1);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
&.selected {
|
||
border-color: rgb(var(--primary-6));
|
||
box-shadow: 0 0 0 2px rgba(var(--primary-6), 0.2);
|
||
}
|
||
|
||
:deep(.arco-image) {
|
||
width: 100%;
|
||
height: 300px;
|
||
display: block;
|
||
|
||
.arco-image-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
}
|
||
|
||
.template-name {
|
||
padding: 8px;
|
||
font-size: 12px;
|
||
color: var(--color-text-1);
|
||
text-align: center;
|
||
background: var(--color-fill-1);
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
}
|
||
}
|
||
|
||
.empty-template {
|
||
text-align: center;
|
||
padding: 60px 20px;
|
||
color: var(--color-text-3);
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
.template-dialog-footer {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 12px;
|
||
padding: 16px 0 0 0;
|
||
border-top: 1px solid var(--color-border-2);
|
||
flex-shrink: 0;
|
||
background: var(--color-bg-1);
|
||
}
|
||
|
||
@media (max-width: 576px) {
|
||
.image {
|
||
.left {
|
||
width: 100%;
|
||
}
|
||
|
||
.right {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 100px 40px;
|
||
background: linear-gradient(
|
||
0deg,
|
||
rgba(#050b15, 1) 0%,
|
||
rgba(#0f1011, 1) 49%,
|
||
rgba(#111215, 1) 100%
|
||
);
|
||
|
||
&-close {
|
||
right: 20px;
|
||
top: 80px;
|
||
position: fixed;
|
||
display: block;
|
||
cursor: pointer;
|
||
color: #fff;
|
||
|
||
.mf-icon {
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
|
||
.result-image {
|
||
width: 100%;
|
||
min-width: auto;
|
||
}
|
||
|
||
.action {
|
||
.mf-button {
|
||
width: calc(50% - 8px);
|
||
margin: 0 10px;
|
||
background-color: rgb(var(--primary-6));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|