add journal-detail-panel

This commit is contained in:
Timi
2025-12-10 16:45:29 +08:00
parent a5fb1d752b
commit 1e54782600
12 changed files with 496 additions and 527 deletions

View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-popup": "tdesign-miniprogram/popup/popup"
}
}

View File

@ -0,0 +1,160 @@
/* components/journal-detail-panel/index.less */
.detail-panel {
width: 100%;
height: 70vh;
display: flex;
background: var(--theme-bg-card);
border-radius: 16rpx 16rpx 0 0;
flex-direction: column;
.detail-content {
flex: 1;
display: flex;
overflow: hidden;
flex-direction: column;
.header {
display: flex;
padding: 32rpx 32rpx 0 32rpx;
flex-shrink: 0;
margin-bottom: 24rpx;
align-items: flex-start;
justify-content: space-between;
.info {
flex: 1;
display: flex;
flex-direction: column;
.title {
color: #333;
display: flex;
font-size: 32rpx;
font-weight: 600;
align-items: center;
margin-bottom: 8rpx;
.icon {
width: 32rpx;
height: 32rpx;
margin-right: 8rpx;
}
}
}
.actions {
gap: 16rpx;
display: flex;
flex-shrink: 0;
align-items: center;
.indicator {
color: var(--theme-wx);
padding: 4rpx 12rpx;
font-size: 24rpx;
font-weight: 600;
border-radius: 12rpx;
background: var(--theme-bg-journal);
}
}
}
.journals-swiper {
flex: 1;
height: 100%;
.swiper-item-wrapper {
height: 100%;
.journal-item {
height: 100%;
display: flex;
flex-direction: column;
.journal-header {
gap: 16rpx;
display: flex;
padding: 0 32rpx;
flex-wrap: wrap;
flex-shrink: 0;
margin-bottom: 16rpx;
align-items: baseline;
.location {
color: #666;
flex-basis: 100%;
font-size: 24rpx;
}
.date {
flex: 1;
color: #333;
font-size: 28rpx;
font-weight: 600;
}
.time {
color: #999;
font-size: 24rpx;
}
}
.idea {
color: #333;
display: block;
padding: 0 32rpx;
font-size: 28rpx;
line-height: 1.6;
flex-shrink: 0;
margin-bottom: 16rpx;
}
.items-scroll {
flex: 1;
height: 100%;
.items {
padding: 0 32rpx 128rpx 32rpx;
.wrapper {
column-gap: 8rpx;
column-count: 3;
padding-bottom: 128rpx;
.item {
overflow: hidden;
background: var(--theme-bg-card);
break-inside: avoid;
margin-bottom: 8rpx;
&.thumbnail {
width: 100%;
display: block;
}
&.video {
position: relative;
&::after {
content: "";
top: 50%;
left: 53%;
width: 0;
height: 0;
position: absolute;
transform: translate(-50%, -50%);
border-top: 16px solid transparent;
border-left: 24px solid var(--theme-video-play);
border-bottom: 16px solid transparent;
pointer-events: none;
}
}
}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,102 @@
// components/journal-detail-panel/index.ts
interface JournalInfo {
id: number;
date: string;
time: string;
location?: string;
idea?: string;
items: Array<{
type: number;
thumbURL: string;
sourceURL: string;
mongoId: string;
}>;
}
interface JournalDetailPanelData {
currentJournalIndex: number;
}
Component({
properties: {
// 是否显示
visible: {
type: Boolean,
value: false
},
// 标题(如 "2024 年 1 月 1 日" 或位置名称)
title: {
type: String,
value: ""
},
// 日记列表
journals: {
type: Array,
value: []
},
// 是否显示标题位置图标
showLocationIcon: {
type: Boolean,
value: false
},
// 是否显示每条日记的日期
showJournalDate: {
type: Boolean,
value: true
},
// 是否显示每条日记的位置
showJournalLocation: {
type: Boolean,
value: true
}
},
data: <JournalDetailPanelData>{
currentJournalIndex: 0,
},
observers: {
'journals, visible'(journals: JournalInfo[], visible: boolean) {
if (visible && journals && journals.length > 0) {
// 显示时重置索引和 margin
this.setData({
currentJournalIndex: 0,
});
}
}
},
methods: {
/** 关闭详情 */
closeDetail() {
this.triggerEvent('close');
},
/** swiper 切换事件 */
onSwiperChange(e: WechatMiniprogram.SwiperChange) {
this.setData({
currentJournalIndex: e.detail.current
});
},
/** 预览媒体 */
previewMedia(e: WechatMiniprogram.BaseEvent) {
const { mediaIndex } = e.currentTarget.dataset;
const journals = this.properties.journals as JournalInfo[];
if (!journals || journals.length === 0) return;
// 使用当前 swiper 的索引
const journal = journals[this.data.currentJournalIndex];
const sources = journal.items.map((item: any) => ({
url: item.sourceURL,
type: item.type === 0 ? "image" : "video"
}));
wx.previewMedia({
current: mediaIndex,
sources: sources as WechatMiniprogram.MediaSource[]
});
}
}
});

View File

@ -0,0 +1,54 @@
<!-- components/journal-detail-panel/index.wxml -->
<t-popup
class="popup"
visible="{{visible}}"
placement="bottom"
bind:visible-change="closeDetail"
>
<view class="detail-panel">
<view class="detail-content">
<view class="header">
<view class="info">
<view wx:if="{{title}}" class="title">
<image wx:if="{{showLocationIcon}}" class="icon" src="../../assets/image/location.png" />
<text>{{title}}</text>
</view>
</view>
<view class="actions">
<view wx:if="{{journals.length > 1}}" class="indicator">
{{currentJournalIndex + 1}}/{{journals.length}}
</view>
<t-icon name="close" catchtap="closeDetail" size="48rpx" />
</view>
</view>
<swiper class="journals-swiper" current="{{currentJournalIndex}}" bindchange="onSwiperChange">
<block wx:for="{{journals}}" wx:key="id">
<swiper-item class="swiper-item-wrapper">
<view class="journal-item">
<view class="journal-header">
<view wx:if="{{item.location && showJournalLocation}}" class="location">📍 {{item.location}}</view>
<view wx:if="{{showJournalDate}}" class="date">{{item.date}}</view>
</view>
<view wx:if="{{item.idea}}" class="idea">{{item.idea}}</view>
<scroll-view wx:if="{{item.items && item.items.length > 0}}" scroll-y class="items-scroll">
<view class="items">
<view class="wrapper">
<block wx:for="{{item.items}}" wx:key="mongoId" wx:for-item="media" wx:for-index="mediaIndex">
<image
class="item thumbnail {{media.type === 1 ? 'video' : 'image'}}"
src="{{media.thumbURL}}"
mode="widthFix"
catchtap="previewMedia"
data-media-index="{{mediaIndex}}"
/>
</block>
</view>
</view>
</scroll-view>
</view>
</swiper-item>
</block>
</swiper>
</view>
</view>
</t-popup>