fix travel style

This commit is contained in:
Timi
2025-12-16 16:57:49 +08:00
parent e650571563
commit f0f2815971
32 changed files with 1238 additions and 594 deletions

View File

@ -6,11 +6,14 @@
"t-rate": "tdesign-miniprogram/rate/rate",
"t-input": "tdesign-miniprogram/input/input",
"t-button": "tdesign-miniprogram/button/button",
"t-dialog": "tdesign-miniprogram/dialog/dialog",
"t-picker": "tdesign-miniprogram/picker/picker",
"t-navbar": "tdesign-miniprogram/navbar/navbar",
"t-loading": "tdesign-miniprogram/loading/loading",
"t-stepper": "tdesign-miniprogram/stepper/stepper",
"t-textarea": "tdesign-miniprogram/textarea/textarea",
"t-cell-group": "tdesign-miniprogram/cell-group/cell-group"
"t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
"t-picker-item": "tdesign-miniprogram/picker-item/picker-item"
},
"styleIsolation": "shared"
}

View File

@ -1,6 +1,6 @@
// pages/main/travel-location-editor/index.less
.container {
.travel-location-editor {
width: 100vw;
min-height: 100vh;
background: var(--theme-bg-secondary);
@ -14,7 +14,7 @@
align-items: center;
flex-direction: column;
.loading-text {
.text {
color: var(--theme-text-secondary);
margin-top: 24rpx;
font-size: 28rpx;
@ -24,32 +24,31 @@
.section {
margin-top: 48rpx;
> .title {
color: var(--theme-text-secondary);
padding: 0 32rpx;
font-size: 28rpx;
line-height: 64rpx;
}
.location {
.title {
width: 2em;
}
}
.picker .slot {
gap: 16rpx;
display: flex;
align-items: center;
}
.location-slot {
gap: 16rpx;
display: flex;
align-items: center;
.location-text {
color: var(--theme-text-primary);
font-size: 28rpx;
}
.location-placeholder {
color: var(--theme-text-placeholder);
font-size: 28rpx;
}
}
&.media {
.gallery {
gap: 10rpx;
padding: 0 6rpx;
display: grid;
grid-template-columns: repeat(3, 1fr);
@ -67,6 +66,10 @@
margin: 0;
font-size: 80rpx;
background: transparent;
&::after {
border-radius: 0;
}
}
.thumbnail {
@ -224,3 +227,14 @@
}
}
}
.delete-dialog {
padding: 16rpx 0;
.tips {
color: var(--theme-text-secondary);
font-size: 28rpx;
line-height: 1.5;
margin-bottom: 24rpx;
}
}

View File

@ -30,8 +30,18 @@ interface TravelLocationEditorData {
amount: number;
/** 是否需要身份证 */
requireIdCard: boolean;
/** 必要评分 */
/** 是否需要预约 */
requireAppointment: boolean;
/** 首次出行时间戳 */
firstTraveledAt: number;
/** 上次出行时间戳 */
lastTraveledAt: number;
/** 出行次数 */
travelCount: number;
/** 评分 */
score: number;
/** 重要程度 */
importance: number;
/** 媒体列表(创建和编辑模式使用) */
mediaList: (MediaItem | WechatMediaItem)[];
/** 新媒体列表(编辑模式使用) */
@ -48,6 +58,12 @@ interface TravelLocationEditorData {
locationTypes: { label: string; value: TravelLocationType }[];
/** 地点类型选中索引 */
locationTypeIndex: number;
/** 地点类型选择器可见性 */
locationTypePickerVisible: boolean;
/** 删除对话框可见性 */
deleteDialogVisible: boolean;
/** 删除确认文本 */
deleteConfirmText: string;
/** 媒体类型枚举 */
mediaItemTypeEnum: any;
}
@ -65,7 +81,12 @@ Page({
lng: 0,
amount: 0,
requireIdCard: false,
requireAppointment: false,
firstTraveledAt: 0,
lastTraveledAt: 0,
travelCount: 0,
score: 3,
importance: 1,
mediaList: [],
newMediaList: [],
isLoading: false,
@ -83,7 +104,10 @@ Page({
{ label: "购物", value: TravelLocationType.SHOPPING },
{ label: "其他", value: TravelLocationType.OTHER }
],
locationTypeIndex: 0
locationTypeIndex: 0,
locationTypePickerVisible: false,
deleteDialogVisible: false,
deleteConfirmText: ""
},
onLoad(options: any) {
@ -161,7 +185,12 @@ Page({
lng: location.lng || 0,
amount: location.amount || 0,
requireIdCard: location.requireIdCard || false,
requireAppointment: location.requireAppointment || false,
firstTraveledAt: location.firstTraveledAt || 0,
lastTraveledAt: location.lastTraveledAt || 0,
travelCount: location.travelCount || 0,
score: location.score !== undefined ? location.score : 3,
importance: location.importance !== undefined ? location.importance : 1,
mediaList,
isLoading: false
});
@ -187,21 +216,51 @@ Page({
});
},
/** 显示地点类型选择器 */
showLocationTypePicker() {
this.setData({ locationTypePickerVisible: true });
},
/** Picker 确认 */
onPickerConfirm(e: any) {
const index = e.detail.value;
this.setData({
locationTypeIndex: index,
type: this.data.locationTypes[index].value,
locationTypePickerVisible: false
});
},
/** Picker 取消 */
onPickerCancel() {
this.setData({ locationTypePickerVisible: false });
},
/** 改变是否需要身份证 */
onChangeRequireIdCard(e: any) {
this.setData({ requireIdCard: e.detail.value });
},
/** 改变是否需要预约 */
onChangeRequireAppointment(e: any) {
this.setData({ requireAppointment: e.detail.value });
},
/** 改变评分 */
onChangeScore(e: any) {
this.setData({ score: e.detail.value });
},
/** 改变重要程度 */
onChangeImportance(e: any) {
this.setData({ importance: e.detail.value });
},
/** 选择位置 */
chooseLocation() {
wx.chooseLocation({
success: (res) => {
const locationName = res.address || res.name;
const locationName = res.name || res.address;
const updateData: any = {
location: locationName,
lat: res.latitude,
@ -340,31 +399,60 @@ Page({
/** 删除地点 */
deleteLocation() {
wx.showModal({
title: "确认删除",
content: "确定要删除这个地点吗?删除后无法恢复。",
success: async (res) => {
if (res.confirm && this.data.id) {
try {
await TravelLocationApi.delete(this.data.id);
wx.showToast({
title: "删除成功",
icon: "success"
});
setTimeout(() => {
wx.navigateBack();
}, 1000);
} catch (error) {
wx.showToast({
title: "删除失败",
icon: "error"
});
}
}
}
this.setData({
deleteDialogVisible: true,
deleteConfirmText: ""
});
},
/** 取消删除 */
cancelDelete() {
this.setData({
deleteDialogVisible: false,
deleteConfirmText: ""
});
},
/** 确认删除 */
confirmDelete() {
const inputText = this.data.deleteConfirmText.trim();
if (inputText !== "确认删除") {
wx.showToast({
title: "输入不匹配",
icon: "error"
});
return;
}
this.setData({
deleteDialogVisible: false
});
this.executeDelete();
},
/** 执行删除 */
async executeDelete() {
if (!this.data.id) {
return;
}
wx.showLoading({ title: "删除中...", mask: true });
try {
await TravelLocationApi.delete(this.data.id);
wx.showToast({
title: "删除成功",
icon: "success"
});
setTimeout(() => {
wx.navigateBack();
}, 1500);
} catch (error) {
// 错误已由 Network 类处理
} finally {
wx.hideLoading();
}
},
/** 提交/保存 */
submit() {
// 验证必填字段
@ -425,7 +513,12 @@ Page({
lng: this.data.lng,
amount: this.data.amount,
requireIdCard: this.data.requireIdCard,
requireAppointment: this.data.requireAppointment,
firstTraveledAt: this.data.firstTraveledAt,
lastTraveledAt: this.data.lastTraveledAt,
travelCount: this.data.travelCount,
score: this.data.score,
importance: this.data.importance,
tempFileIds
});
wx.showToast({
@ -479,7 +572,12 @@ Page({
lng: this.data.lng,
amount: this.data.amount,
requireIdCard: this.data.requireIdCard,
requireAppointment: this.data.requireAppointment,
firstTraveledAt: this.data.firstTraveledAt,
lastTraveledAt: this.data.lastTraveledAt,
travelCount: this.data.travelCount,
score: this.data.score,
importance: this.data.importance,
attachmentIds,
tempFileIds
});

View File

@ -3,42 +3,25 @@
<text slot="left" bindtap="cancel">取消</text>
</t-navbar>
<scroll-view class="container" type="custom" scroll-y show-scrollbar="{{false}}">
<scroll-view class="travel-location-editor" type="custom" scroll-y show-scrollbar="{{false}}">
<view class="content">
<view wx:if="{{isLoading}}" class="loading">
<t-loading theme="dots" size="40rpx" />
<text class="loading-text">加载中...</text>
<text class="text">加载中...</text>
</view>
<block wx:else>
<t-cell-group class="section">
<t-cell title="地点类型">
<view slot="right-icon">
<picker
class="picker"
mode="selector"
range="{{locationTypes}}"
range-key="label"
value="{{locationTypeIndex}}"
bindchange="onChangeLocationType"
>
<view class="slot">
<text>{{locationTypes[locationTypeIndex].label}}</text>
<t-icon name="chevron-right" size="20px" class="icon" />
</view>
</picker>
</view>
<view slot="title" class="title">位置信息</view>
<t-cell title="地点类型" arrow bind:click="showLocationTypePicker">
<view slot="note" class="black">{{locationTypes[locationTypeIndex].label}}</view>
</t-cell>
<t-cell title="位置" required bind:click="chooseLocation">
<view slot="right-icon">
<view class="location-slot">
<text wx:if="{{location}}" class="location-text">{{location}}</text>
<text wx:else class="location-placeholder">点击选择位置</text>
<t-icon name="chevron-right" size="20px" class="icon" />
</view>
</view>
<t-cell class="location" required arrow bind:click="chooseLocation">
<view slot="title" class="title">位置</view>
<view slot="note" class="black">{{location}}</view>
</t-cell>
</t-cell-group>
<t-cell-group class="section">
<view slot="title" class="title">基本信息</view>
<t-input
class="input"
placeholder="请输入地点名称"
@ -57,6 +40,7 @@
</t-textarea>
</t-cell-group>
<t-cell-group class="section">
<view slot="title" class="title">详细信息</view>
<t-input
model:value="{{amount}}"
placeholder="0"
@ -64,7 +48,27 @@
suffix="元"
align="right"
/>
<t-cell title="必要评分">
<t-cell title="需要身份证">
<view slot="right-icon">
<switch checked="{{requireIdCard}}" bindchange="onChangeRequireIdCard" />
</view>
</t-cell>
<t-cell title="需要预约">
<view slot="right-icon">
<switch checked="{{requireAppointment}}" bindchange="onChangeRequireAppointment" />
</view>
</t-cell>
<t-cell title="重要程度">
<view slot="right-icon">
<t-rate
value="{{importance}}"
count="{{5}}"
size="24px"
bind:change="onChangeImportance"
/>
</view>
</t-cell>
<t-cell title="评分">
<view slot="right-icon">
<t-rate
value="{{score}}"
@ -74,11 +78,6 @@
/>
</view>
</t-cell>
<t-cell title="需要身份证">
<view slot="right-icon">
<switch checked="{{requireIdCard}}" bindchange="onChangeRequireIdCard" />
</view>
</t-cell>
</t-cell-group>
<view class="section media">
<view class="gallery">
@ -187,7 +186,7 @@
<t-icon
class="delete"
name="close"
bindtap="deleteMedia"
bindtap="deleteNewMedia"
data-index="{{index}}"
data-new-media="{{true}}"
/>
@ -240,3 +239,34 @@
</block>
</view>
</scroll-view>
<!-- 地点类型选择器 -->
<t-picker
visible="{{locationTypePickerVisible}}"
value="{{locationTypeIndex}}"
cancelBtn="取消"
confirmBtn="确认"
bind:confirm="onPickerConfirm"
bind:cancel="onPickerCancel"
>
<t-picker-item options="{{locationTypes}}" />
</t-picker>
<!-- 删除确认对话框 -->
<t-dialog
visible="{{deleteDialogVisible}}"
title="删除地点"
confirm-btn="{{ {content: '删除', variant: 'text', theme: 'danger'} }}"
cancel-btn="取消"
bind:confirm="confirmDelete"
bind:cancel="cancelDelete"
>
<view slot="content" class="delete-dialog">
<view class="tips">
<text>此地点的图片和视频也会同步删除,删除后无法恢复,请输入 "</text>
<text style="color: var(--theme-error)">确认删除</text>
<text>" 以继续</text>
</view>
<t-input placeholder="请输入:确认删除" model:value="{{deleteConfirmText}}" />
</view>
</t-dialog>