xingchengxiangqing.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. const app = getApp()
  2. Page({
  3. data: {
  4. plan: {},
  5. isLoading: true,
  6. showCheckinModal: false,
  7. currentCheckins: [],
  8. currentCheckinIndex: 0,
  9. currentSpotId: null,
  10. currentPlanId: null,
  11. spotImages: {},
  12. showMapModal: false,
  13. mapData: {
  14. longitude: 117.070218, // 默认济南中心点
  15. latitude: 36.666316,
  16. scale: 14,
  17. markers: [],
  18. polylines: [],
  19. includePoints: []
  20. },
  21. allSpots: []
  22. },
  23. onLoad(options) {
  24. if (options.id) {
  25. this.loadPlanDetail(options.id)
  26. } else {
  27. wx.showToast({
  28. title: '缺少行程ID',
  29. icon: 'none'
  30. })
  31. setTimeout(() => {
  32. wx.navigateBack()
  33. }, 1500)
  34. }
  35. },
  36. // 加载行程详情
  37. loadPlanDetail(planId) {
  38. wx.showLoading({
  39. title: '加载中...',
  40. })
  41. wx.request({
  42. url: app.globalData.apiBaseUrl + '/api/user/plans/' + planId + '/',
  43. method: 'GET',
  44. header: {
  45. 'Authorization': 'Token ' + app.globalData.token
  46. },
  47. success: (res) => {
  48. if (res.statusCode === 200 && res.data.status === 'success') {
  49. const plan = res.data.data.plan;
  50. this.setData({
  51. plan: plan,
  52. isLoading: false
  53. });
  54. // 立即设置现有图片,然后异步获取更好的图片
  55. this.initSpotImages(plan);
  56. // 检查所有景点是否需要获取图片
  57. this.checkAndFetchSpotImages(plan);
  58. } else {
  59. this.handleError(res);
  60. }
  61. },
  62. fail: (err) => {
  63. wx.showToast({
  64. title: '网络错误',
  65. icon: 'none'
  66. });
  67. console.error('加载行程详情失败:', err);
  68. },
  69. complete: () => {
  70. wx.hideLoading();
  71. }
  72. });
  73. },
  74. // 初始化景点图片
  75. initSpotImages(plan) {
  76. if (!plan.day_plans) return;
  77. const spotImages = {...this.data.spotImages};
  78. // 遍历所有景点,设置初始图片
  79. plan.day_plans.forEach(dayPlan => {
  80. if (dayPlan.spots) {
  81. dayPlan.spots.forEach(spot => {
  82. // 如果景点已有图片,直接使用
  83. if (spot.image && !spot.image.includes('default')) {
  84. spotImages[spot.id] = spot.image;
  85. }
  86. });
  87. }
  88. });
  89. this.setData({ spotImages });
  90. },
  91. // 检查并获取景点图片
  92. checkAndFetchSpotImages(plan) {
  93. if (!plan.day_plans) return;
  94. const spotImages = {...this.data.spotImages};
  95. // 遍历所有景点
  96. plan.day_plans.forEach(dayPlan => {
  97. if (dayPlan.spots) {
  98. dayPlan.spots.forEach(spot => {
  99. // 如果景点没有图片或使用默认图片,尝试获取更好的图片
  100. if (!spot.image || spot.image.includes('default')) {
  101. this.fetchSpotImage(spot.id, spot.name, plan.cities);
  102. }
  103. });
  104. }
  105. });
  106. },
  107. // 获取景点图片
  108. fetchSpotImage(spotId, spotName, cities) {
  109. // 尝试从城市信息中提取城市名
  110. let cityName = '';
  111. if (cities && cities.length > 0) {
  112. cityName = cities[0].name;
  113. }
  114. wx.request({
  115. url: `${app.globalData.apiBaseUrl}/api/attractions/image/`,
  116. method: 'GET',
  117. data: {
  118. name: spotName,
  119. city: cityName
  120. },
  121. success: (res) => {
  122. if (res.statusCode === 200 && res.data.status === 'success') {
  123. // 更新单个图片
  124. this.setData({
  125. [`spotImages.${spotId}`]: res.data.image_url
  126. });
  127. }
  128. // 即使API返回错误,也保持现有图片不变
  129. },
  130. fail: (err) => {
  131. console.error('获取景点图片失败:', spotName, err);
  132. // 失败时保持现有图片不变
  133. }
  134. });
  135. },
  136. // 处理错误
  137. handleError(res) {
  138. let errorMsg = '加载失败'
  139. if (res.data && res.data.message) {
  140. errorMsg = res.data.message
  141. }
  142. wx.showToast({
  143. title: errorMsg,
  144. icon: 'none'
  145. })
  146. setTimeout(() => {
  147. wx.navigateBack()
  148. }, 1500)
  149. },
  150. // 返回上一页
  151. navigateBack() {
  152. wx.navigateBack()
  153. },
  154. // 分享行程
  155. sharePlan() {
  156. wx.showShareMenu({
  157. withShareTicket: true
  158. })
  159. },
  160. onShareAppMessage() {
  161. return {
  162. title: this.data.plan.title || '红色旅游行程',
  163. path: `/pages/xingchengxiangqing/xingchengxiangqing?id=${this.data.plan.id}`,
  164. imageUrl: this.data.plan.day_plans && this.data.plan.day_plans[0] && this.data.plan.day_plans[0].spots && this.data.plan.day_plans[0].spots[0] ?
  165. this.data.plan.day_plans[0].spots[0].image : '/images/share-default.jpg'
  166. }
  167. },
  168. // 查看打卡记录
  169. viewCheckins: function(e) {
  170. const spotId = e.currentTarget.dataset.spotId;
  171. const planId = e.currentTarget.dataset.planId;
  172. this.setData({
  173. isLoading: true
  174. });
  175. // 获取打卡记录
  176. wx.request({
  177. url: `${app.globalData.apiBaseUrl}/api/user/spot-checkins/`,
  178. method: 'GET',
  179. data: {
  180. spot_id: spotId,
  181. plan_id: planId
  182. },
  183. header: {
  184. 'Authorization': 'Token ' + app.globalData.token
  185. },
  186. success: (res) => {
  187. if (res.statusCode === 200 && res.data.status === 'success') {
  188. const checkins = res.data.data.checkins;
  189. if (checkins.length === 0) {
  190. wx.showToast({
  191. title: '暂无打卡记录',
  192. icon: 'none'
  193. });
  194. return;
  195. }
  196. // 格式化时间
  197. const formattedCheckins = checkins.map(item => {
  198. return {
  199. ...item,
  200. check_in_time: this.formatTime(item.check_in_time)
  201. };
  202. });
  203. this.setData({
  204. currentCheckins: formattedCheckins,
  205. currentCheckinIndex: 0,
  206. currentSpotId: spotId,
  207. currentPlanId: planId,
  208. showCheckinModal: true,
  209. isLoading: false
  210. });
  211. } else {
  212. this.handleError(res);
  213. }
  214. },
  215. fail: (err) => {
  216. wx.showToast({
  217. title: '获取打卡记录失败',
  218. icon: 'none'
  219. });
  220. console.error('获取打卡记录失败:', err);
  221. this.setData({
  222. isLoading: false
  223. });
  224. }
  225. });
  226. },
  227. // 格式化时间
  228. formatTime: function(timeString) {
  229. const date = new Date(timeString);
  230. const year = date.getFullYear();
  231. const month = (date.getMonth() + 1).toString().padStart(2, '0');
  232. const day = date.getDate().toString().padStart(2, '0');
  233. const hours = date.getHours().toString().padStart(2, '0');
  234. const minutes = date.getMinutes().toString().padStart(2, '0');
  235. return `${year}-${month}-${day} ${hours}:${minutes}`;
  236. },
  237. // 关闭弹窗
  238. closeCheckinModal: function() {
  239. this.setData({
  240. showCheckinModal: false,
  241. currentCheckins: [],
  242. currentCheckinIndex: 0
  243. });
  244. },
  245. // 滑动切换
  246. swiperChange: function(e) {
  247. this.setData({
  248. currentCheckinIndex: e.detail.current
  249. });
  250. },
  251. // 查看地图
  252. viewOnMap: function() {
  253. this.prepareMapData();
  254. this.setData({
  255. showMapModal: true
  256. });
  257. },
  258. // 准备地图数据
  259. prepareMapData: function() {
  260. const plan = this.data.plan;
  261. if (!plan.day_plans || plan.day_plans.length === 0) return;
  262. const markers = [];
  263. const polylines = [];
  264. const includePoints = [];
  265. const allSpots = []; // 收集所有景点
  266. // 收集所有景点的坐标
  267. plan.day_plans.forEach(dayPlan => {
  268. if (!dayPlan.spots) return;
  269. const dayColor = ['#e54d42','#f37b1d','#1cbbb4','#0081ff','#6739b6','#9c26b0','#e03997'][dayPlan.day_number - 1];
  270. const points = [];
  271. dayPlan.spots.forEach((spot, index) => {
  272. if (spot.longitude && spot.latitude) {
  273. // 添加标记点(添加callout内容)
  274. markers.push({
  275. id: spot.id,
  276. longitude: parseFloat(spot.longitude),
  277. latitude: parseFloat(spot.latitude),
  278. iconPath: '/images/marker-red-star.png',
  279. width: 30,
  280. height: 30,
  281. callout: {
  282. content: spot.name,
  283. color: '#333',
  284. fontSize: 12,
  285. borderRadius: 4,
  286. bgColor: '#ffffff',
  287. padding: 4,
  288. display: 'ALWAYS'
  289. },
  290. day: dayPlan.day_number,
  291. index: index
  292. });
  293. // 收集坐标点
  294. points.push({
  295. longitude: parseFloat(spot.longitude),
  296. latitude: parseFloat(spot.latitude)
  297. });
  298. includePoints.push({
  299. longitude: parseFloat(spot.longitude),
  300. latitude: parseFloat(spot.latitude)
  301. });
  302. // 添加到所有景点列表
  303. allSpots.push({
  304. id: spot.id,
  305. name: spot.name,
  306. day_number: dayPlan.day_number,
  307. longitude: parseFloat(spot.longitude),
  308. latitude: parseFloat(spot.latitude)
  309. });
  310. }
  311. });
  312. // 添加路线
  313. if (points.length > 1) {
  314. polylines.push({
  315. points: points,
  316. color: dayColor,
  317. width: 6,
  318. dottedLine: false
  319. });
  320. }
  321. });
  322. // 设置地图中心点为第一个景点或默认值
  323. let centerLongitude = 116.397428;
  324. let centerLatitude = 39.90923;
  325. if (includePoints.length > 0) {
  326. centerLongitude = includePoints[0].longitude;
  327. centerLatitude = includePoints[0].latitude;
  328. }
  329. this.setData({
  330. mapData: {
  331. longitude: centerLongitude,
  332. latitude: centerLatitude,
  333. scale: 14,
  334. markers: markers,
  335. polylines: polylines,
  336. includePoints: includePoints
  337. },
  338. allSpots: allSpots // 设置所有景点列表
  339. });
  340. },
  341. // 关闭地图弹窗
  342. closeMapModal: function() {
  343. this.setData({
  344. showMapModal: false
  345. });
  346. },
  347. // 聚焦到指定标记点
  348. focusOnMarker: function(e) {
  349. const markerId = e.currentTarget.dataset.markerId;
  350. const marker = this.data.mapData.markers.find(m => m.id === markerId);
  351. if (marker) {
  352. this.setData({
  353. 'mapData.longitude': marker.longitude,
  354. 'mapData.latitude': marker.latitude,
  355. 'mapData.scale': 16
  356. });
  357. }
  358. },
  359. // 放大地图
  360. handleZoomIn: function() {
  361. if (this.data.mapData.scale < 18) {
  362. this.setData({
  363. 'mapData.scale': this.data.mapData.scale + 1
  364. });
  365. }
  366. },
  367. // 缩小地图
  368. handleZoomOut: function() {
  369. if (this.data.mapData.scale > 3) {
  370. this.setData({
  371. 'mapData.scale': this.data.mapData.scale - 1
  372. });
  373. }
  374. },
  375. // 重置视图以显示所有景点
  376. resetToAllAttractions: function() {
  377. const mapData = this.data.mapData;
  378. this.setData({
  379. 'mapData.longitude': mapData.initialLongitude || 116.397428,
  380. 'mapData.latitude': mapData.initialLatitude || 39.90923,
  381. 'mapData.scale': mapData.initialScale || 14
  382. });
  383. }
  384. })