diff --git a/.gitignore b/.gitignore
index 0c17b9c..37ffffb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,4 +62,5 @@ ehthumbs.db
.claude/
CLAUDE.md
+AGENTS.md
/docs
diff --git a/miniprogram/app.json b/miniprogram/app.json
index 022ccf9..4294f01 100644
--- a/miniprogram/app.json
+++ b/miniprogram/app.json
@@ -8,9 +8,10 @@
"pages/main/journal-date/index",
"pages/main/portfolio/index",
"pages/main/travel/index",
- "pages/main/travel-location-map/index",
"pages/main/travel-detail/index",
"pages/main/travel-editor/index",
+ "pages/main/travel-location-detail/index",
+ "pages/main/travel-location-map/index",
"pages/main/travel-location-editor/index",
"pages/main/about/index",
"pages/main/moment/index"
@@ -19,8 +20,8 @@
"themeLocation": "theme.json",
"window": {
"navigationStyle": "custom",
- "navigationBarTextStyle": "black",
- "navigationBarBackgroundColor": "#FFFFFF"
+ "navigationBarTextStyle": "@navigationBarTextStyle",
+ "navigationBarBackgroundColor": "@navigationBarBackgroundColor"
},
"lazyCodeLoading": "requiredComponents",
"tabBar": {
@@ -70,4 +71,4 @@
"getLocation",
"chooseLocation"
]
-}
\ No newline at end of file
+}
diff --git a/miniprogram/app.less b/miniprogram/app.less
new file mode 100644
index 0000000..ed55a27
--- /dev/null
+++ b/miniprogram/app.less
@@ -0,0 +1,17 @@
+/**app.wxss**/
+@import "./timi-web.less";
+@import "./tdesign.less";
+@import "./theme.less";
+
+.setting-bg {
+ background: var(--theme-bg-wx);
+
+ &::before {
+ content: "";
+ width: 100vw;
+ height: 100vh;
+ z-index: -1;
+ position: fixed;
+ background: var(--theme-bg-wx);
+ }
+}
\ No newline at end of file
diff --git a/miniprogram/app.wxss b/miniprogram/app.wxss
deleted file mode 100644
index 7bea78a..0000000
--- a/miniprogram/app.wxss
+++ /dev/null
@@ -1,3 +0,0 @@
-/**app.wxss**/
-@import "./tdesign.wxss";
-@import "./theme.wxss";
\ No newline at end of file
diff --git a/miniprogram/components/travel-location-popup/index.wxml b/miniprogram/components/travel-location-popup/index.wxml
index 6990c4d..f179775 100644
--- a/miniprogram/components/travel-location-popup/index.wxml
+++ b/miniprogram/components/travel-location-popup/index.wxml
@@ -40,9 +40,18 @@
评分 {{item.score}}
+
+ 重要性 {{item.importance}}
+
+
+ 已出行 {{item.travelCount}} 次
+
需要身份证
+
+ 需要预约
+
{{item.description}}
diff --git a/miniprogram/pages/main/about/index.less b/miniprogram/pages/main/about/index.less
index 8f6a046..ed56ff8 100644
--- a/miniprogram/pages/main/about/index.less
+++ b/miniprogram/pages/main/about/index.less
@@ -1,7 +1,7 @@
/* pages/info/info.less */
page {
- height: 100vh;
display: flex;
+ background: var(--theme-bg-wx);
flex-direction: column;
}
diff --git a/miniprogram/pages/main/about/index.wxml b/miniprogram/pages/main/about/index.wxml
index d4cdaf1..2341d99 100644
--- a/miniprogram/pages/main/about/index.wxml
+++ b/miniprogram/pages/main/about/index.wxml
@@ -26,7 +26,7 @@
版本:
- 1.6.0
+ 1.6.1
{{copyright}}
diff --git a/miniprogram/pages/main/journal-editor/index.less b/miniprogram/pages/main/journal-editor/index.less
index 1235e43..8c1d9c8 100644
--- a/miniprogram/pages/main/journal-editor/index.less
+++ b/miniprogram/pages/main/journal-editor/index.less
@@ -59,6 +59,10 @@
margin: 0;
font-size: 80rpx;
background: transparent;
+
+ &::after {
+ border-radius: 0;
+ }
}
.thumbnail {
diff --git a/miniprogram/pages/main/journal-editor/index.wxml b/miniprogram/pages/main/journal-editor/index.wxml
index 45e7bf6..7e05759 100644
--- a/miniprogram/pages/main/journal-editor/index.wxml
+++ b/miniprogram/pages/main/journal-editor/index.wxml
@@ -238,10 +238,6 @@
确认删除
" 以继续
-
+
diff --git a/miniprogram/pages/main/journal/index.wxml b/miniprogram/pages/main/journal/index.wxml
index bcb42d9..cad41e9 100644
--- a/miniprogram/pages/main/journal/index.wxml
+++ b/miniprogram/pages/main/journal/index.wxml
@@ -24,7 +24,7 @@
sticky-offset="{{stickyOffset}}"
>
-
+
{{journal.idea}}
.title {
+ color: var(--theme-text-secondary);
+ padding: 0 32rpx;
+ font-size: 28rpx;
+ line-height: 64rpx;
+ }
- .title {
+ &.status {
+ display: flex;
+ margin-top: 24rpx;
+ justify-content: center;
+ }
+
+ &.title {
color: var(--theme-text-primary);
+ padding: 24rpx;
font-size: 40rpx;
+ text-align: center;
+ margin-top: 24rpx;
+ background: var(--theme-bg-card);
+ box-shadow: 0 2px 12px var(--theme-shadow-light);
font-weight: bold;
line-height: 1.5;
}
- }
- .info-card,
- .content-card,
- .locations-card {
- overflow: hidden;
- background: var(--theme-bg-card);
- box-shadow: 0 2px 12px var(--theme-shadow-light);
+ &.locations {
- .card-title {
- display: flex;
- padding: 24rpx;
- align-items: center;
- justify-content: space-between;
- border-bottom: 1px solid var(--theme-border-light);
-
- .title-left {
- gap: 12rpx;
+ .action {
+ gap: 32rpx;
display: flex;
- align-items: center;
-
- .icon {
- color: var(--theme-primary);
- }
-
- .text {
- color: var(--theme-text-primary);
- font-size: 32rpx;
- font-weight: bold;
- }
}
- .title-right {
- gap: 16rpx;
- display: flex;
- align-items: center;
+ .location {
- .icon-btn {
+ .note {
+ width: 2em;
+ }
+
+ .description {
+ column-gap: 24rpx;
+ color: var(--theme-text-secondary);
display: flex;
- padding: 8rpx;
- align-items: center;
- justify-content: center;
- transition: all .2s;
+ flex-wrap: wrap;
+ font-size: 26rpx;
- &:active {
- transform: scale(1.1);
- }
- }
- }
- }
-
- .info-list {
- padding: 24rpx;
-
- .info-item {
- display: flex;
- padding: 20rpx 0;
- align-items: center;
- justify-content: space-between;
- border-bottom: 1px solid var(--theme-border-light);
-
- &:last-child {
- border-bottom: none;
- }
-
- .label {
- gap: 12rpx;
- flex: 1;
- display: flex;
- align-items: center;
-
- .icon {
- color: var(--theme-text-secondary);
- }
-
- .text {
- color: var(--theme-text-secondary);
- font-size: 28rpx;
- }
- }
-
- .value {
- color: var(--theme-text-primary);
- font-size: 28rpx;
- font-weight: 500;
- }
- }
- }
-
- .content-text {
- color: var(--theme-text-primary);
- padding: 24rpx;
- font-size: 28rpx;
- line-height: 1.8;
- white-space: pre-wrap;
- word-break: break-all;
- }
-
- .loading-container {
- display: flex;
- padding: 48rpx;
- align-items: center;
- justify-content: center;
- }
-
- .locations-list {
- padding: 24rpx;
-
- .location-item {
- gap: 24rpx;
- display: flex;
- padding: 24rpx;
- margin-bottom: 20rpx;
- border-radius: 12rpx;
- background: var(--theme-bg-page);
- border: 1px solid var(--theme-border-light);
- transition: all .3s;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- &:active {
- transform: scale(.98);
- background: var(--theme-bg-card);
- }
-
- .location-icon {
- display: flex;
- flex-shrink: 0;
- align-items: center;
- justify-content: center;
- }
-
- .location-content {
- gap: 16rpx;
- flex: 1;
- display: flex;
- overflow: hidden;
- flex-direction: column;
-
- .location-header {
+ .item {
+ gap: 12rpx;
+ width: fit-content;
display: flex;
+ padding: 2rpx 4rpx;
align-items: center;
- justify-content: space-between;
+ background: var(--theme-bg-page);
- .location-title {
- flex: 1;
- color: var(--theme-text-primary);
- overflow: hidden;
- font-size: 30rpx;
- font-weight: bold;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
-
- .location-description {
- color: var(--theme-text-secondary);
- font-size: 26rpx;
- line-height: 1.6;
- word-break: break-all;
- }
-
- .location-info {
- gap: 24rpx;
- display: flex;
- flex-wrap: wrap;
-
- .info-item {
+ .stars {
gap: 8rpx;
display: flex;
- align-items: center;
- color: var(--theme-text-secondary);
- font-size: 24rpx;
}
}
}
-
- .location-arrow {
- display: flex;
- flex-shrink: 0;
- align-items: center;
- justify-content: center;
- }
}
}
- .empty-state {
- gap: 16rpx;
+ &.action {
+ gap: 24rpx;
display: flex;
- padding: 64rpx 24rpx;
- align-items: center;
- flex-direction: column;
- justify-content: center;
+ padding: 24rpx 16rpx 128rpx 16rpx;
- .empty-text {
- color: var(--theme-text-secondary);
- font-size: 26rpx;
- }
- }
- }
-
- .time-card {
- gap: 16rpx;
- display: flex;
- padding: 24rpx;
- flex-direction: column;
- background: var(--theme-bg-card);
- box-shadow: 0 2px 12px var(--theme-shadow-light);
-
- .time-item {
- display: flex;
- align-items: center;
- justify-content: space-between;
-
- .label {
- color: var(--theme-text-secondary);
- font-size: 24rpx;
+ .edit {
+ flex: 2;
}
- .value {
- color: var(--theme-text-secondary);
- font-size: 24rpx;
+ .delete {
+ flex: 1;
}
}
}
-
- .action-section {
- gap: 24rpx;
- display: flex;
- padding: 24rpx 16rpx 48rpx 16rpx;
-
- .edit-btn {
- flex: 2;
- }
-
- .delete-btn {
- flex: 1;
- }
- }
}
}
-.delete-dialog-content {
- gap: 32rpx;
- display: flex;
- flex-direction: column;
+.delete-dialog {
+ padding: 16rpx 0;
- .delete-warning {
- gap: 16rpx;
- display: flex;
- padding: 24rpx;
- align-items: center;
- border-radius: 12rpx;
- flex-direction: column;
- background: #FFF4F4;
-
- .warning-text {
- color: #E34D59;
- font-size: 28rpx;
- text-align: center;
- }
- }
-
- .delete-confirm {
- gap: 16rpx;
- display: flex;
- flex-direction: column;
-
- .confirm-label {
- color: var(--theme-text-primary);
- font-size: 28rpx;
- }
+ .tips {
+ color: var(--theme-text-secondary);
+ font-size: 28rpx;
+ line-height: 1.5;
+ margin-bottom: 24rpx;
}
}
diff --git a/miniprogram/pages/main/travel-detail/index.ts b/miniprogram/pages/main/travel-detail/index.ts
index 89aad09..608cc8d 100644
--- a/miniprogram/pages/main/travel-detail/index.ts
+++ b/miniprogram/pages/main/travel-detail/index.ts
@@ -83,15 +83,6 @@ Page({
travel.travelDate = Time.toDate(travel.travelAt);
travel.travelTime = Time.toTime(travel.travelAt);
}
-
- // 格式化创建和更新时间
- if (travel.createdAt) {
- (travel as any).createdAtFormatted = Time.toDateTime(travel.createdAt);
- }
- if (travel.updatedAt) {
- (travel as any).updatedAtFormatted = Time.toDateTime(travel.updatedAt);
- }
-
this.setData({ travel });
// 获取地点列表
@@ -151,13 +142,13 @@ Page({
}
},
- /** 编辑地点 */
- toEditLocation(e: WechatMiniprogram.BaseEvent) {
+ /** 查看地点详情 */
+ toLocationDetail(e: WechatMiniprogram.BaseEvent) {
const { id } = e.currentTarget.dataset;
const { travel } = this.data;
if (id && travel && travel.id) {
wx.navigateTo({
- url: `/pages/main/travel-location-editor/index?id=${id}&travelId=${travel.id}`
+ url: `/pages/main/travel-location-detail/index?id=${id}&travelId=${travel.id}`
});
}
},
diff --git a/miniprogram/pages/main/travel-detail/index.wxml b/miniprogram/pages/main/travel-detail/index.wxml
index 48da43c..f534aa3 100644
--- a/miniprogram/pages/main/travel-detail/index.wxml
+++ b/miniprogram/pages/main/travel-detail/index.wxml
@@ -7,164 +7,105 @@
-
+
-
-
+
{{statusLabels[travel.status]}}
-
-
- {{travel.title || '未命名旅行'}}
-
-
+ {{travel.title || '未命名旅行'}}
-
-
-
- 基本信息
-
-
-
-
-
-
- 出行时间
-
- {{travel.travelDate}} {{travel.travelTime}}
+
+ 基本信息
+
+
+ {{travel.travelDate}} {{travel.travelTime}}
+ 未定
-
-
-
-
- 旅行天数
-
- {{travel.days}} 天
+
+
+
+ {{travel.days}} 天
+ 未定
-
-
-
-
- 交通方式
-
- {{transportLabels[travel.transportationType]}}
-
-
-
-
+
+
+ {{transportLabels[travel.transportationType]}}
+
+
-
-
-
- 详细说明
-
- {{travel.content}}
-
-
-
-
-
-
-
- 地点列表
+
+ 详细说明
+
+
+
+ 地点列表
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
- 创建时间
- {{travel.createdAtFormatted || ''}}
-
-
- 更新时间
- {{travel.updatedAtFormatted || ''}}
-
-
-
+
+
+
-
+
删除
@@ -173,7 +114,7 @@
theme="primary"
size="large"
icon="edit"
- t-class="edit-btn"
+ t-class="edit"
bind:tap="toEdit"
>
编辑旅行计划
@@ -186,23 +127,17 @@
-
-
-
- 删除后无法恢复,请谨慎操作!
-
-
- 请输入"确认删除"以继续:
-
+
+
+ 此计划的地点、图片和视频也会同步删除,删除后无法恢复,请输入 "
+ 确认删除
+ " 以继续
+
diff --git a/miniprogram/pages/main/travel-editor/index.less b/miniprogram/pages/main/travel-editor/index.less
index 86c5916..63a1032 100644
--- a/miniprogram/pages/main/travel-editor/index.less
+++ b/miniprogram/pages/main/travel-editor/index.less
@@ -30,6 +30,31 @@
align-items: center;
}
+ .travel-at-content,
+ .days-content {
+ gap: 16rpx;
+ display: flex;
+ align-items: center;
+
+ .clear-icon {
+ color: var(--theme-text-tertiary);
+ cursor: pointer;
+
+ &:active {
+ opacity: .6;
+ }
+ }
+
+ .undecided-text {
+ color: var(--theme-text-tertiary);
+ cursor: pointer;
+
+ &:active {
+ opacity: .6;
+ }
+ }
+ }
+
.days-stepper {
display: flex;
align-items: center;
@@ -58,35 +83,13 @@
}
}
-.delete-dialog-content {
- gap: 32rpx;
- display: flex;
- flex-direction: column;
+.delete-dialog {
+ padding: 16rpx 0;
- .delete-warning {
- gap: 16rpx;
- display: flex;
- padding: 24rpx;
- align-items: center;
- border-radius: 12rpx;
- flex-direction: column;
- background: #FFF4F4;
-
- .warning-text {
- color: #E34D59;
- font-size: 28rpx;
- text-align: center;
- }
- }
-
- .delete-confirm {
- gap: 16rpx;
- display: flex;
- flex-direction: column;
-
- .confirm-label {
- color: var(--theme-text-primary);
- font-size: 28rpx;
- }
+ .tips {
+ color: var(--theme-text-secondary);
+ font-size: 28rpx;
+ line-height: 1.5;
+ margin-bottom: 24rpx;
}
}
diff --git a/miniprogram/pages/main/travel-editor/index.ts b/miniprogram/pages/main/travel-editor/index.ts
index f177fcf..557df1a 100644
--- a/miniprogram/pages/main/travel-editor/index.ts
+++ b/miniprogram/pages/main/travel-editor/index.ts
@@ -17,8 +17,12 @@ interface TravelEditorData {
date: string;
/** 出行时间 */
time: string;
+ /** 出行时间是否未定 */
+ travelAtUndecided: boolean;
/** 天数 */
days: number;
+ /** 天数是否未定 */
+ daysUndecided: boolean;
/** 交通类型 */
transportationType: TransportationType;
/** 状态 */
@@ -49,9 +53,11 @@ Page({
content: "",
date: "2025-06-28",
time: "16:00",
+ travelAtUndecided: true,
days: 1,
- transportationType: TransportationType.PLANE,
- transportationTypeIndex: 0,
+ daysUndecided: true,
+ transportationType: TransportationType.SELF_DRIVING,
+ transportationTypeIndex: 4,
status: TravelStatus.PLANNING,
statusIndex: 0,
isLoading: false,
@@ -108,13 +114,19 @@ Page({
// 格式化数据
let date = "";
let time = "";
+ let travelAtUndecided = true;
if (travel.travelAt) {
date = Time.toDate(travel.travelAt);
time = Time.toTime(travel.travelAt);
+ travelAtUndecided = false;
}
+ // 判断天数是否未定
+ const daysUndecided = !travel.days;
+ const days = travel.days || 1;
+
// 计算交通类型索引
- const transportationType = travel.transportationType || TransportationType.PLANE;
+ const transportationType = travel.transportationType || TransportationType.SELF_DRIVING;
const transportationTypeIndex = this.data.transportationTypes.findIndex(
item => item.value === transportationType
);
@@ -128,9 +140,11 @@ Page({
content: travel.content || "",
date,
time,
- days: travel.days || 1,
+ travelAtUndecided,
+ days,
+ daysUndecided,
transportationType,
- transportationTypeIndex: transportationTypeIndex >= 0 ? transportationTypeIndex : 0,
+ transportationTypeIndex: transportationTypeIndex >= 0 ? transportationTypeIndex : 4,
status,
statusIndex: statusIndex >= 0 ? statusIndex : 0,
isLoading: false
@@ -163,13 +177,42 @@ Page({
status: this.data.statuses[index].value
});
},
+ /** 切换出行时间未定状态 */
+ toggleTravelAtUndecided(e: any) {
+ this.setData({ travelAtUndecided: e.detail.value });
+ },
+ /** 切换天数未定状态 */
+ toggleDaysUndecided(e: any) {
+ this.setData({ daysUndecided: e.detail.value });
+ },
+ /** 清除出行时间 */
+ clearTravelAt() {
+ this.setData({ travelAtUndecided: true });
+ },
+ /** 清除天数 */
+ clearDays() {
+ this.setData({ daysUndecided: true });
+ },
+ /** 点击未定文字选择时间 */
+ selectTravelAt() {
+ // 设置为已定状态,会自动显示选择器
+ const unixTime = new Date().getTime();
+ this.setData({
+ travelAtUndecided: false,
+ date: Time.toDate(unixTime),
+ time: Time.toTime(unixTime)
+ });
+ },
+ /** 点击未定文字选择天数 */
+ selectDays() {
+ this.setData({
+ daysUndecided: false,
+ days: 1
+ });
+ },
/** 取消 */
cancel() {
- if (this.data.mode === "create") {
- wx.navigateBack();
- } else {
- wx.navigateBack();
- }
+ wx.navigateBack();
},
/** 提交/保存 */
submit() {
@@ -195,8 +238,10 @@ Page({
await TravelApi.create({
title: this.data.title.trim(),
content: this.data.content.trim(),
- travelAt: new Date(`${this.data.date}T${this.data.time}:00`).getTime(),
- days: this.data.days,
+ travelAt: this.data.travelAtUndecided
+ ? null
+ : new Date(`${this.data.date}T${this.data.time}:00`).getTime(),
+ days: this.data.daysUndecided ? null : this.data.days,
transportationType: this.data.transportationType,
status: this.data.status
});
@@ -219,8 +264,10 @@ Page({
id: this.data.id!,
title: this.data.title.trim(),
content: this.data.content.trim(),
- travelAt: new Date(`${this.data.date}T${this.data.time}:00`).getTime(),
- days: this.data.days,
+ travelAt: this.data.travelAtUndecided
+ ? null
+ : new Date(`${this.data.date}T${this.data.time}:00`).getTime(),
+ days: this.data.daysUndecided ? null : this.data.days,
transportationType: this.data.transportationType,
status: this.data.status
});
diff --git a/miniprogram/pages/main/travel-editor/index.wxml b/miniprogram/pages/main/travel-editor/index.wxml
index bb05af5..80a8cac 100644
--- a/miniprogram/pages/main/travel-editor/index.wxml
+++ b/miniprogram/pages/main/travel-editor/index.wxml
@@ -32,18 +32,29 @@
-
-
+
+
{{date}}
+
+ 未定
+
+
-
+
+
+ 未定
+
+
@@ -128,23 +149,17 @@
-
-
-
- 删除后无法恢复,请谨慎操作!
-
-
- 请输入"确认删除"以继续:
-
+
+
+ 此计划的地点、图片和视频也会同步删除,删除后无法恢复,请输入 "
+ 确认删除
+ " 以继续
+
diff --git a/miniprogram/pages/main/travel-location-detail/index.json b/miniprogram/pages/main/travel-location-detail/index.json
new file mode 100644
index 0000000..b37af6b
--- /dev/null
+++ b/miniprogram/pages/main/travel-location-detail/index.json
@@ -0,0 +1,17 @@
+{
+ "component": true,
+ "usingComponents": {
+ "t-tag": "tdesign-miniprogram/tag/tag",
+ "t-cell": "tdesign-miniprogram/cell/cell",
+ "t-rate": "tdesign-miniprogram/rate/rate",
+ "t-icon": "tdesign-miniprogram/icon/icon",
+ "t-input": "tdesign-miniprogram/input/input",
+ "t-button": "tdesign-miniprogram/button/button",
+ "t-empty": "tdesign-miniprogram/empty/empty",
+ "t-dialog": "tdesign-miniprogram/dialog/dialog",
+ "t-navbar": "tdesign-miniprogram/navbar/navbar",
+ "t-loading": "tdesign-miniprogram/loading/loading",
+ "t-cell-group": "tdesign-miniprogram/cell-group/cell-group"
+ },
+ "styleIsolation": "shared"
+}
diff --git a/miniprogram/pages/main/travel-location-detail/index.less b/miniprogram/pages/main/travel-location-detail/index.less
new file mode 100644
index 0000000..f41fe57
--- /dev/null
+++ b/miniprogram/pages/main/travel-location-detail/index.less
@@ -0,0 +1,144 @@
+// pages/main/travel-location-detail/index.less
+.travel-location-detail {
+ width: 100vw;
+ min-height: 100vh;
+ background: var(--theme-bg-page);
+ box-sizing: border-box;
+
+ .status-card {
+ padding: 64rpx 24rpx;
+ }
+
+ .content {
+ display: flex;
+ padding-top: 48rpx;
+ flex-direction: column;
+ padding-bottom: 128rpx;
+
+ .section {
+ margin-top: 32rpx;
+
+ > .title {
+ color: var(--theme-text-secondary);
+ padding: 0 32rpx;
+ font-size: 28rpx;
+ line-height: 64rpx;
+ }
+
+ &.status {
+ display: flex;
+ margin-top: 24rpx;
+ justify-content: center;
+ }
+
+ &.title {
+ color: var(--theme-text-primary);
+ padding: 24rpx;
+ text-align: center;
+ margin-top: 24rpx;
+ background: var(--theme-bg-card);
+ box-shadow: 0 2px 12px var(--theme-shadow-light);
+
+ .title-text {
+ color: var(--theme-text-primary);
+ font-size: 40rpx;
+ font-weight: bold;
+ line-height: 1.5;
+ }
+
+ .subtitle {
+ color: var(--theme-text-secondary);
+ display: block;
+ font-size: 28rpx;
+ margin-top: 12rpx;
+ }
+ }
+
+ &.location {
+
+ .t-cell__title {
+ margin: 0;
+ }
+
+ .map {
+ padding: 0;
+ }
+
+ .mini-map {
+ width: 100%;
+ height: 520rpx;
+ }
+ }
+
+ &.media {
+
+ .media-grid {
+ gap: 16rpx;
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+
+ .media-item {
+ width: 100%;
+ height: 200rpx;
+ overflow: hidden;
+ position: relative;
+ border-radius: 12rpx;
+
+ .thumbnail {
+ width: 100%;
+ height: 100%;
+ }
+
+ .video-container {
+ width: 100%;
+ height: 100%;
+ position: relative;
+
+ .thumbnail {
+ width: 100%;
+ height: 100%;
+ }
+
+ .play-icon {
+ top: 50%;
+ left: 50%;
+ color: rgba(255, 255, 255, .9);
+ position: absolute;
+ transform: translate(-50%, -50%);
+ }
+ }
+ }
+ }
+ }
+
+ &.navigate {
+ padding: 0 16rpx;
+ }
+
+ &.action {
+ gap: 24rpx;
+ display: flex;
+ padding: 24rpx 16rpx 0 16rpx;
+
+ .edit {
+ flex: 2;
+ }
+
+ .delete {
+ flex: 1;
+ }
+ }
+ }
+ }
+}
+
+.delete-dialog {
+ padding: 16rpx 0;
+
+ .tips {
+ color: var(--theme-text-secondary);
+ font-size: 28rpx;
+ line-height: 1.5;
+ margin-bottom: 24rpx;
+ }
+}
diff --git a/miniprogram/pages/main/travel-location-detail/index.ts b/miniprogram/pages/main/travel-location-detail/index.ts
new file mode 100644
index 0000000..e811be4
--- /dev/null
+++ b/miniprogram/pages/main/travel-location-detail/index.ts
@@ -0,0 +1,291 @@
+// pages/main/travel-location-detail/index.ts
+
+import Time from "../../../utils/Time";
+import config from "../../../config/index";
+import { TravelLocationApi } from "../../../api/TravelLocationApi";
+import { TravelLocation, TravelLocationTypeIcon, TravelLocationTypeLabel } from "../../../types/Travel";
+import { MediaAttachExt, MediaAttachType } from "../../../types/Attachment";
+import { MediaItem, MediaItemType } from "../../../types/UI";
+import Toolkit from "../../../utils/Toolkit";
+
+interface TravelLocationView extends TravelLocation {
+ /** 首次出行时间 */
+ firstTravelTime?: string;
+ /** 最近出行时间 */
+ lastTravelTime?: string;
+ /** 媒体列表 */
+ mediaItems?: MediaItem[];
+}
+
+interface TravelLocationDetailData {
+ /** 地点详情 */
+ location: TravelLocationView | null;
+ /** 地点 ID */
+ locationId: string;
+ /** 旅行 ID */
+ travelId: string;
+ /** 是否正在加载 */
+ isLoading: boolean;
+ /** 错误信息 */
+ errorMessage: string;
+ /** 地点类型标签映射 */
+ locationTypeLabels: typeof TravelLocationTypeLabel;
+ /** 地点类型图标映射 */
+ locationTypeIcons: typeof TravelLocationTypeIcon;
+ /** 媒体类型枚举 */
+ mediaItemTypeEnum: typeof MediaItemType;
+ /** 地图标记 */
+ mapMarkers: WechatMiniprogram.MapMarker[];
+ /** 删除对话框可见性 */
+ deleteDialogVisible: boolean;
+ /** 删除确认文本 */
+ deleteConfirmText: string;
+}
+
+Page({
+ data: {
+ location: null,
+ locationId: "",
+ travelId: "",
+ isLoading: true,
+ errorMessage: "",
+ locationTypeLabels: TravelLocationTypeLabel,
+ locationTypeIcons: TravelLocationTypeIcon,
+ mediaItemTypeEnum: {
+ ...MediaItemType
+ },
+ mapMarkers: [],
+ deleteDialogVisible: false,
+ deleteConfirmText: ""
+ },
+
+ onLoad(options: any) {
+ const { id, travelId } = options;
+ if (id) {
+ this.setData({
+ locationId: id,
+ travelId: travelId || ""
+ });
+ this.fetchDetail(id);
+ } else {
+ wx.showToast({
+ title: "参数错误",
+ icon: "error"
+ });
+ setTimeout(() => {
+ wx.navigateBack();
+ }, 1500);
+ }
+ },
+
+ onShow() {
+ // 页面显示时刷新数据(从编辑页返回时)
+ if (this.data.locationId && !this.data.isLoading && this.data.location) {
+ this.fetchDetail(this.data.locationId);
+ }
+ },
+
+ /** 获取地点详情 */
+ async fetchDetail(id: string) {
+ this.setData({
+ isLoading: true,
+ errorMessage: ""
+ });
+
+ try {
+ const location = await TravelLocationApi.getDetail(id);
+
+ const thumbItems = (location.items || []).filter((item) => item.attachType === MediaAttachType.THUMB);
+ const mediaItems: MediaItem[] = [];
+
+ thumbItems.forEach((thumbItem) => {
+ try {
+ const extStr = thumbItem.ext ? thumbItem.ext.toString() : "";
+ if (!extStr) {
+ return;
+ }
+ const ext = JSON.parse(extStr) as MediaAttachExt;
+ const thumbURL = `${config.url}/attachment/read/${thumbItem.mongoId}`;
+ const sourceURL = `${config.url}/attachment/read/${ext.sourceMongoId}`;
+ mediaItems.push({
+ type: ext.isVideo ? MediaItemType.VIDEO : MediaItemType.IMAGE,
+ thumbURL,
+ sourceURL,
+ size: thumbItem.size || 0,
+ attachmentId: thumbItem.id!
+ });
+ } catch (parseError) {
+ console.warn("解析附件扩展信息失败", parseError);
+ }
+ });
+
+ // 构建地图标记
+ const mapMarkers: WechatMiniprogram.MapMarker[] = [];
+ if (location.lat !== undefined && location.lng !== undefined) {
+ mapMarkers.push({
+ id: 0,
+ latitude: location.lat,
+ longitude: location.lng,
+ width: 30,
+ height: 30,
+ callout: {
+ content: location.title || "地点",
+ display: "ALWAYS",
+ padding: 10,
+ borderRadius: 5,
+ bgColor: "#FFFFFF",
+ color: "#333333",
+ fontSize: 12,
+ textAlign: "center"
+ }
+ });
+ }
+
+ console.log(mediaItems);
+
+ this.setData({
+ location: {
+ ...location,
+ mediaItems,
+ firstTravelTime: location.firstTraveledAt ? Time.toDateTime(location.firstTraveledAt) : "",
+ lastTravelTime: location.lastTraveledAt ? Time.toDateTime(location.lastTraveledAt) : ""
+ },
+ travelId: location.travelId ? String(location.travelId) : this.data.travelId,
+ mapMarkers
+ });
+ } catch (error) {
+ console.error("获取地点详情失败:", error);
+ this.setData({
+ errorMessage: "加载失败,请稍后重试"
+ });
+ wx.showToast({
+ title: "加载失败",
+ icon: "error"
+ });
+ } finally {
+ this.setData({ isLoading: false });
+ }
+ },
+
+ /** 重新加载 */
+ retryFetch() {
+ if (this.data.locationId) {
+ this.fetchDetail(this.data.locationId);
+ }
+ },
+
+ /** 编辑地点 */
+ toEdit() {
+ const { location, travelId } = this.data;
+ if (location && location.id) {
+ wx.navigateTo({
+ url: `/pages/main/travel-location-editor/index?id=${location.id}&travelId=${travelId || location.travelId || ""}`
+ });
+ }
+ },
+
+ /** 出发(打开地图导航) */
+ navigate() {
+ const { location } = this.data;
+ if (location && location.lat !== undefined && location.lng !== undefined) {
+ wx.openLocation({
+ latitude: location.lat,
+ longitude: location.lng,
+ name: location.title || "目的地",
+ address: location.location || "",
+ scale: 15
+ });
+ } else {
+ wx.showToast({
+ title: "位置信息不完整",
+ icon: "error"
+ });
+ }
+ },
+
+ /** 预览媒体 */
+ preview(e: WechatMiniprogram.BaseEvent) {
+ const index = e.currentTarget.dataset.index;
+ const { location } = this.data;
+
+ if (!location || !location.mediaItems) {
+ return;
+ }
+
+ const sources = location.mediaItems.map(item => ({
+ url: item.sourceURL,
+ type: MediaItemType[item.type].toLowerCase()
+ }));
+
+ const total = sources.length;
+ const startIndex = Math.max(0, index - 25);
+ const endIndex = Math.min(total, startIndex + 50);
+ const newCurrentIndex = index - startIndex;
+
+ wx.previewMedia({
+ current: newCurrentIndex,
+ sources: sources.slice(startIndex, endIndex) as WechatMiniprogram.MediaSource[]
+ });
+ },
+
+ /** 删除地点 */
+ deleteLocation() {
+ 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.location || !this.data.location.id) {
+ return;
+ }
+
+ wx.showLoading({ title: "删除中...", mask: true });
+
+ try {
+ await TravelLocationApi.delete(this.data.location.id);
+ wx.showToast({
+ title: "删除成功",
+ icon: "success"
+ });
+ setTimeout(() => {
+ wx.navigateBack();
+ }, 1500);
+ } catch (error) {
+ // 错误已由 Network 类处理
+ } finally {
+ wx.hideLoading();
+ }
+ },
+
+ /** 返回 */
+ async goBack() {
+ Toolkit.async(() => wx.navigateBack()); // 微信 BUG,需要延时
+ }
+});
diff --git a/miniprogram/pages/main/travel-location-detail/index.wxml b/miniprogram/pages/main/travel-location-detail/index.wxml
new file mode 100644
index 0000000..d6eb721
--- /dev/null
+++ b/miniprogram/pages/main/travel-location-detail/index.wxml
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 重新加载
+
+
+
+
+
+
+
+
+
+
+ {{locationTypeLabels[location.type]}}
+
+
+
+
+ {{location.title || '未命名地点'}}
+
+
+
+ 位置信息
+
+
+
+
+
+
+
+ 基础信息
+
+ ¥{{location.amount}}
+
+
+
+ {{location.requireIdCard ? '需要' : '无需'}}
+
+
+
+
+ {{location.requireAppointment ? '需要' : '无需'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 出行记录
+
+ {{location.firstTravelTime || '未记录'}}
+
+
+ {{location.lastTravelTime || '未记录'}}
+
+
+ {{location.travelCount || 0}} 次
+
+
+
+
+ 详细说明
+
+
+
+
+ 照片/视频
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 出发导航
+
+
+
+
+
+ 删除
+
+
+ 编辑地点
+
+
+
+
+
+
+
+
+ 此地点的图片和视频也会同步删除,删除后无法恢复,请输入 "
+ 确认删除
+ " 以继续
+
+
+
+
diff --git a/miniprogram/pages/main/travel-location-editor/index.json b/miniprogram/pages/main/travel-location-editor/index.json
index d5bb092..3b377fe 100644
--- a/miniprogram/pages/main/travel-location-editor/index.json
+++ b/miniprogram/pages/main/travel-location-editor/index.json
@@ -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"
}
diff --git a/miniprogram/pages/main/travel-location-editor/index.less b/miniprogram/pages/main/travel-location-editor/index.less
index 2e25b36..fe72122 100644
--- a/miniprogram/pages/main/travel-location-editor/index.less
+++ b/miniprogram/pages/main/travel-location-editor/index.less
@@ -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;
+ }
+}
diff --git a/miniprogram/pages/main/travel-location-editor/index.ts b/miniprogram/pages/main/travel-location-editor/index.ts
index 973ac8d..e5a304b 100644
--- a/miniprogram/pages/main/travel-location-editor/index.ts
+++ b/miniprogram/pages/main/travel-location-editor/index.ts
@@ -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
});
diff --git a/miniprogram/pages/main/travel-location-editor/index.wxml b/miniprogram/pages/main/travel-location-editor/index.wxml
index 5559d00..c85a36b 100644
--- a/miniprogram/pages/main/travel-location-editor/index.wxml
+++ b/miniprogram/pages/main/travel-location-editor/index.wxml
@@ -3,42 +3,25 @@
取消
-
+
- 加载中...
+ 加载中...
-
-
-
-
- {{locationTypes[locationTypeIndex].label}}
-
-
-
-
+ 位置信息
+
+ {{locationTypes[locationTypeIndex].label}}
-
-
-
- {{location}}
- 点击选择位置
-
-
-
+
+ 位置
+ {{location}}
+ 基本信息
+ 详细信息
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
@@ -187,7 +186,7 @@
@@ -240,3 +239,34 @@
+
+
+
+
+
+
+
+
+
+
+ 此地点的图片和视频也会同步删除,删除后无法恢复,请输入 "
+ 确认删除
+ " 以继续
+
+
+
+
diff --git a/miniprogram/pages/main/travel/index.less b/miniprogram/pages/main/travel/index.less
index 0aeb2a3..e7428fe 100644
--- a/miniprogram/pages/main/travel/index.less
+++ b/miniprogram/pages/main/travel/index.less
@@ -18,32 +18,31 @@
}
}
-.travel-list {
+.travels {
width: 100vw;
padding: 16rpx;
- min-height: 100vh;
box-sizing: border-box;
padding-bottom: 120rpx;
- .travel-card {
- background: var(--theme-bg-card);
- margin-bottom: 24rpx;
- border-radius: 16rpx;
+ .travel {
overflow: hidden;
box-shadow: 0 2px 12px var(--theme-shadow-light);
transition: all .3s;
+ background: var(--theme-bg-card);
+ margin-bottom: 24rpx;
+ border-radius: 16rpx;
&:active {
transform: scale(.98);
box-shadow: 0 2px 8px var(--theme-shadow-light);
}
- .card-header {
+ .header {
padding: 24rpx;
border-bottom: 1px solid var(--theme-border-light);
}
- .card-body {
+ .body {
padding: 24rpx;
.title {
@@ -71,7 +70,7 @@
display: flex;
flex-wrap: wrap;
- .meta-item {
+ .item {
gap: 8rpx;
display: flex;
align-items: center;
diff --git a/miniprogram/pages/main/travel/index.wxml b/miniprogram/pages/main/travel/index.wxml
index 82b75fc..e2b66aa 100644
--- a/miniprogram/pages/main/travel/index.wxml
+++ b/miniprogram/pages/main/travel/index.wxml
@@ -47,25 +47,24 @@
-
+
-
-