deotalandAi/apps/FrontendDesigner/src/components/admin/PromptCardHorizontal.vue

277 lines
5.1 KiB
Vue

<template>
<div
class="prompt-card-horizontal"
draggable="true"
@dragstart="onDragStart"
@click="handleClick"
>
<!-- 左侧图片 -->
<div v-if="prompt.imageUrls.length > 0" class="card-image">
<img :src="prompt.imageUrls[0]" />
</div>
<!-- 右侧内容 -->
<div class="card-content">
<div class="card-header">
<h4 class="card-title">{{ prompt.title }}</h4>
<el-tag :type="typeTagType" size="small">{{ getTypeLabel(prompt.type) }}</el-tag>
</div>
<div class="card-body">
<p class="card-description">{{ prompt.content }}</p>
</div>
<div class="card-footer">
<el-button
text
size="small"
@click.stop="$emit('edit', prompt)"
class="action-btn edit"
>
<el-icon><EditPen /></el-icon>
{{ t('common.edit') }}
</el-button>
<el-button
text
size="small"
@click.stop="handleDelete"
class="action-btn delete"
>
<el-icon><Delete /></el-icon>
{{ t('common.delete') }}
</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { EditPen, Delete, Check } from '@element-plus/icons-vue'
const { t } = useI18n()
// 组件属性
const props = defineProps({
prompt: {
type: Object,
required: true,
default: () => ({
id: '',
title: '',
content: '',
type: '',
referenceImage: '',
isActive: false
})
},
isActive: {
type: Boolean,
default: false
}
})
// 事件定义
const emit = defineEmits(['edit', 'delete', 'drag-start', 'click'])
// 根据类型获取标签类型
const typeTagType = computed(() => {
const typeMap = {
animal: 'success',
person: 'warning',
general: 'info'
}
return typeMap[props.prompt.type] || 'info'
})
// 获取类型标签
const getTypeLabel = (type) => {
const typeMap = {
animal: t('admin.promptManagement.animal'),
person: t('admin.promptManagement.person'),
general: t('admin.promptManagement.general')
}
return typeMap[type] || type
}
// 拖拽开始事件
const onDragStart = (event) => {
event.dataTransfer.effectAllowed = 'move'
emit('drag-start', props.prompt)
}
// 点击卡片事件
const handleClick = () => {
emit('click', props.prompt)
}
// 删除提示词事件
const handleDelete = () => {
emit('delete', props.prompt.id)
}
</script>
<style scoped>
.prompt-card-horizontal {
background: white;
border: 1px solid #e5e7eb;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
overflow: hidden;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
display: flex;
min-height: 120px;
}
.prompt-card-horizontal:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
border-color: #a78bfa;
}
/* 左侧图片 */
.card-image {
width: 120px;
flex-shrink: 0;
overflow: hidden;
background: #f9fafb;
min-height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
display: block;
}
.prompt-card-horizontal:hover .card-image img {
transform: scale(1.05);
}
/* 右侧内容 */
.card-content {
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
gap: 8px;
min-width: 0;
}
/* 卡片头部 */
.card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 8px;
}
.card-title {
font-size: 16px;
font-weight: 600;
color: #374151;
margin: 0;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
/* 卡片内容 */
.card-body {
flex: 1;
overflow: hidden;
min-height: 0;
}
.card-description {
font-size: 14px;
color: #6b7280;
margin: 0;
line-height: 1.5;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
/* 卡片底部 */
.card-footer {
display: flex;
gap: 8px;
justify-content: flex-end;
margin-top: auto;
}
.action-btn {
padding: 0;
font-size: 14px;
transition: color 0.2s ease;
}
.action-btn.edit:hover {
color: #6b7280;
}
.action-btn.delete:hover {
color: #ef4444;
}
/* 生效标识 */
.active-badge {
position: absolute;
top: 8px;
right: 8px;
background: #10b981;
color: white;
font-size: 12px;
padding: 4px 8px;
border-radius: 12px;
display: flex;
align-items: center;
gap: 4px;
font-weight: 500;
z-index: 1;
}
.active-badge .el-icon {
font-size: 10px;
}
/* 无图片的卡片 */
.prompt-card-horizontal:not(:has(.card-image)) {
min-height: 100px;
}
.prompt-card-horizontal:not(:has(.card-image)) .card-content {
padding: 16px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.prompt-card-horizontal {
flex-direction: column;
}
.card-image {
width: 100%;
height: 120px;
}
.card-header {
flex-direction: column;
align-items: flex-start;
gap: 4px;
}
}
</style>