123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143 |
- const app = getApp()
- Page({
- data: {
- activeTab: 'in_progress', // in_progress, completed, all
- inProgressPlans: [], // 进行中行程数据
- completedPlans: [], // 已完成行程数据
- allPlans: [], // 全部行程数据
- completedCurrentPage: 1, // 已完成行程当前页码
- completedTotalPages: 1, // 已完成行程总页数
- allCurrentPage: 1, // 全部行程当前页码
- allTotalPages: 1, // 全部行程总页数
- isLoading: false, // 是否正在加载
- isLogin: false, // 登录状态
- showSpotModal: false, // 是否显示景点详情弹窗
- currentSpot: {}, // 当前显示的景点
- currentDayIndex: 0, // 当前景点的天数索引
- currentSpotIndex: 0, // 当前景点的索引
- showCheckinModal: false, // 是否显示打卡弹窗
- checkinImage: '', // 打卡图片
- checkinNote: '', // 打卡文案
- isUploading: false, // 是否正在上传图片
- tempCheckinData: {}, // 临时存储打卡数据
- latestPlanMapData: { // 地图数据
- showMap: false,
- markers: [],
- polylines: [],
- includePoints: [],
- longitude: 116.4074,
- latitude: 39.9042,
- scale: 14
- },
- currentMapDay: -1, // 当前显示的地图天数
- cityOptions: [] // 城市选项
- },
- onLoad() {
- const token = wx.getStorageSync('token')
- const userInfo = wx.getStorageSync('userInfo')
-
- if (token && userInfo) {
- app.globalData.token = token
- app.globalData.userInfo = userInfo
- this.setData({ isLogin: true })
- this.loadInProgressPlans()
- } else {
- this.checkLoginStatus()
- }
- },
- onShow() {
- if (this.data.isLogin) {
- if (this.data.activeTab === 'in_progress') {
- this.loadInProgressPlans()
- } else if (this.data.activeTab === 'completed') {
- this.loadCompletedPlans(this.data.completedCurrentPage)
- } else if (this.data.activeTab === 'all') {
- this.loadAllPlans(this.data.allCurrentPage)
- }
- }
- },
- checkLoginStatus() {
- const token = app.globalData.token
- if (!token) {
- wx.showModal({
- title: '未登录',
- content: '请先登录查看行程',
- confirmText: '去登录',
- success: (res) => {
- if (res.confirm) {
- wx.navigateTo({
- url: '/pages/login/login'
- })
- } else {
- wx.switchTab({
- url: '/pages/index/index'
- })
- }
- }
- })
- return
- }
- this.setData({ isLogin: true })
- this.loadInProgressPlans()
- },
- // 切换选项卡
- switchTab(e) {
- const tab = e.currentTarget.dataset.tab;
- if (this.data.activeTab === tab) return;
-
- this.setData({ activeTab: tab });
-
- if (tab === 'in_progress') {
- this.loadInProgressPlans();
- } else if (tab === 'completed') {
- this.loadCompletedPlans(1);
- } else if (tab === 'all') {
- this.loadAllPlans(1);
- }
- },
- // 加载进行中行程
- loadInProgressPlans() {
- if (!app.globalData.token) return
-
- this.setData({ isLoading: true });
-
- wx.request({
- url: app.globalData.apiBaseUrl + '/api/user/plans/',
- method: 'GET',
- data: {
- status: 'in_progress',
- limit: 1,
- timestamp: new Date().getTime()
- },
- header: {
- 'Authorization': 'Token ' + app.globalData.token,
- 'Content-Type': 'application/json'
- },
- success: (res) => {
- if (res.statusCode === 200 && res.data.status === 'success') {
- this.setData({
- inProgressPlans: res.data.data.plans,
- });
-
- if (res.data.data.plans.length > 0) {
- this.processPlanMapData(res.data.data.plans[0]);
- }
- } else {
- this.handleErrorResponse(res);
- }
- },
- fail: (err) => {
- this.handleRequestError(err);
- },
- complete: () => {
- this.setData({ isLoading: false });
- }
- });
- },
- // 加载已完成行程
- loadCompletedPlans(page = 1) {
- if (!app.globalData.token) return;
-
- this.setData({ isLoading: true });
-
- wx.request({
- url: app.globalData.apiBaseUrl + '/api/user/plans/',
- method: 'GET',
- data: {
- status: 'completed',
- page: page,
- page_size: 5
- },
- header: {
- 'Authorization': 'Token ' + app.globalData.token,
- 'Content-Type': 'application/json'
- },
- success: (res) => {
- if (res.statusCode === 200 && res.data.status === 'success') {
- this.setData({
- completedPlans: res.data.data.plans,
- completedCurrentPage: page,
- completedTotalPages: res.data.data.pagination.total_pages || 1
- });
- } else {
- this.handleErrorResponse(res);
- }
- },
- fail: (err) => {
- this.handleRequestError(err);
- },
- complete: () => {
- this.setData({ isLoading: false });
- }
- });
- },
- // 加载全部行程
- loadAllPlans(page = 1) {
- if (!app.globalData.token) return;
-
- this.setData({ isLoading: true });
-
- wx.request({
- url: app.globalData.apiBaseUrl + '/api/user/plans/',
- method: 'GET',
- data: {
- status: 'in_progress',
- page: page,
- page_size: 5
- },
- header: {
- 'Authorization': 'Token ' + app.globalData.token,
- 'Content-Type': 'application/json'
- },
- success: (res) => {
- if (res.statusCode === 200 && res.data.status === 'success') {
- this.setData({
- allPlans: res.data.data.plans,
- allCurrentPage: page,
- allTotalPages: res.data.data.pagination.total_pages || 1
- });
- } else {
- this.handleErrorResponse(res);
- }
- },
- fail: (err) => {
- this.handleRequestError(err);
- },
- complete: () => {
- this.setData({ isLoading: false });
- }
- });
- },
- // 已完成行程翻页
- changeCompletedPage(e) {
- const page = e.currentTarget.dataset.page
- if (page < 1 || page > this.data.completedTotalPages) return
- this.loadCompletedPlans(page)
- },
- // 全部行程翻页
- changeAllPage(e) {
- const page = e.currentTarget.dataset.page
- if (page < 1 || page > this.data.allTotalPages) return
- this.loadAllPlans(page)
- },
- // 开始行程
- startPlan(e) {
- const planId = e.currentTarget.dataset.id
- // 切换到进行中选项卡并加载该行程
- this.setData({
- activeTab: 'in_progress'
- }, () => {
- // 加载特定行程数据
- this.loadSpecificPlan(planId)
- })
- },
- // 加载特定行程
- loadSpecificPlan(planId) {
- if (!app.globalData.token) return
-
- this.setData({ isLoading: true });
-
- wx.request({
- url: app.globalData.apiBaseUrl + '/api/user/plans/' + planId + '/',
- method: 'GET',
- header: {
- 'Authorization': 'Token ' + app.globalData.token,
- 'Content-Type': 'application/json'
- },
- success: (res) => {
- if (res.statusCode === 200 && res.data.status === 'success') {
- this.setData({
- inProgressPlans: [res.data.data.plan],
- });
-
- this.processPlanMapData(res.data.data.plan);
- } else {
- this.handleErrorResponse(res);
- }
- },
- fail: (err) => {
- this.handleRequestError(err);
- },
- complete: () => {
- this.setData({ isLoading: false });
- }
- });
- },
- // 完成行程
- completePlan(e) {
- const planId = e.currentTarget.dataset.id
-
- wx.showModal({
- title: '确认完成',
- content: '确定要结束并保存此行程吗?',
- success: (res) => {
- if (res.confirm) {
- this.markPlanAsCompleted(planId)
- }
- }
- })
- },
- // 标记行程为已完成
- markPlanAsCompleted(planId) {
- wx.request({
- url: app.globalData.apiBaseUrl + '/api/user/plans/' + planId + '/complete/',
- method: 'POST',
- header: {
- 'Authorization': 'Token ' + app.globalData.token,
- 'Content-Type': 'application/json'
- },
- success: (res) => {
- if (res.statusCode === 200 && res.data.status === 'success') {
- wx.showToast({
- title: '行程已完成',
- icon: 'success'
- })
-
- // 重新加载数据
- this.loadInProgressPlans()
- this.loadCompletedPlans(1)
- this.loadAllPlans(1)
- } else {
- this.handleErrorResponse(res)
- }
- },
- fail: (err) => {
- this.handleRequestError(err)
- }
- })
- },
- // 处理单个行程的地图数据
- processPlanMapData(plan) {
- if (!plan || !Array.isArray(plan.day_plans) || plan.day_plans.length === 0) {
- console.warn('无效的行程数据或没有天数数据', plan);
- this.setData({
- latestPlanMapData: {
- showMap: false,
- markers: [],
- polylines: [],
- includePoints: []
- }
- });
- return;
- }
-
- const markers = [];
- const polylines = [];
- const includePoints = [];
- const dayColors = ['#e54d42', '#f37b1d', '#1cbbb4', '#0081ff', '#6739b6', '#9c26b0', '#e03997'];
-
- try {
- // 处理每一天的景点
- plan.day_plans.forEach((day, dayIndex) => {
- if (!day || !Array.isArray(day.spots)) {
- console.warn('无效的天数据或没有景点数据', day);
- return;
- }
-
- const dayColor = dayColors[dayIndex % dayColors.length];
- const dayPoints = [];
-
- // 处理当天景点
- day.spots.forEach((spot, spotIndex) => {
- if (!spot || spot.latitude === undefined || spot.longitude === undefined) {
- console.warn('景点缺少位置信息', spot);
- return;
- }
-
- const markerId = dayIndex * 100 + spotIndex;
- markers.push({
- id: markerId,
- latitude: spot.latitude,
- longitude: spot.longitude,
- iconPath: spot.has_checked ? '/images/marker.png' : '/images/marker-default.png',
- width: 24,
- height: 24,
- callout: {
- content: `第${day.day_number}天 ${spotIndex + 1}. ${spot.name}`,
- color: '#333',
- fontSize: 14,
- borderRadius: 4,
- display: 'BYCLICK'
- },
- customData: {
- dayIndex,
- spotIndex,
- spotId: spot.id,
- dayNumber: day.day_number
- },
- label: {
- content: `${dayIndex + 1}-${spotIndex + 1}`,
- color: dayColor,
- fontSize: 12,
- bgColor: '#ffffff',
- padding: 4,
- borderRadius: 4,
- borderWidth: 1,
- borderColor: dayColor
- }
- });
-
- dayPoints.push({
- latitude: spot.latitude,
- longitude: spot.longitude
- });
- });
-
- // 添加当天路线
- if (dayPoints.length > 1) {
- polylines.push({
- points: dayPoints,
- color: dayColor,
- width: 4,
- arrowLine: true,
- dottedLine: false
- });
- }
-
- includePoints.push(...dayPoints);
- });
-
- // 计算地图中心点和缩放级别
- const { center, scale } = this.calculateMapViewport(includePoints);
-
- // 更新地图数据
- this.setData({
- latestPlanMapData: {
- markers,
- polylines,
- latitude: center.latitude,
- longitude: center.longitude,
- scale: scale,
- showMap: markers.length > 0,
- includePoints,
- dayColors
- }
- });
-
- // 播放路线动画
- this.playRouteAnimation(polylines);
- } catch (error) {
- console.error('处理地图数据时出错:', error);
- this.setData({
- latestPlanMapData: {
- showMap: false,
- markers: [],
- polylines: [],
- includePoints: []
- }
- });
- }
- },
- // 计算地图视野
- calculateMapViewport(points) {
- if (!points || points.length === 0) {
- return {
- center: { latitude: 39.9042, longitude: 116.4074 },
- scale: 12
- };
- }
- // 计算所有点的边界
- const lats = points.map(p => p.latitude);
- const lngs = points.map(p => p.longitude);
-
- const minLat = Math.min(...lats);
- const maxLat = Math.max(...lats);
- const minLng = Math.min(...lngs);
- const maxLng = Math.max(...lngs);
- // 计算中心点
- const center = {
- latitude: (minLat + maxLat) / 2,
- longitude: (minLng + maxLng) / 2
- };
- // 计算缩放级别
- const latRange = maxLat - minLat;
- const lngRange = maxLng - minLng;
- const maxRange = Math.max(latRange, lngRange);
-
- // 根据范围大小调整缩放级别
- let scale = 15 - Math.floor(maxRange * 15);
- scale = Math.max(10, Math.min(scale, 17));
- return { center, scale };
- },
- // 播放路线动画
- playRouteAnimation(polylines) {
- if (!polylines || polylines.length === 0) return;
-
- // 初始状态:所有路线半透明
- const transparentPolylines = polylines.map(line => ({
- ...line,
- color: line.color + '80' // 添加透明度
- }));
-
- this.setData({
- 'latestPlanMapData.polylines': transparentPolylines
- });
-
- // 逐个显示路线
- let i = 0;
- const timer = setInterval(() => {
- if (i >= polylines.length) {
- clearInterval(timer);
- return;
- }
-
- const updatedPolylines = [...polylines];
- updatedPolylines[i] = {
- ...updatedPolylines[i],
- color: polylines[i].color.replace('80', '') // 移除透明度
- };
-
- this.setData({
- 'latestPlanMapData.polylines': updatedPolylines
- });
- i++;
- }, 500);
- },
- // 切换显示指定天数的路线
- switchMapDay(e) {
- const dayIndex = e.currentTarget.dataset.day;
- const dayColors = ['#e54d42', '#f37b1d', '#1cbbb4', '#0081ff', '#6739b6', '#9c26b0', '#e03997'];
-
- this.setData({
- currentMapDay: dayIndex
- });
- if (!this.data.inProgressPlans.length) return;
- const plan = this.data.inProgressPlans[0];
- const day = plan.day_plans[dayIndex];
- const dayColor = dayColors[dayIndex % dayColors.length];
- // 1. 准备当天的景点数据
- const markers = [];
- const includePoints = [];
-
- day.spots.forEach((spot, spotIndex) => {
- if (!spot || !spot.latitude || !spot.longitude) return;
-
- const markerId = dayIndex * 100 + spotIndex;
- markers.push({
- id: markerId,
- latitude: spot.latitude,
- longitude: spot.longitude,
- iconPath: spot.has_checked ? '/images/marker.png' : '/images/marker-default.png',
- width: 24,
- height: 24,
- callout: {
- content: `第${day.day_number}天 ${spotIndex + 1}. ${spot.name}`,
- color: '#333',
- fontSize: 14,
- borderRadius: 4,
- display: 'BYCLICK'
- },
- customData: {
- dayIndex,
- spotIndex,
- spotId: spot.id,
- dayNumber: day.day_number
- },
- label: {
- content: `${dayIndex + 1}-${spotIndex + 1}`,
- color: dayColor,
- fontSize: 12,
- bgColor: '#ffffff',
- padding: 4,
- borderRadius: 4,
- borderWidth: 1,
- borderColor: dayColor
- }
- });
- includePoints.push({
- latitude: spot.latitude,
- longitude: spot.longitude
- });
- });
- // 2. 生成当天路线
- const polylines = [];
- if (day.spots.length > 1) {
- const points = day.spots
- .filter(spot => spot.latitude && spot.longitude)
- .map(spot => ({
- latitude: spot.latitude,
- longitude: spot.longitude
- }));
-
- if (points.length > 1) {
- polylines.push({
- points: points,
- color: dayColor, // 使用当天专属颜色
- width: 4,
- arrowLine: true,
- dottedLine: false
- });
- }
- }
- // 3. 计算地图视野
- const { center, scale } = this.calculateMapViewport(includePoints);
- // 4. 更新地图数据
- this.setData({
- latestPlanMapData: {
- markers,
- polylines,
- latitude: center.latitude,
- longitude: center.longitude,
- scale,
- showMap: markers.length > 0,
- includePoints,
- dayColors: [dayColor] // 只保留当前天的颜色
- }
- });
- // 5. 播放路线动画
- this.playRouteAnimation(polylines);
- },
- // 重新定位到所有景点
- resetToAllAttractions() {
- this.setData({
- currentMapDay: -1
- });
-
- // 重新处理地图数据,显示所有景点
- if (this.data.inProgressPlans.length > 0) {
- this.processPlanMapData(this.data.inProgressPlans[0]);
- }
- },
- // 地图缩放控制
- handleZoomIn() {
- this.setData({
- 'latestPlanMapData.scale': Math.min(this.data.latestPlanMapData.scale + 1, 18)
- });
- },
- handleZoomOut() {
- this.setData({
- 'latestPlanMapData.scale': Math.max(this.data.latestPlanMapData.scale - 1, 10)
- });
- },
- // 处理标记点点击
- handleMarkerTap(e) {
- const markerId = e.detail.markerId;
- const marker = this.data.latestPlanMapData.markers.find(m => m.id === markerId);
-
- if (!marker || !this.data.inProgressPlans || this.data.inProgressPlans.length === 0) {
- console.error('无法找到标记或行程数据');
- return;
- }
-
- const { dayIndex, spotIndex, spotId } = marker.customData || {};
- const spot = this.data.inProgressPlans[0].day_plans[dayIndex].spots[spotIndex];
-
- if (!spot) {
- console.error('无法找到景点数据');
- return;
- }
- // 显示加载状态
- this.setData({
- showSpotModal: true,
- currentSpot: {
- ...spot,
- isLoadingImage: true // 添加加载状态
- },
- currentDayIndex: dayIndex,
- currentSpotIndex: spotIndex
- });
- // 获取景点图片
- this.fetchAttractionImage(spot).then(imageUrl => {
- this.setData({
- 'currentSpot.image': imageUrl,
- 'currentSpot.isLoadingImage': false
- });
- }).catch(err => {
- console.error('获取景点图片失败:', err);
- this.setData({
- 'currentSpot.isLoadingImage': false
- });
- });
- },
- // 从API获取景点图片
- fetchAttractionImage(spot) {
- return new Promise((resolve, reject) => {
- // 如果已经有有效图片,直接返回
- if (spot.image && !spot.image.includes('default')) {
- resolve(spot.image);
- return;
- }
- // 获取城市名称
- let cityName = '济南'; // 默认值
- if (spot.city_id && this.data.cityOptions) {
- const city = this.data.cityOptions.find(c => c.value === spot.city_id);
- if (city) cityName = city.label.replace(/市$/, '');
- }
- wx.request({
- url: `${app.globalData.apiBaseUrl}/api/attractions/image/`,
- method: 'GET',
- data: {
- name: spot.name,
- city: cityName
- },
- success: (res) => {
- if (res.data.status === 'success' && res.data.image_url) {
- // 检查URL是否完整,如果不完整则补全
- const imageUrl = res.data.image_url.startsWith('http') ?
- res.data.image_url :
- `${app.globalData.mediaBaseUrl}${res.data.image_url}`;
- resolve(imageUrl);
- } else {
- reject(new Error('未获取到有效图片'));
- }
- },
- fail: (err) => {
- reject(err);
- }
- });
- });
- },
- // 显示景点详情
- showSpotDetail(e) {
- const dayIndex = e.currentTarget.dataset.day;
- const spotIndex = e.currentTarget.dataset.spot;
- const spotId = e.currentTarget.dataset.spotid;
-
- const spot = this.data.inProgressPlans[0].day_plans[dayIndex].spots[spotIndex];
-
- // 显示加载状态
- this.setData({
- showSpotModal: true,
- currentSpot: {
- ...spot,
- isLoadingImage: true // 添加加载状态
- },
- currentDayIndex: dayIndex,
- currentSpotIndex: spotIndex
- });
-
- // 获取景点图片
- this.fetchAttractionImage(spot).then(imageUrl => {
- this.setData({
- 'currentSpot.image': imageUrl,
- 'currentSpot.isLoadingImage': false
- });
- }).catch(err => {
- console.error('获取景点图片失败:', err);
- this.setData({
- 'currentSpot.isLoadingImage': false,
- 'currentSpot.image': '/images/default-spot.png' // 设置默认图片
- });
- });
- },
-
- // 隐藏景点详情
- hideSpotModal() {
- this.setData({
- showSpotModal: false
- });
- },
-
- // 打卡景点
- checkInSpot(e) {
- const dayIndex = e.currentTarget.dataset.day;
- const spotIndex = e.currentTarget.dataset.spot;
- const spotId = e.currentTarget.dataset.spotid;
- const planId = this.data.inProgressPlans[0]?.id;
-
- // 获取当前景点数据
- const spot = this.data.inProgressPlans[0].day_plans[dayIndex].spots[spotIndex];
-
- // 获取该景点的所有打卡记录
- this.getSpotCheckinRecords(spotId, planId).then(records => {
- // 如果有打卡记录,使用最后一条记录的数据
- const lastRecord = records.length > 0 ? records[0] : null;
-
- this.setData({
- tempCheckinData: {
- dayIndex,
- spotIndex,
- spotId,
- planId,
- isEdit: spot.has_checked // 标记是否为编辑模式
- },
- showCheckinModal: true,
- checkinImage: lastRecord?.image_url || spot.checkin_images?.[0] || '',
- checkinNote: lastRecord?.note || spot.checkin_note || ''
- });
- }).catch(err => {
- console.error('获取打卡记录失败:', err);
- // 失败时仍显示基本数据
- this.setData({
- tempCheckinData: {
- dayIndex,
- spotIndex,
- spotId,
- planId,
- isEdit: spot.has_checked
- },
- showCheckinModal: true,
- checkinImage: spot.checkin_images?.[0] || '',
- checkinNote: spot.checkin_note || ''
- });
- });
- },
- // 获取景点的打卡记录
- getSpotCheckinRecords(spotId, planId) {
- return new Promise((resolve, reject) => {
- wx.request({
- url: `${app.globalData.apiBaseUrl}/api/user/checkins/`,
- method: 'GET',
- data: {
- spot_id: spotId,
- plan_id: planId
- },
- header: { 'Authorization': 'Token ' + app.globalData.token },
- success: (res) => {
- if (res.statusCode === 200) {
- // 确保返回的数据是当前景点的打卡记录
- const filteredRecords = res.data.data?.checkins.filter(record =>
- record.spot_id.toString() === spotId.toString()
- ) || [];
- resolve(filteredRecords);
- } else {
- reject(new Error(res.data.message || '获取打卡记录失败'));
- }
- },
- fail: (err) => {
- reject(err);
- }
- });
- });
- },
- chooseCheckinImage() {
- wx.chooseImage({
- count: 1,
- sizeType: ['compressed'],
- sourceType: ['album', 'camera'],
- success: (res) => {
- this.setData({
- checkinImage: res.tempFilePaths[0],
- isUploading: true
- });
-
- // 上传图片
- this.uploadCheckinImage(res.tempFilePaths[0]);
- }
- });
- },
- // 上传打卡图片
- uploadCheckinImage(tempFilePath) {
- wx.uploadFile({
- url: app.globalData.apiBaseUrl + '/api/upload/checkin-image/',
- filePath: tempFilePath,
- name: 'image',
- header: {
- 'Authorization': 'Token ' + app.globalData.token,
- 'Content-Type': 'multipart/form-data'
- },
- success: (res) => {
- try {
- const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
- if (data.status === 'success') {
- this.setData({
- checkinImage: data.data.image_url,
- isUploading: false
- });
- } else {
- wx.showToast({ title: '图片上传失败', icon: 'none' });
- this.setData({ isUploading: false });
- }
- } catch (e) {
- console.error('解析响应失败:', e);
- wx.showToast({ title: '处理响应失败', icon: 'none' });
- this.setData({ isUploading: false });
- }
- },
- fail: (err) => {
- console.error('上传失败:', err);
- wx.showToast({ title: '上传失败', icon: 'none' });
- this.setData({ isUploading: false });
- }
- });
- },
- // 文案输入处理
- onCheckinNoteInput(e) {
- this.setData({
- checkinNote: e.detail.value
- });
- },
- // 提交打卡
- submitCheckin() {
- const { dayIndex, spotIndex, spotId, planId, isEdit } = this.data.tempCheckinData;
- const { checkinImage, checkinNote } = this.data;
-
- if (!checkinImage) {
- wx.showToast({ title: '请上传打卡照片', icon: 'none' });
- return;
- }
-
- wx.showLoading({ title: isEdit ? '更新打卡中...' : '提交打卡中...', mask: true });
-
- // 统一使用POST方法,后端可以通过操作类型区分
- wx.request({
- url: `${app.globalData.apiBaseUrl}/api/user/checkin/`,
- method: 'POST',
- data: {
- spot_id: spotId.toString(),
- plan_id: planId.toString(),
- image_url: checkinImage,
- note: checkinNote,
- is_edit: isEdit // 添加编辑标记
- },
- header: {
- 'Authorization': 'Token ' + app.globalData.token,
- 'Content-Type': 'application/json'
- },
- success: (res) => {
- wx.hideLoading();
-
- // 接受200或201状态码
- if (res.statusCode === 200 || res.statusCode === 201) {
- try {
- // 处理响应数据
- const responseData = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
-
- if (responseData.status === 'success') {
- // 更新本地数据
- const keyPath = `inProgressPlans[0].day_plans[${dayIndex}].spots[${spotIndex}]`;
-
- this.setData({
- [keyPath]: {
- ...this.data.inProgressPlans[0].day_plans[dayIndex].spots[spotIndex],
- has_checked: true,
- checkin_images: [checkinImage],
- checkin_note: checkinNote
- },
- showCheckinModal: false,
- 'currentSpot.has_checked': true,
- 'currentSpot.checkin_images': [checkinImage],
- 'currentSpot.checkin_note': checkinNote
- });
-
- wx.showToast({
- title: isEdit ? '更新成功' : '打卡成功',
- icon: 'success',
- duration: 2000
- });
-
- this.updateMarkerAfterCheckIn(dayIndex, spotIndex);
- this.loadInProgressPlans(); // 刷新数据
- } else {
- throw new Error(responseData.message || '操作失败');
- }
- } catch (e) {
- console.error('处理响应数据失败:', e);
- wx.showToast({
- title: '处理响应数据失败',
- icon: 'none'
- });
- }
- } else {
- throw new Error(res.data?.message || `请求失败,状态码: ${res.statusCode}`);
- }
- },
- fail: (err) => {
- wx.hideLoading();
- console.error('请求失败:', err);
- wx.showToast({
- title: '网络错误,请检查连接',
- icon: 'none'
- });
- }
- });
- },
- // 关闭打卡弹窗
- closeCheckinModal() {
- this.setData({
- showCheckinModal: false,
- checkinImage: '',
- checkinNote: ''
- });
- },
- // 更新地图标记点状态
- updateMarkerAfterCheckIn(dayIndex, spotIndex) {
- const markerId = dayIndex * 100 + spotIndex;
- const markers = this.data.latestPlanMapData.markers.map(marker => {
- if (marker.id === markerId) {
- return {
- ...marker,
- iconPath: '/images/marker.png',
- callout: { // 更新callout内容
- ...marker.callout,
- content: `已打卡 - ${marker.callout.content}`
- }
- };
- }
- return marker;
- });
-
- this.setData({ 'latestPlanMapData.markers': markers });
- },
- // 导航到景点位置
- navigateToSpot() {
- const { latitude, longitude, name, address } = this.data.currentSpot;
-
- // 验证坐标是否存在
- if (!latitude || !longitude) {
- wx.showToast({
- title: '该地点缺少位置信息',
- icon: 'none'
- });
- return;
- }
- // 使用微信内置地图
- wx.openLocation({
- latitude: Number(latitude),
- longitude: Number(longitude),
- name: name || '目的地',
- address: address || '', // 添加详细地址
- scale: 18 // 缩放级别
- });
- },
- // 跳转到详情页
- navigateToDetail(e) {
- const planId = e.currentTarget.dataset.id
- wx.navigateTo({
- url: `/pages/xingchengxiangqing/xingchengxiangqing?id=${planId}`
- })
- },
- // 跳转到创建行程页
- navigateToCreate() {
- wx.navigateTo({
- url: '/pages/xingchengguihua/xingchengguihua'
- })
- },
- // 分享行程
- sharePlan(e) {
- const planId = e.currentTarget.dataset.id;
- let plan;
-
- // 根据当前选项卡确定要分享的行程
- if (this.data.activeTab === 'in_progress' && this.data.inProgressPlans.length > 0) {
- plan = this.data.inProgressPlans[0];
- } else if (this.data.activeTab === 'completed') {
- plan = this.data.completedPlans.find(p => p.id === planId);
- } else if (this.data.activeTab === 'all') {
- plan = this.data.allPlans.find(p => p.id === planId);
- }
-
- if (!plan) return;
-
- wx.showShareMenu({
- withShareTicket: true
- });
- },
- onShareAppMessage() {
- let plan;
-
- // 根据当前选项卡确定要分享的行程
- if (this.data.activeTab === 'in_progress' && this.data.inProgressPlans.length > 0) {
- plan = this.data.inProgressPlans[0];
- } else if (this.data.activeTab === 'completed' && this.data.completedPlans.length > 0) {
- plan = this.data.completedPlans[0];
- } else if (this.data.activeTab === 'all' && this.data.allPlans.length > 0) {
- plan = this.data.allPlans[0];
- }
-
- if (!plan) return {};
-
- return {
- title: plan.title || '我的红色之旅行程',
- path: `/pages/xingchengxiangqing/xingchengxiangqing?id=${plan.id}`,
- imageUrl: plan.day_plans[0]?.spots[0]?.image || '/images/red-tourism-share.jpg'
- };
- },
- // 处理错误响应
- handleErrorResponse(res) {
- let errorMsg = '加载失败'
- if (res.data && res.data.message) {
- errorMsg += ': ' + res.data.message
- }
-
- if (res.statusCode === 401) {
- errorMsg = '登录已过期,请重新登录'
- this.showLoginModal()
- }
-
- wx.showToast({
- title: errorMsg,
- icon: 'none'
- })
- },
- // 处理请求错误
- handleRequestError(err) {
- console.error('请求失败:', err)
- wx.showToast({
- title: '网络错误,请检查网络连接',
- icon: 'none'
- })
- },
- // 显示登录弹窗
- showLoginModal() {
- wx.showModal({
- title: '登录过期',
- content: '您的登录已过期,请重新登录',
- confirmText: '去登录',
- success: (res) => {
- if (res.confirm) {
- wx.navigateTo({
- url: '/pages/login/login'
- })
- }
- }
- })
- }
-
- })
|