Files
sweet-hut-ui/src/components/Journal/JournalCard.vue

175 lines
4.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="journal-note card-item">
<div class="journal-head" @click="editClick">
<div class="head-left">
<span class="time">
{{ formatDate(props.item.date, 'HH:mm') }}
</span>
<span v-if="props.item?.location" class="location">
<i class="fa-solid fa-location-dot"></i>
{{ props.item.location }}
</span>
<el-tag v-if="props.item?.category" type="primary">
{{ props.item.category }}
</el-tag>
<span v-if="props.item?.mood" class="emoji">
{{ props.item.mood }}
</span>
</div>
<svgIcon v-if="props.item?.weather" :name="`weather-${props.item?.weather}`"/>
</div>
<!-- 内容区域 -->
<div class="journal-body">
<!-- 可折叠文本 -->
<div
ref="textContent"
class="text-content"
:class="{ 'collapsed': !expanded }"
@click="toggleExpand">
{{ props.item.content }}
</div>
<!-- 单媒体内容图片优先于视频 -->
<el-image
v-if="props.item?.imageUrl"
:src="`${props.item?.imageUrl}${ThumbImageQuery}`"
fit="contain" @click="viewImageClick"
class="media-content"/>
<video
v-if="props.item?.videoUrl"
controls
class="media-content">
<source :src="props.item?.videoUrl" type="video/mp4">
</video>
<!-- 展开/收起按钮 -->
<el-button
v-if="showToggle"
text class="toggle-btn"
@click.stop="toggleExpand">
<el-icon>
<ArrowUp v-if="expanded" />
<ArrowDown v-else />
</el-icon>
{{ expanded ? '收起内容' : `展开全文(${overflowLines}行)` }}
</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, PropType, defineProps } from 'vue'
import { ElTag, ElButton, ElImage } from 'element-plus'
import { SvgIcon } from 'vue3-common'
import { ArrowUp, ArrowDown } from '@element-plus/icons-vue'
import { IJournal } from '@/types/journal.ts'
import { formatDate } from 'vue3-common/utils/dateUtil'
import { useJournalStore } from '@/store/journal.ts'
import { useAppStore } from '@/store/app.ts'
import { useRouter } from 'vue-router'
import { RawImageQuery, ThumbImageQuery } from '@/utils'
import { showImagePreview } from 'vant'
const props = defineProps({
item: {
required: true,
type: Object as PropType<IJournal>
}
})
const journalStore = useJournalStore()
const appStore = useAppStore()
const router = useRouter()
onMounted(() => {
if (overflowLines.value <= 0) expanded.value = true
})
// 文本展开逻辑
const expanded = ref(false)
const textContent = ref<HTMLElement>()
const maxLines = 3
const overflowLines = computed(() => {
if (!textContent.value) return 0
const lineHeight = parseInt(getComputedStyle(textContent.value).lineHeight, 10)
return Math.round((textContent.value.scrollHeight - textContent.value.clientHeight) / lineHeight)
})
const showToggle = computed(() => overflowLines.value > 0)
const toggleExpand = () => expanded.value = !expanded.value
const viewImageClick = () => {
showImagePreview({ images: [props.item?.imageUrl + RawImageQuery], closeable: true })
}
const editClick = async () => {
const id = props.item?.id
journalStore.journalApiType = 'UPDATE'
journalStore.currentJournal = props.item
appStore.isShowMobileBack = true
await router.push({ name: 'JournalDetailId', params: { id } })
}
</script>
<style lang="scss">
.journal-note {
width: 100%;
overflow: auto;
.journal-head {
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
.head-left {
display: flex;
align-items: center;
gap: 8px;
color: darkgrey;
font-size: 1rem;
}
}
.journal-body {
padding: 10px;
.text-content {
white-space: pre-line;
word-break: break-word;
line-height: 2;
cursor: pointer;
overflow: hidden;
&.collapsed {
display: -webkit-box;
-webkit-line-clamp: v-bind(maxLines);
-webkit-box-orient: vertical;
}
}
.media-content {
width: 100%;
// height: 300px;
}
.toggle-btn {
padding: 0;
color: #999;
font-size: small;
}
}
}
</style>