fix: greeting page
This commit is contained in:
@@ -45,52 +45,51 @@
|
|||||||
|
|
||||||
<view class="list-container">
|
<view class="list-container">
|
||||||
<view v-for="item in list" :key="item.id" class="list-item-wrap">
|
<view v-for="item in list" :key="item.id" class="list-item-wrap">
|
||||||
<!-- Swipe Action Wrapper would go here, for now simulating simple layout -->
|
<view class="swipe-container">
|
||||||
<!-- Since uni-swipe-action requires specific component structure,
|
<!-- Delete Action (Behind) -->
|
||||||
we'll implement the visual part first as per design.
|
<view class="delete-action" @tap.stop="onDelete(item)">
|
||||||
For "Left swipe to delete", we can use uni-swipe-action.
|
<text>删除</text>
|
||||||
-->
|
</view>
|
||||||
<uni-swipe-action>
|
|
||||||
<uni-swipe-action-item
|
<!-- Card Content (Front) -->
|
||||||
:right-options="deleteOptions"
|
<view
|
||||||
@click="onSwipeClick($event, item)"
|
class="card-item"
|
||||||
|
:style="{
|
||||||
|
transform: `translateX(${item.translateX || 0}px)`,
|
||||||
|
transition: item.useTransition ? 'transform 0.3s' : 'none',
|
||||||
|
}"
|
||||||
|
@touchstart="onTouchStart($event, item)"
|
||||||
|
@touchmove="onTouchMove($event, item)"
|
||||||
|
@touchend="onTouchEnd($event, item)"
|
||||||
>
|
>
|
||||||
<view class="card-item">
|
<image :src="item.imageUrl" mode="aspectFill" class="card-img" />
|
||||||
<image
|
<view class="card-content">
|
||||||
:src="item.imageUrl"
|
<view class="card-title"
|
||||||
mode="aspectFill"
|
>{{ item.blessingTo
|
||||||
class="card-img"
|
}}{{
|
||||||
/>
|
item.blessingFrom ? item.blessingFrom : "好友"
|
||||||
<view class="card-content">
|
}}身体健康</view
|
||||||
<view class="card-title"
|
>
|
||||||
>{{ item.blessingTo
|
<view class="card-date"
|
||||||
}}{{
|
>更新时间:{{ formatDate(item.updatedAt) }}</view
|
||||||
item.blessingFrom ? item.blessingFrom : "好友"
|
>
|
||||||
}}身体健康</view
|
<view class="tags">
|
||||||
>
|
<view class="tag yellow" v-if="item.festival">{{
|
||||||
<view class="card-date"
|
item.festival
|
||||||
>更新时间:{{ formatDate(item.updatedAt) }}</view
|
}}</view>
|
||||||
>
|
<view class="tag red" v-if="item.year">{{ item.year }}</view>
|
||||||
<view class="tags">
|
|
||||||
<view class="tag yellow" v-if="item.festival">{{
|
|
||||||
item.festival
|
|
||||||
}}</view>
|
|
||||||
<view class="tag red" v-if="item.year">{{
|
|
||||||
item.year
|
|
||||||
}}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-actions">
|
|
||||||
<view class="action-btn" @tap.stop="onShare(item)">
|
|
||||||
<text class="icon">🔗</text>
|
|
||||||
</view>
|
|
||||||
<view class="action-btn" @tap.stop="onEdit(item)">
|
|
||||||
<text class="icon">✎</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</uni-swipe-action-item>
|
<view class="card-actions">
|
||||||
</uni-swipe-action>
|
<view class="action-btn" @tap.stop="onShare(item)">
|
||||||
|
<text class="icon">🔗</text>
|
||||||
|
</view>
|
||||||
|
<view class="action-btn" @tap.stop="onEdit(item)">
|
||||||
|
<text class="icon">✎</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
@@ -132,6 +131,64 @@ const deleteOptions = ref([
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Swipe Logic
|
||||||
|
const startX = ref(0);
|
||||||
|
const activeItem = ref(null);
|
||||||
|
const MAX_SWIPE_WIDTH = 80;
|
||||||
|
|
||||||
|
const onTouchStart = (e, item) => {
|
||||||
|
if (e.touches.length > 1) return;
|
||||||
|
// Close other items
|
||||||
|
if (activeItem.value && activeItem.value.id !== item.id) {
|
||||||
|
activeItem.value.translateX = 0;
|
||||||
|
activeItem.value.useTransition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
startX.value = e.touches[0].clientX;
|
||||||
|
item.useTransition = false;
|
||||||
|
activeItem.value = item;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTouchMove = (e, item) => {
|
||||||
|
if (e.touches.length > 1) return;
|
||||||
|
const currentX = e.touches[0].clientX;
|
||||||
|
const deltaX = currentX - startX.value;
|
||||||
|
|
||||||
|
// Allow swiping left (negative) up to -MAX_SWIPE_WIDTH
|
||||||
|
// If already open (translateX = -80), deltaX needs to be adjusted
|
||||||
|
// But simpler: just use delta from 0 position.
|
||||||
|
// Actually, standard swipe logic needs to account for current position.
|
||||||
|
// For simplicity: assume always starting from 0 (closed) or -80 (open).
|
||||||
|
// But if we start drag from open state, we need to handle it.
|
||||||
|
|
||||||
|
// Let's stick to "start from 0" logic for now, assuming auto-close.
|
||||||
|
// If item is already open, and we swipe right, we close it.
|
||||||
|
|
||||||
|
// Re-calculate based on initial offset if we want to support dragging from open.
|
||||||
|
// For now: simple close-on-touch-other logic covers most cases.
|
||||||
|
// We assume startX is from a state where it is either 0 or -80.
|
||||||
|
// But `item.translateX` might be -80.
|
||||||
|
|
||||||
|
let targetX = deltaX;
|
||||||
|
if (item.translateX === -MAX_SWIPE_WIDTH) {
|
||||||
|
targetX = -MAX_SWIPE_WIDTH + deltaX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetX < -MAX_SWIPE_WIDTH) targetX = -MAX_SWIPE_WIDTH;
|
||||||
|
if (targetX > 0) targetX = 0;
|
||||||
|
|
||||||
|
item.translateX = targetX;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTouchEnd = (e, item) => {
|
||||||
|
item.useTransition = true;
|
||||||
|
if (item.translateX < -30) {
|
||||||
|
item.translateX = -MAX_SWIPE_WIDTH;
|
||||||
|
} else {
|
||||||
|
item.translateX = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const sysInfo = uni.getSystemInfoSync();
|
const sysInfo = uni.getSystemInfoSync();
|
||||||
navBarTop.value = sysInfo.statusBarHeight;
|
navBarTop.value = sysInfo.statusBarHeight;
|
||||||
@@ -202,23 +259,23 @@ const formatDate = (dateStr) => {
|
|||||||
return `${y}-${m}-${d}`;
|
return `${y}-${m}-${d}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSwipeClick = (e, item) => {
|
const onDelete = (item) => {
|
||||||
if (e.index === 0) {
|
uni.showModal({
|
||||||
// Delete action
|
title: "提示",
|
||||||
uni.showModal({
|
content: "确定要删除这条祝福吗?",
|
||||||
title: "提示",
|
success: (res) => {
|
||||||
content: "确定要删除这条祝福吗?",
|
if (res.confirm) {
|
||||||
success: (res) => {
|
// Implement delete API call here
|
||||||
if (res.confirm) {
|
// For now just remove from list locally
|
||||||
// Implement delete API call here
|
list.value = list.value.filter((i) => i.id !== item.id);
|
||||||
// For now just remove from list locally
|
totalCount.value = Math.max(0, totalCount.value - 1);
|
||||||
list.value = list.value.filter((i) => i.id !== item.id);
|
uni.showToast({ title: "删除成功", icon: "none" });
|
||||||
totalCount.value = Math.max(0, totalCount.value - 1);
|
} else {
|
||||||
uni.showToast({ title: "删除成功", icon: "none" });
|
// Reset swipe state if cancelled
|
||||||
}
|
item.translateX = 0;
|
||||||
},
|
}
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onShare = (item) => {
|
const onShare = (item) => {
|
||||||
@@ -408,11 +465,36 @@ const onEdit = (item) => {
|
|||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.swipe-container {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
background: #ff3b30; // Delete background color
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-action {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 80px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #ff3b30;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.card-item {
|
.card-item {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
.card-img {
|
.card-img {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
|
|||||||
@@ -160,6 +160,12 @@ const handleLogind = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const navTo = (page) => {
|
const navTo = (page) => {
|
||||||
|
if (!isLoggedIn.value) {
|
||||||
|
loginPopupRef.value.open();
|
||||||
|
uni.showToast({ title: "请先登录", icon: "none" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (page === "greetings") {
|
if (page === "greetings") {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: "/pages/mine/greeting",
|
url: "/pages/mine/greeting",
|
||||||
|
|||||||
Reference in New Issue
Block a user