This commit is contained in:
2026-06-13 07:47:49 +08:00
parent 11bd086685
commit ddc90e4b0d
11 changed files with 562 additions and 456 deletions
+57 -1
View File
@@ -49,6 +49,20 @@
<div class="compose-body">
<n-input v-model:value="composeText" type="textarea" :rows="4"
placeholder="分享你的想法..." maxlength="1000" show-count />
<!-- 图片选择 -->
<div class="image-upload-area">
<div class="image-previews">
<div v-for="(img, i) in composeImages" :key="i" class="image-preview-item">
<img :src="img" />
<span class="remove-img" @click="composeImages.splice(i, 1)"></span>
</div>
<div v-if="composeImages.length < 9" class="add-image-btn" @click="triggerMomentImage">
<span>+</span>
<span style="font-size:11px">图片</span>
</div>
</div>
<input ref="momentImageInput" type="file" accept="image/*" multiple style="display:none" @change="handleMomentImages" />
</div>
<div class="compose-options">
<div class="visibility-select">
<span class="option-label">可见范围</span>
@@ -73,6 +87,7 @@
import { ref, onMounted } from 'vue'
import { useMomentsStore } from '@/stores/moments'
import { useMessage } from 'naive-ui'
import api from '@/api/client'
import MomentCard from './MomentCard.vue'
const momentsStore = useMomentsStore()
@@ -82,18 +97,41 @@ const showCompose = ref(false)
const composeText = ref('')
const composeVisibility = ref('friends')
const publishing = ref(false)
const composeImages = ref<string[]>([])
const momentImageInput = ref<HTMLInputElement>()
onMounted(() => {
momentsStore.fetchFeed(true)
})
function triggerMomentImage() {
momentImageInput.value?.click()
}
async function handleMomentImages(event: Event) {
const target = event.target as HTMLInputElement
const files = target.files
if (!files) return
for (let i = 0; i < files.length && composeImages.value.length < 9; i++) {
try {
const formData = new FormData()
formData.append('file', files[i])
const { data } = await api.post('/uploads/file', formData, { headers: { 'Content-Type': 'multipart/form-data' } })
composeImages.value.push(data.url)
} catch {}
}
target.value = ''
}
async function publishMoment() {
if (!composeText.value.trim()) return
publishing.value = true
try {
await momentsStore.createMoment(composeText.value.trim(), undefined, composeVisibility.value)
const images = composeImages.value.length > 0 ? composeImages.value : undefined
await momentsStore.createMoment(composeText.value.trim(), images, composeVisibility.value)
message.success('动态发布成功')
composeText.value = ''
composeImages.value = []
showCompose.value = false
} catch {
message.error('发布失败')
@@ -159,6 +197,24 @@ async function handleComment(momentId: string, content: string) {
.close-btn:hover { color: var(--color-text-primary); }
.compose-body { padding: 16px 24px; }
.compose-options { margin-top: 12px; }
/* 图片上传 */
.image-upload-area { margin-top: 10px; }
.image-previews { display: flex; gap: 8px; flex-wrap: wrap; }
.image-preview-item { width: 64px; height: 64px; position: relative; border-radius: 8px; overflow: hidden; }
.image-preview-item img { width: 100%; height: 100%; object-fit: cover; }
.remove-img {
position: absolute; top: 2px; right: 2px; width: 18px; height: 18px;
background: rgba(0,0,0,0.5); color: white; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 10px; cursor: pointer;
}
.add-image-btn {
width: 64px; height: 64px; border: 2px dashed var(--color-border); border-radius: 8px;
display: flex; flex-direction: column; align-items: center; justify-content: center;
cursor: pointer; color: var(--color-text-hint); font-size: 24px; transition: border-color 0.2s;
}
.add-image-btn:hover { border-color: var(--color-primary-lighter); color: var(--color-primary); }
.visibility-select { display: flex; align-items: center; gap: 8px; }
.option-label { font-size: 13px; color: var(--color-text-secondary); }
.compose-footer {